vines-services 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,2 @@
1
+ var Api,__bind=function(a,b){return function(){return a.apply(b,arguments)}};Api=function(){function b(b){this.session=b,this.user=null,this.session.onRoster(__bind(function(){return this.get(a,{jid:this.session.bareJid()},__bind(function(a){return this.user=a},this))},this))}var a;return a="http://getvines.com/protocol/users",b.prototype.jid=function(){return"vines."+this.session.bareJid().split("@")[1]},b.prototype.get=function(a,b,c){var d,e,f;e=this.session.xml('<iq id="'+this.session.uniqueId()+'" to="'+this.jid()+'" type="get">\n <query xmlns="'+a+'"/>\n</iq>');for(d in b)f=b[d],$("query",e).attr(d,f);return this.session.sendIQ(e,__bind(function(a){var b;b=$(a).attr("type")==="result";if(!b)return;return c(JSON.parse($("query",a).text()))},this))},b.prototype.get2=function(a,b,c){var d;return d=this.session.xml('<iq id="'+this.session.uniqueId()+'" to="'+this.jid()+'" type="get">\n <query xmlns="'+a+'"/>\n</iq>'),$("query",d).text(b),this.session.sendIQ(d,__bind(function(a){var b;b=$(a).attr("type")==="result";if(!b)return;return c(JSON.parse($("query",a).text()))},this))},b.prototype.remove=function(a,b,c){var d;return d=this.session.xml('<iq id="'+this.session.uniqueId()+'" to="'+this.jid()+'" type="set">\n <query xmlns="'+a+'" action="delete" id=""/>\n</iq>'),$("query",d).attr("id",b),this.session.sendIQ(d,c)},b.prototype.save=function(a,b,c){var d;return d=this.session.xml('<iq id="'+this.session.uniqueId()+'" to="'+this.jid()+'" type="set">\n <query xmlns="'+a+'"/>\n</iq>'),$("query",d).text(JSON.stringify(b)),this.session.sendIQ(d,__bind(function(a){var b;b=$(a).attr("type")==="result";if(!b)return;return c(JSON.parse($("query",a).text()))},this))},b}();var Commands;Commands=function(){function a(){this.buf=[],this.index=0}return a.prototype.prev=function(){var a;return a=this.buf[--this.index],a||(this.index=-1),a||""},a.prototype.next=function(){var a;return a=this.buf[++this.index],a||(this.index=this.buf.length),a||""},a.prototype.push=function(a){return this.buf.push(a),this.index=this.buf.length},a}();var SystemsPage,__bind=function(a,b){return function(){return a.apply(b,arguments)}};SystemsPage=function(){function a(a){this.session=a,this.session.onRoster(__bind(function(){return this.roster()},this)),this.session.onMessage(__bind(function(a){return this.message(a)},this)),this.session.onPresence(__bind(function(a){return this.presence(a)},this)),this.commands=new Commands,this.chats={},this.currentContact=null,this.layout=null}return a.prototype.datef=function(a){var b,c,d,e;return b=new Date(a),d=b.getHours()<12?" am":" pm",c=b.getHours()>12?b.getHours()-12:b.getHours(),c===0&&(c=12),e=b.getMinutes()+"",e.length===1&&(e="0"+e),c+":"+e+d},a.prototype.groupContacts=function(){var a,b,c,d,e,f,g,h;c={},g=this.session.roster;for(d in g){a=g[d],h=a.groups;for(e=0,f=h.length;e<f;e++)b=h[e],(c[b]||(c[b]=[])).push(a)}return c},a.prototype.roster=function(){var a,b,c,d,e,f,g,h,i,j,k,l;d=this.groupContacts(),i=function(){var a;a=[];for(c in d)b=d[c],a.push(c);return a}(),i=i.sort(function(a,b){return a=a.toLowerCase(),b=b.toLowerCase(),a>b?1:a<b?-1:0}),e=$("#roster-items").empty(),l=[];for(j=0,k=i.length;j<k;j++)c=i[j],b=d[c],g=$('<li class="group"></li>').appendTo(e),g.text(c),g.attr("data-group",c),l.push(function(){var d,g,i;i=[];for(d=0,g=b.length;d<g;d++)a=b[d],h=$('<li data-jid="'+a.jid+'">\n <span class="text"></span>\n <span class="unread" style="display:none;"></span>\n</li>').appendTo(e),a.offline()&&h.addClass("offline"),h.click(__bind(function(a){return this.selectContact(a)},this)),f=a.name||a.jid.split("@")[0],h.attr("data-name",f),h.attr("data-group",c),i.push($(".text",h).text(f));return i}.call(this));return l},a.prototype.message=function(a){var b,c,d,e;this.queueMessage(a),e=a.from===this.session.jid(),d=a.from.split("/")[0];if(!e&&d!==this.currentContact)return c=this.chat(a.from),c.unread++,this.eachContact(d,function(a){return $(".unread",a).text(c.unread).show()});b=this.atBottom(),this.appendMessage(a);if(b)return this.scroll({animate:!0})},a.prototype.eachContact=function(a,b){var c,d,e,f,g;f=$("#roster-items li[data-jid='"+a+"']").get(),g=[];for(d=0,e=f.length;d<e;d++)c=f[d],g.push(b($(c)));return g},a.prototype.appendMessage=function(a){var b,c,d,e,f,g,h;d=a.from===this.session.jid(),h=$("jid",a.node).text(),c=(h||a.from).split("/")[0],b=this.session.roster[c],e=b?b.name||c:c,f=$('<li data-jid="'+c+'"><pre></pre></li>').appendTo("#messages"),g=d?"$ ":"",$("pre",f).text(g+a.text);if(!d)return f.append('<footer>\n <span class="author"></span> @\n <span class="time">'+this.datef(a.received)+"</span>\n</footer>"),$(".author",f).text(e)},a.prototype.queueMessage=function(a){var b,c,d;return d=a.from===this.session.jid(),c=a[d?"to":"from"],b=this.chat(c),b.jid=c,b.messages.push(a)},a.prototype.chat=function(a){var b,c;return b=a.split("/")[0],c=this.chats[b],c||(c={jid:a,messages:[],unread:0},this.chats[b]=c),c},a.prototype.presence=function(a){var b,c;c=a.from.split("/")[0];if(c===this.session.bareJid())return;if(!a.type||a.offline)b=this.session.roster[c],this.eachContact(c,function(a){return b.offline()?a.addClass("offline"):a.removeClass("offline")});if(a.offline)return this.chat(c).jid=c},a.prototype.selectContact=function(a){var b,c,d;$("#blank-slate").fadeOut(200,function(){return $(this).remove()}),$("#roster").hide(),d=$(a.currentTarget),c=d.attr("data-jid"),b=this.session.roster[c];if(this.currentContact===c)return;return this.currentContact=c,$("#message-label").text($(".text",d).text()),$("#messages").empty(),$("#message").focus(),this.layout.resize(),this.restoreChat(c)},a.prototype.restoreChat=function(a){var b,c,d,e,f;b=this.chats[a],c=[],b&&(c=b.messages,b.unread=0,this.eachContact(a,function(a){return $(".unread",a).text("").hide()}));for(e=0,f=c.length;e<f;e++)d=c[e],this.appendMessage(d);return this.scroll()},a.prototype.scroll=function(a){var b;return a||(a={}),b=$("#messages"),a.animate?b.animate({scrollTop:b.prop("scrollHeight")},400):b.scrollTop(b.prop("scrollHeight"))},a.prototype.atBottom=function(){var a,b;return b=$("#messages"),a=b.prop("scrollHeight")-b.outerHeight(),b.scrollTop()>=a},a.prototype.send=function(){var a,b,c,d;return this.currentContact?(b=$("#message"),d=b.val().trim(),d&&(a=this.chats[this.currentContact],c=a?a.jid:this.currentContact,this.message({from:this.session.jid(),text:d,to:c,received:new Date}),this.session.sendMessage(c,d),this.commands.push(d)),b.val(""),!1):!1},a.prototype.drawBlankSlate=function(){return $('<form id="blank-slate" class="float">\n <p>\n Services, and individual systems, can be controlled by sending\n them shell commands through this terminal. Select a system to chat with\n to get started.\n </p>\n <input type="submit" value="Select System"/>\n</form>').appendTo("#alpha"),$("#blank-slate").submit(__bind(function(){return $("#roster").show(),this.layout.resize(),!1},this))},a.prototype.draw=function(){var a,b;if(!this.session.connected()){window.location.hash="";return}return $("body").attr("id","systems-page"),$("#container").hide().empty(),$('<div id="alpha" class="primary column x-fill y-fill">\n <ul id="messages" class="scroll y-fill"></ul>\n <form id="message-form">\n <label id="message-label"></label>\n <input id="message" name="message" type="text" maxlength="1024" placeholder="Type a command and press enter to send"/>\n </form>\n <div id="roster" class="float" style="display:none;">\n <ul id="roster-items"></ul>\n <div id="roster-form"></div>\n </div>\n</div>').appendTo("#container"),$("#message-form").submit(__bind(function(){return this.send()},this)),$("#messages").click(function(){return $("#roster").hide()}),$("#message").focus(function(){return $("#roster").hide()}),this.roster(),$("#message-label").click(__bind(function(){return $("#roster").toggle()},this)),$("#message").keyup(__bind(function(a){switch(a.keyCode){case 38:return $("#message").val(this.commands.prev());case 40:return $("#message").val(this.commands.next())}},this)),this.currentContact?(this.currentContact&&this.restoreChat(this.currentContact),a=this.session.roster[this.currentContact],b=a.name||a.jid.split("@")[0],$("#message-label").text(b),$("#message").focus()):this.drawBlankSlate(),$("#container").show(),this.layout=this.resize(),this.scroll(),new Filter({list:"#roster-items",form:"#roster-form",attrs:["data-jid","data-name"]}),$("form","#roster-form").show()},a.prototype.resize=function(){var a,b,c,d,e,f,g;return a=$("#container"),g=$("#roster"),c=$("#roster-items"),f=$("#roster-form"),e=$("#message"),b=$("#message-form"),d=$("#message-label"),new Layout(function(){var h;return e.width(b.width()-d.width()-32),h=a.height()-b.height()-10,g.css("max-height",h),c.css("max-height",h-f.outerHeight()-10)})},a}();var ServicesPage,__bind=function(a,b){return function(){return a.apply(b,arguments)}};ServicesPage=function(){function f(a){this.session=a,this.api=new Api(this.session),this.selectedService=null,this.validateTimeout=null,this.layout=null,this.users=[]}var a,b,c,d,e;return c="http://getvines.com/protocol/services",b="http://getvines.com/protocol/services/members",d="http://getvines.com/protocol/systems",a="http://getvines.com/protocol/systems/attributes",e="http://getvines.com/protocol/users",f.prototype.deleteService=function(a){var b;return this.drawBlankSlate(),this.toggleForm("#remove-contact-form"),b=$("#services li[data-id='"+this.selectedService.id+"']"),this.api.remove(c,this.selectedService.id,__bind(function(a){return b.fadeOut(200,function(){return b.remove(),this.selectedService=null})},this)),!1},f.prototype.icon=function(a){var b,c;return c={darwin:"mac.png",linux:"linux.png",windows:"windows.png"},b=c[a.os]||"run.png","images/"+b},f.prototype.drawMember=function(a){var b;if(!this.editorVisible())return;return b=$('<li>\n <span class="icon"><img src="'+this.icon(a)+'"/></span>\n <span class="text"></span>\n</li>').appendTo("#members"),$(".text",b).text(a.name)},f.prototype.operators=function(){var a,b,c,d,e,f;e=["like","not like","starts with","ends with","is","is not",">",">=","<","<=","and","or"],f=[];for(c=0,d=e.length;c<d;c++)b=e[c],a=$('<li data-selector="'+b+'">\n '+b+"\n</li>").appendTo("#operators"),f.push(a.click(__bind(function(a){var b;return $("#syntax").focus(),b=$(a.currentTarget).attr("data-selector"),$("#syntax").val($("#syntax").val()+(" "+b+" ")),this.validateIn()},this)));return f},f.prototype.selectService=function(a){var b,d;return b=$(a).attr("data-id"),d=$(a).attr("data-name"),$("#services li").removeClass("selected"),$(a).addClass("selected"),$("#remove-service-msg").html("Are you sure you want to remove the "+("<strong>"+d+"</strong> service?")),$("#remove-service-form .buttons").fadeIn(200),this.api.get(c,{id:b},__bind(function(a){return this.selectedService=a,this.drawEditor(a)},this))},f.prototype.serviceNode=function(a){var b,c;return b=a.size===1?"system":"systems",c=$('<li data-id="'+a.id+'" data-name="" data-size="'+a.size+'">\n <span class="text">'+a.name+'</span>\n <span class="count">'+a.size+" "+b+"</span>\n</li>").appendTo("#services"),c.attr("data-name",a.name),$(".text",c).text(a.name),c.click(__bind(function(a){return this.selectService(a.currentTarget)},this)),c},f.prototype.findServices=function(){return this.api.get(c,{},__bind(function(a){var b,c,d,e,f;e=a.rows,f=[];for(c=0,d=e.length;c<d;c++)b=e[c],f.push(this.serviceNode(b));return f},this))},f.prototype.findMembers=function(a){return this.api.get(b,{id:a},__bind(function(a){var b,c,d,e,f;e=a.rows,f=[];for(c=0,d=e.length;c<d;c++)b=e[c],f.push(this.drawMember(b));return f},this))},f.prototype.findUsers=function(a){return this.api.get(e,{},__bind(function(a){var b;return this.users=function(){var c,d,e,f;e=a.rows,f=[];for(c=0,d=e.length;c<d;c++)b=e[c],b.system||f.push(b);return f}(),this.drawUsers()},this))},f.prototype.attributeNode=function(a){var b;return b=$('<li data-name=""></li>').appendTo("#attributes"),b.text(a),b.attr("data-name",a),b.click(__bind(function(a){var b;return $("#syntax").focus(),b=$(a.currentTarget).attr("data-name"),$("#syntax").val($("#syntax").val()+(" "+b+" ")),this.validateIn()},this))},f.prototype.findAttributes=function(b){return this.api.get(a,{},__bind(function(a){var b,c,d,e,f;e=a.rows,f=[];for(c=0,d=e.length;c<d;c++)b=e[c],f.push(this.attributeNode(b));return f},this))},f.prototype.validateIn=function(a){return clearTimeout(this.validateTimeout),this.validateTimeout=setTimeout(__bind(function(){return this.validate()},this),a||500)},f.prototype.validate=function(){var a,c;$("#syntax-status").text(""),c=$("#syntax").data("prev"),a=$.trim($("#syntax").val()),$("#syntax").data("prev",a);if(!a||a===c)return;return $("#syntax-status").text("Searching . . ."),$("#members").empty(),this.api.get2(b,a,__bind(function(a){var b,c,d,e,f;if(a.ok){$("#syntax-status").text(""),e=a.rows,f=[];for(c=0,d=e.length;c<d;c++)b=e[c],f.push(this.drawMember(b));return f}return $("#syntax-status").text(a.error)},this))},f.prototype.validateForm=function(){var a,b;return $("#name-error").empty(),b=!0,a=$.trim($("#name").val()),a===""&&($("#name-error").text("Name is required."),b=!1),b},f.prototype.save=function(){var a,b,d,e;if(!this.validateForm())return;return e=$("#users :checked").map(function(){return $(this).val()}).get(),a=$("#unix-users").val().split(","),a=function(){var b,c,e;e=[];for(b=0,c=a.length;b<c;b++)d=a[b],$.trim(d).length>0&&e.push($.trim(d));return e}(),b={name:$("#name").val(),code:$("#syntax").val(),accounts:a,users:e},$("#id").val().length>0&&(b.id=$("#id").val()),this.api.save(c,b,__bind(function(a){var b;return new Notification("Service saved successfully"),a.size=$("#members").length,$("#id").val(a.id),b=$("#services li[data-id='"+a.id+"']"),b.length===0?(b=this.serviceNode(a),this.selectService(b)):$(".text",b).text(a.name)},this)),!1},f.prototype.drawBlankSlate=function(){return $("#beta").empty(),$('<form id="blank-slate">\n <p>\n Services are dynamically updated groups of systems based on\n criteria you define. Send a command to the service and it runs\n on every system in the group.\n </p>\n <input type="submit" id="blank-slate-add" value="Add Service"/>\n</form>').appendTo("#beta"),this.api.user.permissions.services||$("#blank-slate-add").remove(),$("#blank-slate").submit(__bind(function(){return this.drawEditor(),!1},this))},f.prototype.draw=function(){var a;if(!this.session.connected()){window.location.hash="";return}return $("body").attr("id","services-page"),$("#container").hide().empty(),$('<div id="alpha" class="sidebar column y-fill">\n <h2>Services <div id="search-services-icon"></div></h2>\n <div id="search-services-form"></div>\n <ul id="services" class="selectable scroll y-fill"></ul>\n <div id="alpha-controls" class="controls">\n <div id="add-service"></div>\n <div id="remove-service"></div>\n </div>\n <form id="remove-service-form" class="overlay" style="display:none;">\n <h2>Remove Service</h2>\n <p id="remove-service-msg">Select a service in the list above to remove.</p>\n <fieldset class="buttons" style="display:none;">\n <input id="remove-service-cancel" type="button" value="Cancel"/>\n <input id="remove-service-ok" type="submit" value="Remove"/>\n </fieldset>\n </form>\n</div>\n<div id="beta" class="primary column x-fill y-fill"></div>\n<div id="charlie" class="sidebar column y-fill">\n <h2>Operators</h2>\n <ul id="operators"></ul>\n <h2>Attributes <div id="search-attributes-icon"></div></h2>\n <div id="search-attributes-form"></div>\n <ul id="attributes" class="y-fill scroll"></ul>\n</div>').appendTo("#container"),new Button("#add-service",ICONS.plus),new Button("#remove-service",ICONS.minus),this.api.user.permissions.services||$("#alpha-controls div").remove(),this.drawBlankSlate(),$("#add-service").click(__bind(function(){return this.drawEditor()},this)),$("#remove-service").click(__bind(function(){return this.toggleForm("#remove-service-form")},this)),$("#remove-service-cancel").click(__bind(function(){return this.toggleForm("#remove-service-form")},this)),$("#remove-service-form").submit(__bind(function(){return this.deleteService()},this)),this.operators(),this.findServices(),this.findAttributes(),this.findUsers(),$("#container").show(),this.layout=this.resize(),a=__bind(function(){return this.layout.resize(),this.layout.resize()},this),new Filter({list:"#services",icon:"#search-services-icon",form:"#search-services-form",attrs:["data-name"],open:a,close:a}),new Filter({list:"#attributes",icon:"#search-attributes-icon",form:"#search-attributes-form",attrs:["data-name"],open:a,close:a})},f.prototype.drawEditor=function(a){if(!this.pageVisible())return;return a||(this.selectedService=null,$("#services li").removeClass("selected")),$("#beta").empty(),$('<form id="editor-form" class="sections y-fill scroll">\n <input id="id" type="hidden"/>\n <div>\n <section>\n <h2>Service</h2>\n <fieldset>\n <label for="name">Name</label>\n <input id="name" type="text"/>\n <p id="name-error" class="error"></p>\n <label for="syntax">Criteria</label>\n <textarea id="syntax" placeholder="fqdn starts with \'www.\' and platform is \'mac_os_x\'"></textarea>\n <p id="syntax-status"></p>\n </fieldset>\n </section>\n <section>\n <h2>Members</h2>\n <fieldset id="service-preview">\n <ul id="members" class="scroll"></ul>\n </fieldset>\n </section>\n <section>\n <h2>Permissions</h2>\n <fieldset>\n <label>Users</label>\n <ul id="users" class="scroll"></ul>\n <label for="unix-users">Unix Accounts</label>\n <input id="unix-users" type="text"/>\n </fieldset>\n </section>\n </div>\n</form>\n<form id="editor-buttons">\n <input id="save" type="submit" value="Save"/>\n</form>').appendTo("#beta"),a&&(this.findMembers(a.id),$("#id").val(a.id),$("#name").val(a.name),$("#syntax").val(a.code),$("#unix-users").val(a.accounts.join(", "))),this.users.length>0&&this.drawUsers(),this.layout.resize(),$("#name").focus(),$("#syntax").change(__bind(function(){return this.validateIn()},this)),$("#syntax").keyup(__bind(function(){return this.validateIn()},this)),$("#editor-form").submit(__bind(function(){return this.save()},this)),$("#editor-buttons").submit(__bind(function(){return this.save()},this))},f.prototype.drawUsers=function(){var a,b,c,d,e;if(!this.editorVisible())return;$("#users").empty(),e=this.users;for(c=0,d=e.length;c<d;c++)b=e[c],a=$("<li>\n <input id='user-"+b.jid+"' type='checkbox' value='"+b.jid+"'/>\n <label for='user-"+b.jid+"'>"+b.jid+"</label>\n</li>").appendTo("#users"),b.jid===this.session.bareJid()&&$("input",a).prop("checked",!0);if(this.selectedService)return $('#users input[type="checkbox"]').val(this.selectedService.users)},f.prototype.toggleForm=function(a,b){return a=$(a),$("form.overlay").each(function(){if(this.id!==a.attr("id"))return $(this).hide()}),a.is(":hidden")?(b&&b(),a.fadeIn(100)):a.fadeOut(100,function(){a[0].reset();if(b)return b()})},f.prototype.pageVisible=function(){return $("#services-page").length>0},f.prototype.editorVisible=function(){return $("#services-page #editor-form").length>0},f.prototype.resize=function(){var a,b,c;return a=$("#alpha"),b=$("#beta"),c=$("#charlie"),new Layout(function(){return c.css("left",a.width()+b.width())})},f}();var FilesPage,__bind=function(a,b){return function(){return a.apply(b,arguments)}};FilesPage=function(){function d(a){this.session=a,this.api=new Api(this.session),this.uploads=new c({session:this.session,jid:this.api.jid,size:this.size,complete:__bind(function(a){return this.findFile(a.name)},this)})}var a,b,c;return a="http://getvines.com/protocol/files",b="http://getvines.com/protocol/files/labels",d.prototype.findLabels=function(){return $("#labels").empty(),this.api.get(b,{},__bind(function(a){var b,c,d,e,f;e=a.rows,f=[];for(c=0,d=e.length;c<d;c++)b=e[c],f.push(this.labelNodeList(b));return f},this))},d.prototype.labelNodeList=function(a){var b,c;return c=a.size===1?"file":"files",b=$('<li data-name="">\n <span class="text"></span>\n <span class="count">'+a.size+" "+c+"</span>\n</li>").appendTo("#labels"),$(".text",b).text(a.name),b.attr("data-name",a.name),b.click(__bind(function(a){return this.selectLabel(a)},this))},d.prototype.selectLabel=function(a){var b;return b=$(a.currentTarget).attr("data-name"),$("#labels li").removeClass("selected"),$(a.currentTarget).addClass("selected"),$("#files").empty(),this.findFiles({label:$(a.currentTarget).attr("data-name")})},d.prototype.findFiles=function(b){return this.api.get(a,b,__bind(function(a){var b,c,d,e,f;e=a.rows,f=[];for(c=0,d=e.length;c<d;c++)b=e[c],f.push(this.fileNode(b));return f},this))},d.prototype.findFile=function(b){return this.api.get(a,{name:b},__bind(function(a){return this.fileNode(a)},this))},d.prototype.updateFileNode=function(a){var b,c,d;return b=$("#files li[data-id='"+a.id+"']"),c=this.size(a.size),d=this.date(a.created_at),b.data("file",a),$("h2",b).text(a.name),$(".size",b).text(c),$(".time",b).text(d),b.attr("data-name",a.name),b.attr("data-size",c),b.attr("data-created",d)},d.prototype.fileNode=function(a){var b,c,d,e,f,g;if($("#files li[data-id='"+a.id+"']").length>0){this.updateFileNode(a);return}c=$('<li data-id="'+a.id+'">\n <div class="file-icon">\n <span class="size"></span>\n </div>\n <h2></h2>\n <footer>\n <span class="time"></span>\n <ul class="labels"></ul>\n <form class="add-label">\n <div class="add-label-button"></div>\n <input type="text" placeholder="Label" style="display:none;"/>\n </form>\n </footer>\n <form class="file-form">\n <fieldset>\n <input class="cancel" type="submit" value="Delete"/>\n </fieldset>\n </form>\n</li>').appendTo("#files"),new Button($(".file-icon",c).get(0),ICONS.page2,{scale:1,translation:"-2 0","stroke-width":.1,opacity:1}),new Button($(".add-label-button",c).get(0),ICONS.plus,{translation:"-10 -10",scale:.5}),$("form.file-form",c).submit(__bind(function(){return this.deleteFile(c)},this)),$("form.add-label",c).submit(__bind(function(){return this.addLabel(c)},this)),$(".add-label-button",c).click(function(){return $('form.add-label input[type="text"]',c).show()}),this.updateFileNode(a),f=a.labels,g=[];for(d=0,e=f.length;d<e;d++)b=f[d],g.push(this.labelNode(c,b));return g},d.prototype.labelNode=function(a,b){var c,d;return d=$(".labels",a),c=$('<li data-name="">\n <span class="text"></span>\n <div class="remove"></div>\n</li>').appendTo(d),$(".text",c).text(b),c.attr("data-name",b),new Button($(".remove",c).get(0),ICONS.cross,{translation:"-8 -8",scale:.5}),$(".remove",c).click(__bind(function(){return this.removeLabel(a,c)},this))},d.prototype.addLabel=function(b){var c,d,e,f,g,h,i,j,k;d=$('form.add-label input[type="text"]',b),d.hide(),f=function(){var a,b,c,e;c=d.val().split(/,/),e=[];for(a=0,b=c.length;a<b;a++)g=c[a],g&&e.push(g);return e}(),d.val(""),c=b.data("file");for(h=0,j=f.length;h<j;h++)e=f[h],c.labels.push(e);this.api.save(a,c,function(a){});for(i=0,k=f.length;i<k;i++)e=f[i],this.labelNode(b,e),this.updateLabelCount(e,1);return!1},d.prototype.removeLabel=function(b,c){var d,e,f;return d=b.data("file"),f=c.attr("data-name"),d.labels=function(){var a,b,c,g;c=d.labels,g=[];for(a=0,b=c.length;a<b;a++)e=c[a],e!==f&&g.push(e);return g}(),this.api.save(a,d,function(a){}),c.fadeOut(200,function(){return c.remove()}),this.updateLabelCount(f,-1)},d.prototype.updateLabelCount=function(a,b){var c,d,e;return d=$("#labels li[data-name='"+a+"'] .count"),d.length>0?(c=parseInt(d.text().split(" ")[0])+b,e=c===1?"file":"files",d.text(""+c+" "+e)):this.labelNodeList({name:a,size:1})},d.prototype.deleteFile=function(b){return this.api.remove(a,b.attr("data-id"),__bind(function(a){var c,d,e,f;f=b.data("file").labels;for(d=0,e=f.length;d<e;d++)c=f[d],this.updateLabelCount(c,-1);return b.fadeOut(200,function(){return b.remove()})},this)),!1},d.prototype.date=function(a){var b,c;return a=new Date(a),b="Sun Mon Tue Wed Thu Fri Sat".split(" ")[a.getDay()],c="Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" ")[a.getMonth()],""+b+", "+a.getDate()+" "+c+", "+a.getFullYear()+" @ "+a.getHours()+":"+a.getMinutes()},d.prototype.size=function(a){var b,c,d,e;return d=a/1024,e=d/1024,c=e/1024,b=function(a){return a<100?a.toFixed(1).replace(".0",""):Math.round(a)},d<1?""+a+" b":e<1?""+b(d)+" k":c<1?""+b(e)+" m":""+b(c)+" g"},d.prototype.draw=function(){var a,b;if(!this.session.connected()){window.location.hash="";return}return $("body").attr("id","files-page"),$("#container").hide().empty(),$('<div id="alpha" class="sidebar column y-fill">\n <h2>Labels</h2>\n <ul id="labels" class="selectable scroll y-fill"></ul>\n <div id="alpha-controls" class="controls"></div>\n</div>\n<div id="beta" class="primary column x-fill y-fill">\n <h2 id="files-title">Files <div id="search-files-icon"></div></h2>\n <div id="search-files-form"></div>\n <ul id="files" class="scroll y-fill"></ul>\n</div>\n<div id="charlie" class="sidebar column y-fill">\n <h2>Uploads</h2>\n <div id="upload-dnd" class="float">Drag files here to upload.</div>\n <ul id="uploads" class="scroll y-fill"></ul>\n <div id="charlie-controls" class="controls">\n <form id="file-form">\n <input id="open-file-chooser" type="submit" value="Select files to upload"/>\n <input id="file-chooser" type="file" multiple="true" />\n </form>\n </div>\n</div>').appendTo("#container"),this.api.user.permissions.files?($("#file-chooser").change(__bind(function(a){return this.uploads.queue(a.target.files),$("#file-chooser").val("")},this)),$("#file-form").submit(function(){return $("#file-chooser").click(),!1}),$("#upload-dnd").bind("dragenter",function(a){return a.stopPropagation(),a.preventDefault(),$("#upload-dnd").css("color","#444")}),$("#upload-dnd").bind("dragleave",function(a){return $("#upload-dnd").css("color","#ababab")}),$("#upload-dnd").bind("dragover",function(a){return a.stopPropagation(),a.preventDefault()}),$("#upload-dnd").bind("drop",__bind(function(a){return a.stopPropagation(),a.preventDefault(),$("#upload-dnd").css("color","#ababab"),this.uploads.queue(a.originalEvent.dataTransfer.files)},this))):($("#upload-dnd").text("Your account cannot upload files."),$("#file-form").remove()),this.findLabels(),this.findFiles(),$("#container").show(),b=this.resize(),a=function(){return b.resize(),b.resize()},new Filter({list:"#files",icon:"#search-files-icon",form:"#search-files-form",attrs:["data-name","data-created"],open:a,close:a})},d.prototype.resize=function(){var a,b,c,d,e;return a=$("#alpha"),b=$("#beta"),c=$("#charlie"),e=$("#uploads"),d=$("#upload-dnd"),new Layout(function(){return c.css("left",a.width()+b.width()),d.height(e.height()),d.css("line-height",e.height()+"px")})},c=function(){function a(a){this.session=a.session,this.serviceJid=a.jid,this.size=a.size,this.complete=a.complete,this.uploads=[],this.sending=null}return a.prototype.queue=function(a){var b,c,d;for(c=0,d=a.length;c<d;c++)b=a[c],this.find(b)||this.add(b);return this.process()},a.prototype.add=function(a){var b,c;return c=this.node(a),b=$(".meter",c),this.uploads.push(new Transfer({to:this.serviceJid(),file:a,session:this.session,progress:function(a){return b.css("width",a+"%")},complete:__bind(function(){return this.remove(a),this.complete&&this.complete(a),a.name===this.sending.name&&(this.sending=null),this.process()},this)}))},a.prototype.process=function(){var a;if(this.sending)return;return(a=this.uploads[0])?(this.sending=a.file,a.start()):this.sending=null},a.prototype.find=function(a){var b;return function(){var c,d,e,f;e=this.uploads,f=[];for(c=0,d=e.length;c<d;c++)b=e[c],b.file.name===a.name&&f.push(b);return f}.call(this).shift()},a.prototype.remove=function(a){var b,c;return this.uploads=function(){var b,d,e,f;e=this.uploads,f=[];for(b=0,d=e.length;b<d;b++)c=e[b],c.file.name!==a.name&&f.push(c);return f}.call(this),b=$("#uploads li[data-file='"+a.name+"']"),b.fadeOut(200,function(){return b.remove()})},a.prototype.node=function(a){var b;return b=$('<li data-file="" style="display:none;">\n <form class="inset">\n <h2></h2>\n <div class="progress">\n <div class="meter"></div>\n <span class="text">'+this.size(a.size)+'</span>\n <div class="cancel"></div>\n </div>\n </form>\n</li>').appendTo("#uploads"),b.fadeIn(200),$("h2",b).text(a.name),b.attr("data-file",a.name),new Button($(".cancel",b).get(0),ICONS.cross,{translation:"-8 -8",scale:.5}),$(".cancel",b).click(__bind(function(){return this.cancel(a)},this)),b},a.prototype.cancel=function(a){var b;if(b=this.find(a))return b.stop()},a}(),d}();var SetupPage,__bind=function(a,b){return function(){return a.apply(b,arguments)}};SetupPage=function(){function d(a){this.session=a,this.api=new Api(this.session),this.layout=null,this.selected=null,this.services=[],this.users=[]}var a,b,c;return a="http://getvines.com/protocol/services",b="http://getvines.com/protocol/systems",c="http://getvines.com/protocol/users",d.prototype.findSystem=function(a){return this.api.get(b,{name:a},__bind(function(a){return this.drawSystemInfo(a)},this))},d.prototype.findServices=function(){return this.api.get(a,{},__bind(function(a){return this.services=a.rows,this.drawServices()},this))},d.prototype.drawServices=function(){var a,b,c,d,e;if($("#setup-page #services").length===0)return;$("#services").empty(),e=this.services;for(c=0,d=e.length;c<d;c++)b=e[c],a=$("<li>\n <input id='service-"+b.id+"' type='checkbox' value='"+b.id+"'/>\n <label for='service-"+b.id+"'></label>\n</li>").appendTo("#services"),$("label",a).text(b.name);this.selected&&$('#services input[type="checkbox"]').val(this.selected.services);if(this.selected&&!this.api.user.permissions.services)return $('#services input[type="checkbox"]').prop("disabled",!0)},d.prototype.findUsers=function(){return this.api.get(c,{},__bind(function(a){return this.users=a.rows,this.drawUsers()},this))},d.prototype.drawUsers=function(){var a,b,c,d,e,f;if($("#setup-page #users").length===0)return;$("#users").empty(),a=$("#systems-nav").hasClass("selected"),e=this.users,f=[];for(c=0,d=e.length;c<d;c++)b=e[c],f.push(b.system===a?this.userNode(b):void 0);return f},d.prototype.userNode=function(a){var b,c;return c=$('<li data-name="" data-jid="'+a.jid+'" id="'+a.jid+'">\n <span class="text"></span>\n <span class="jid">'+a.jid+"</span>\n</li>").appendTo("#users"),b=this.userName(a),$(".text",c).text(b),c.attr("data-name",b),c.click(__bind(function(a){return this.selectUser(a.currentTarget)},this)),c},d.prototype.userName=function(a){return a.name||a.jid.split("@")[0]},d.prototype.selectUser=function(a){var b,d;return b=$(a).attr("data-jid"),d=$(a).attr("data-name"),$("#users li").removeClass("selected"),$(a).addClass("selected"),$("#remove-user-msg").html("Are you sure you want to remove "+("<strong>"+d+"</strong>?")),$("#remove-user-form .buttons").fadeIn(200),this.api.get(c,{jid:b},__bind(function(a){return this.selected=a,a.system?this.drawSystemEditor(a):this.drawUserEditor(a)},this))},d.prototype.removeUser=function(){var a;return this.toggleForm("#remove-user-form"),a=$("#users li[data-jid='"+this.selected.jid+"']"),this.api.remove(c,this.selected.jid,__bind(function(b){return a.fadeOut(200,__bind(function(){var b;return this.users=function(){var a,c,d,e;d=this.users,e=[];for(a=0,c=d.length;a<c;a++)b=d[a],b.jid!==this.selected.jid&&e.push(b);return e}.call(this),a.remove(),this.selected=null,$("#users-nav").hasClass("selected")?this.drawUserBlankSlate():this.drawSystemBlankSlate()},this))},this)),!1},d.prototype.selectTask=function(a){this.selected=null,$("#setup li").removeClass("selected secondary"),$(a.currentTarget).addClass("selected secondary");switch($(a.currentTarget).attr("id")){case"users-nav":return $("#beta-header").text("Users"),this.drawUsers(),this.drawUserBlankSlate(),this.api.user.permissions.users?$("#beta-controls div").show():$("#beta-controls div").hide();case"systems-nav":return $("#beta-header").text("Systems"),this.drawUsers(),this.drawSystemBlankSlate(),this.api.user.permissions.systems?$("#beta-controls div").show():$("#beta-controls div").hide()}},d.prototype.toggleForm=function(a,b){return a=$(a),$("form.overlay").each(function(){if(this.id!==a.attr("id"))return $(this).hide()}),a.is(":hidden")?(b&&b(),a.fadeIn(100)):a.fadeOut(100,function(){a[0].reset();if(b)return b()})},d.prototype.validateUser=function(){var a,b,c,d;$("#user-name-error").empty(),$("#password-error").empty(),d=!0,a=$.trim($("#user-name").val()),b=$.trim($("#password1").val()),c=$.trim($("#password2").val());if(this.selected)c.length>0&&c.length<8&&($("#password-error").text("Password must be at least 8 characters."
2
+ ),d=!1),this.session.bareJid()!==this.selected.jid&&b!==c&&($("#password-error").text("Passwords must match."),d=!1);else{a===""&&($("#user-name-error").text("User name is required."),d=!1),a.match(/[\s"&'\/:<>@]/)&&($("#user-name-error").text("User name contains forbidden characters."),d=!1);if(b.length===0||c.length===0)$("#password-error").text("Password is required."),d=!1;b!==c&&($("#password-error").text("Passwords must match."),d=!1),c.length<8&&($("#password-error").text("Password must be at least 8 characters."),d=!1)}return d},d.prototype.saveUser=function(){var a;return this.validateUser()?(a={jid:$("#jid").val(),username:$("#user-name").val(),name:$("#name").val(),password1:$("#password1").val(),password2:$("#password2").val(),services:$("#services :checked").map(function(){return $(this).val()}).get(),permissions:{systems:$("#perm-systems").prop("checked"),services:$("#perm-services").prop("checked"),files:$("#perm-files").prop("checked"),users:$("#perm-users").prop("checked")}},this.api.save(c,a,__bind(function(a){var b;return new Notification("User saved successfully"),$("#jid").val(a.jid),b=$("#users li[data-jid='"+a.jid+"']"),b.length===0?(this.users.push(a),b=this.userNode(a),this.selectUser(b)):$(".text",b).text(this.userName(a))},this)),!1):!1},d.prototype.validateSystem=function(){var a,b;return $("#user-name-error").empty(),b=!0,a=$.trim($("#user-name").val()),this.selected||(a===""&&($("#user-name-error").text("Hostname is required."),b=!1),a.match(/[\s"&'\/:<>@]/)&&($("#user-name-error").text("Hostname contains forbidden characters."),b=!1)),b},d.prototype.saveSystem=function(){var a;return this.validateSystem()?(a={jid:$("#jid").val(),username:$("#user-name").val(),password1:$("#password1").val(),password2:$("#password1").val(),system:!0},this.api.save(c,a,__bind(function(a){var b;return new Notification("System saved successfully"),$("#jid").val(a.jid),b=$("#users li[data-jid='"+a.jid+"']"),b.length===0?(this.users.push(a),b=this.userNode(a),this.selectUser(b)):$(".text",b).text(a.name)},this)),!1):!1},d.prototype.rand=function(){return Math.floor(Math.random()*16)},d.prototype.token=function(){var a;return function(){var b;b=[];for(a=0;a<=127;a++)b.push(this.rand().toString(16));return b}.call(this).join("")},d.prototype.drawUserBlankSlate=function(){var a;return $("#charlie").empty(),a=this.api.user.permissions.users?"Select a user account to update or add a new user.":"Select a user account to update.",$('<form id="blank-slate">\n <p>'+a+'</p>\n <input type="submit" id="blank-slate-add" value="Add User"/>\n</form>').appendTo("#charlie"),this.api.user.permissions.users||$("#blank-slate-add").remove(),$("#blank-slate").submit(__bind(function(){return this.drawUserEditor(),!1},this))},d.prototype.drawSystemBlankSlate=function(){return $("#charlie").empty(),$('<form id="blank-slate">\n <p>\n Systems need a user account before they can connect and\n authenticate with the chat server.\n </p>\n <input type="submit" id="blank-slate-add" value="Add System"/>\n</form>').appendTo("#charlie"),this.api.user.permissions.systems||$("#blank-slate-add").remove(),$("#blank-slate").submit(__bind(function(){return this.drawSystemEditor(),!1},this))},d.prototype.draw=function(){var a;if(!this.session.connected()){window.location.hash="";return}return $("body").attr("id","setup-page"),$("#container").hide().empty(),$('<div id="alpha" class="sidebar column y-fill">\n <h2>Setup</h2>\n <ul id="setup" class="selectable scroll y-fill">\n <li id="users-nav" class=\'selected secondary\'>\n <span class="text">Users</span>\n </li>\n <li id="systems-nav">\n <span class="text">Systems</span>\n </li>\n </ul>\n <div id="alpha-controls" class="controls"></div>\n</div>\n<div id="beta" class="sidebar column y-fill">\n <h2><span id="beta-header">Users</span> <div id="search-users-icon"></div></h2>\n <div id="search-users-form"></div>\n <ul id="users" class="selectable scroll y-fill"></ul>\n <form id="remove-user-form" class="overlay" style="display:none;">\n <h2>Remove User</h2>\n <p id="remove-user-msg">Select a user to delete.</p>\n <fieldset class="buttons" style="display:none;">\n <input id="remove-user-cancel" type="button" value="Cancel"/>\n <input id="remove-user-ok" type="submit" value="Remove"/>\n </fieldset>\n </form>\n <div id="beta-controls" class="controls">\n <div id="add-user"></div>\n <div id="remove-user"></div>\n </div>\n</div>\n<div id="charlie" class="primary column x-fill y-fill"></div>').appendTo("#container"),this.drawUserBlankSlate(),$("#setup li").click(__bind(function(a){return this.selectTask(a)},this)),this.findUsers(),this.findServices(),$("#container").show(),this.layout=this.resize(),new Button("#add-user",ICONS.plus),new Button("#remove-user",ICONS.minus),this.api.user.permissions.users||$("#beta-controls div").hide(),this.api.user.permissions.systems||$("#systems-nav").hide(),$("#add-user").click(__bind(function(){return $("#users-nav").hasClass("selected")?this.drawUserEditor():this.drawSystemEditor()},this)),$("#remove-user").click(__bind(function(){return this.toggleForm("#remove-user-form")},this)),$("#remove-user-cancel").click(__bind(function(){return this.toggleForm("#remove-user-form")},this)),$("#remove-user-form").submit(__bind(function(){return this.removeUser()},this)),a=__bind(function(){return this.layout.resize(),this.layout.resize()},this),new Filter({list:"#users",icon:"#search-users-icon",form:"#search-users-form",attrs:["data-jid","data-name"],open:a,close:a})},d.prototype.drawUserEditor=function(a){var b,c,d,e;a||(this.selected=null,$("#users li").removeClass("selected")),$("#charlie").empty(),$('<form id="editor-form" class="sections y-fill scroll">\n <div>\n <section>\n <h2>User</h2>\n <fieldset id="jid-fields">\n <input id="jid" type="hidden" value=""/>\n <label for="name">Real Name</label>\n <input id="name" type="text" maxlength="1024"/>\n </fieldset>\n </section>\n <section>\n <h2>Password</h2>\n <fieldset>\n <label id="password1-label" for="password1">Current Password</label>\n <input id="password1" type="password" maxlength="1024"/>\n <label id="password2-label" for="password2">New Password</label>\n <input id="password2" type="password" maxlength="1024"/>\n <p id="password-error" class="error"></p>\n </fieldset>\n </section>\n <section>\n <h2>Permissions</h2>\n <fieldset>\n <label>Manage</label>\n <ul id="permissions">\n <li>\n <input id="perm-systems" type="checkbox" value="systems"/>\n <label for="perm-systems">Systems</label>\n </li>\n <li>\n <input id="perm-services" type="checkbox" value="services"/>\n <label for="perm-services">Services</label>\n </li>\n <li>\n <input id="perm-users" type="checkbox" value="users"/>\n <label for="perm-users">Users</label>\n </li>\n <li>\n <input id="perm-files" type="checkbox" value="files"/>\n <label for="perm-files">Files</label>\n </li>\n </ul>\n </fieldset>\n </section>\n <section>\n <h2>Services</h2>\n <fieldset>\n <label>Access To</label>\n <ul id="services" class="scroll"></ul>\n </fieldset>\n </section>\n </div>\n</form>\n<form id="editor-buttons">\n <input id="save" type="submit" value="Save"/>\n</form>').appendTo("#charlie");if(a){$("<label>Account Name</label>\n<p>"+a.jid+"</p>").prependTo("#jid-fields"),$("#name").focus(),this.session.bareJid()!==a.jid&&($("#password1-label").text("Password"),$("#password2-label").text("Password Again")),$("#jid").val(a.jid),$("#name").val(a.name),$("#user-name").val(a.jid.split("@")[0]),e="services systems files users".split(" ");for(c=0,d=e.length;c<d;c++)b=e[c],a.permissions[b]&&$("#perm-"+b).prop("checked",!0),this.session.bareJid()===a.jid&&$("#perm-"+b).prop("disabled",!0)}else $('<label for="user-name">User Name</label>\n<input id="user-name" type="text" maxlength="1023"/>\n<p id="user-name-error" class="error"></p>').prependTo("#jid-fields"),$("#password1-label").text("Password"),$("#password2-label").text("Password Again"),$("#user-name").focus();return this.services.length>0&&this.drawServices(),this.layout.resize(),$("#editor-form").submit(__bind(function(){return this.saveUser()},this)),$("#editor-buttons").submit(__bind(function(){return this.saveUser()},this))},d.prototype.drawSystemEditor=function(a){return a||(this.selected=null,$("#users li").removeClass("selected")),$("#charlie").empty(),$('<form id="editor-form" class="sections y-fill scroll">\n <div>\n <section>\n <h2>System</h2>\n <fieldset id="jid-fields">\n <input id="jid" type="hidden" value=""/>\n <label id="password1-label" for="password1">Authentication Token</label>\n <div id="token-container">\n <input id="password1" type="text" readonly placeholder="Press Generate to create a new token"/>\n <input id="new-token" type="button" value="Generate"/>\n </div>\n </fieldset>\n </section>\n <section id="info">\n <h2>Info</h2>\n <fieldset>\n <label>Platform</label>\n <p id="info-platform">-</p>\n <label>Hostname</label>\n <p id="info-fqdn">-</p>\n <label>IP Address</label>\n <p id="info-ip">-</p>\n <label>MAC Address</label>\n <p id="info-mac">-</p>\n </fieldset>\n </section>\n </div>\n</form>\n<form id="editor-buttons">\n <input id="save" type="submit" value="Save"/>\n</form>').appendTo("#charlie"),$("#new-token").click(__bind(function(){return $("#password1").val(this.token())},this)),a&&this.findSystem(a.jid.split("@")[0]),a?($("<label>Account Name</label>\n<p>"+a.jid+"</p>").prependTo("#jid-fields"),$("#jid").val(a.jid),$("#user-name").val(a.jid.split("@")[0])):($('<label for="user-name">Hostname</label>\n<input id="user-name" type="text" maxlength="1023"/>\n<p id="user-name-error" class="error"></p>').prependTo("#jid-fields"),$("#user-name").focus(),$("#password1").val(this.token())),this.layout.resize(),$("#editor-form").submit(__bind(function(){return this.saveSystem()},this)),$("#editor-buttons").submit(__bind(function(){return this.saveSystem()},this))},d.prototype.drawSystemInfo=function(a){return $("#info-platform").text(a.platform),$("#info-fqdn").text(a.fqdn),$("#info-ip").text(a.ipaddress),$("#info-mac").text(a.macaddress)},d.prototype.resize=function(){var a,b,c;return a=$("#alpha"),b=$("#beta"),c=$("#charlie"),new Layout(function(){return c.css("left",a.outerWidth()+b.outerWidth())})},d}(),$(function(){var a,b,c,d,e,f;f=new Session,d=new NavBar(f),d.draw(),a={Systems:ICONS.commandline,Services:ICONS.magic,Files:ICONS.page2,Setup:ICONS.gear2,Logout:ICONS.power};for(c in a)b=a[c],d.addButton(c,b);return e={"/systems":new SystemsPage(f),"/services":new ServicesPage(f),"/files":new FilesPage(f),"/setup":new SetupPage(f),"/logout":new LogoutPage(f),"default":new LoginPage(f,"/systems/")},(new Router(e)).draw(),d.select($("#nav-link-systems").parent())})
@@ -0,0 +1,28 @@
1
+ var Commands;
2
+ Commands = (function() {
3
+ function Commands() {
4
+ this.buf = [];
5
+ this.index = 0;
6
+ }
7
+ Commands.prototype.prev = function() {
8
+ var val;
9
+ val = this.buf[--this.index];
10
+ if (!val) {
11
+ this.index = -1;
12
+ }
13
+ return val || '';
14
+ };
15
+ Commands.prototype.next = function() {
16
+ var val;
17
+ val = this.buf[++this.index];
18
+ if (!val) {
19
+ this.index = this.buf.length;
20
+ }
21
+ return val || '';
22
+ };
23
+ Commands.prototype.push = function(cmd) {
24
+ this.buf.push(cmd);
25
+ return this.index = this.buf.length;
26
+ };
27
+ return Commands;
28
+ })();
@@ -0,0 +1,424 @@
1
+ var FilesPage;
2
+ var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
3
+ FilesPage = (function() {
4
+ var FILES, LABELS, Uploads;
5
+ FILES = 'http://getvines.com/protocol/files';
6
+ LABELS = 'http://getvines.com/protocol/files/labels';
7
+ function FilesPage(session) {
8
+ this.session = session;
9
+ this.api = new Api(this.session);
10
+ this.uploads = new Uploads({
11
+ session: this.session,
12
+ jid: this.api.jid,
13
+ size: this.size,
14
+ complete: __bind(function(file) {
15
+ return this.findFile(file.name);
16
+ }, this)
17
+ });
18
+ }
19
+ FilesPage.prototype.findLabels = function() {
20
+ $('#labels').empty();
21
+ return this.api.get(LABELS, {}, __bind(function(result) {
22
+ var row, _i, _len, _ref, _results;
23
+ _ref = result.rows;
24
+ _results = [];
25
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
26
+ row = _ref[_i];
27
+ _results.push(this.labelNodeList(row));
28
+ }
29
+ return _results;
30
+ }, this));
31
+ };
32
+ FilesPage.prototype.labelNodeList = function(label) {
33
+ var node, text;
34
+ text = label.size === 1 ? 'file' : 'files';
35
+ node = $("<li data-name=\"\">\n <span class=\"text\"></span>\n <span class=\"count\">" + label.size + " " + text + "</span>\n</li>").appendTo('#labels');
36
+ $('.text', node).text(label.name);
37
+ node.attr('data-name', label.name);
38
+ return node.click(__bind(function(event) {
39
+ return this.selectLabel(event);
40
+ }, this));
41
+ };
42
+ FilesPage.prototype.selectLabel = function(event) {
43
+ var name;
44
+ name = $(event.currentTarget).attr('data-name');
45
+ $('#labels li').removeClass('selected');
46
+ $(event.currentTarget).addClass('selected');
47
+ $('#files').empty();
48
+ return this.findFiles({
49
+ label: $(event.currentTarget).attr('data-name')
50
+ });
51
+ };
52
+ FilesPage.prototype.findFiles = function(criteria) {
53
+ return this.api.get(FILES, criteria, __bind(function(result) {
54
+ var row, _i, _len, _ref, _results;
55
+ _ref = result.rows;
56
+ _results = [];
57
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
58
+ row = _ref[_i];
59
+ _results.push(this.fileNode(row));
60
+ }
61
+ return _results;
62
+ }, this));
63
+ };
64
+ FilesPage.prototype.findFile = function(name) {
65
+ return this.api.get(FILES, {
66
+ name: name
67
+ }, __bind(function(result) {
68
+ return this.fileNode(result);
69
+ }, this));
70
+ };
71
+ FilesPage.prototype.updateFileNode = function(file) {
72
+ var node, size, time;
73
+ node = $("#files li[data-id='" + file.id + "']");
74
+ size = this.size(file.size);
75
+ time = this.date(file.created_at);
76
+ node.data('file', file);
77
+ $('h2', node).text(file.name);
78
+ $('.size', node).text(size);
79
+ $('.time', node).text(time);
80
+ node.attr('data-name', file.name);
81
+ node.attr('data-size', size);
82
+ return node.attr('data-created', time);
83
+ };
84
+ FilesPage.prototype.fileNode = function(file) {
85
+ var label, node, _i, _len, _ref, _results;
86
+ if ($("#files li[data-id='" + file.id + "']").length > 0) {
87
+ this.updateFileNode(file);
88
+ return;
89
+ }
90
+ node = $("<li data-id=\"" + file.id + "\">\n <div class=\"file-icon\">\n <span class=\"size\"></span>\n </div>\n <h2></h2>\n <footer>\n <span class=\"time\"></span>\n <ul class=\"labels\"></ul>\n <form class=\"add-label\">\n <div class=\"add-label-button\"></div>\n <input type=\"text\" placeholder=\"Label\" style=\"display:none;\"/>\n </form>\n </footer>\n <form class=\"file-form\">\n <fieldset>\n <input class=\"cancel\" type=\"submit\" value=\"Delete\"/>\n </fieldset>\n </form>\n</li>").appendTo('#files');
91
+ new Button($('.file-icon', node).get(0), ICONS.page2, {
92
+ scale: 1.0,
93
+ translation: '-2 0',
94
+ 'stroke-width': 0.1,
95
+ opacity: 1.0
96
+ });
97
+ new Button($('.add-label-button', node).get(0), ICONS.plus, {
98
+ translation: '-10 -10',
99
+ scale: 0.5
100
+ });
101
+ $('form.file-form', node).submit(__bind(function() {
102
+ return this.deleteFile(node);
103
+ }, this));
104
+ $('form.add-label', node).submit(__bind(function() {
105
+ return this.addLabel(node);
106
+ }, this));
107
+ $('.add-label-button', node).click(function() {
108
+ return $('form.add-label input[type="text"]', node).show();
109
+ });
110
+ this.updateFileNode(file);
111
+ _ref = file.labels;
112
+ _results = [];
113
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
114
+ label = _ref[_i];
115
+ _results.push(this.labelNode(node, label));
116
+ }
117
+ return _results;
118
+ };
119
+ FilesPage.prototype.labelNode = function(node, label) {
120
+ var item, labels;
121
+ labels = $('.labels', node);
122
+ item = $("<li data-name=\"\">\n <span class=\"text\"></span>\n <div class=\"remove\"></div>\n</li>").appendTo(labels);
123
+ $('.text', item).text(label);
124
+ item.attr('data-name', label);
125
+ new Button($('.remove', item).get(0), ICONS.cross, {
126
+ translation: '-8 -8',
127
+ scale: 0.5
128
+ });
129
+ return $('.remove', item).click(__bind(function() {
130
+ return this.removeLabel(node, item);
131
+ }, this));
132
+ };
133
+ FilesPage.prototype.addLabel = function(node) {
134
+ var file, input, label, labels, val, _i, _j, _len, _len2;
135
+ input = $('form.add-label input[type="text"]', node);
136
+ input.hide();
137
+ labels = (function() {
138
+ var _i, _len, _ref, _results;
139
+ _ref = input.val().split(/,/);
140
+ _results = [];
141
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
142
+ val = _ref[_i];
143
+ if (val) {
144
+ _results.push(val);
145
+ }
146
+ }
147
+ return _results;
148
+ })();
149
+ input.val('');
150
+ file = node.data('file');
151
+ for (_i = 0, _len = labels.length; _i < _len; _i++) {
152
+ label = labels[_i];
153
+ file.labels.push(label);
154
+ }
155
+ this.api.save(FILES, file, function(result) {});
156
+ for (_j = 0, _len2 = labels.length; _j < _len2; _j++) {
157
+ label = labels[_j];
158
+ this.labelNode(node, label);
159
+ this.updateLabelCount(label, 1);
160
+ }
161
+ return false;
162
+ };
163
+ FilesPage.prototype.removeLabel = function(node, item) {
164
+ var file, label, remove;
165
+ file = node.data('file');
166
+ remove = item.attr('data-name');
167
+ file.labels = (function() {
168
+ var _i, _len, _ref, _results;
169
+ _ref = file.labels;
170
+ _results = [];
171
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
172
+ label = _ref[_i];
173
+ if (label !== remove) {
174
+ _results.push(label);
175
+ }
176
+ }
177
+ return _results;
178
+ })();
179
+ this.api.save(FILES, file, function(result) {});
180
+ item.fadeOut(200, function() {
181
+ return item.remove();
182
+ });
183
+ return this.updateLabelCount(remove, -1);
184
+ };
185
+ FilesPage.prototype.updateLabelCount = function(name, inc) {
186
+ var count, el, text;
187
+ el = $("#labels li[data-name='" + name + "'] .count");
188
+ if (el.length > 0) {
189
+ count = parseInt(el.text().split(' ')[0]) + inc;
190
+ text = count === 1 ? 'file' : 'files';
191
+ return el.text("" + count + " " + text);
192
+ } else {
193
+ return this.labelNodeList({
194
+ name: name,
195
+ size: 1
196
+ });
197
+ }
198
+ };
199
+ FilesPage.prototype.deleteFile = function(node) {
200
+ this.api.remove(FILES, node.attr('data-id'), __bind(function(result) {
201
+ var label, _i, _len, _ref;
202
+ _ref = node.data('file').labels;
203
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
204
+ label = _ref[_i];
205
+ this.updateLabelCount(label, -1);
206
+ }
207
+ return node.fadeOut(200, function() {
208
+ return node.remove();
209
+ });
210
+ }, this));
211
+ return false;
212
+ };
213
+ FilesPage.prototype.date = function(date) {
214
+ var day, month;
215
+ date = new Date(date);
216
+ day = 'Sun Mon Tue Wed Thu Fri Sat'.split(' ')[date.getDay()];
217
+ month = 'Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec'.split(' ')[date.getMonth()];
218
+ return "" + day + ", " + (date.getDate()) + " " + month + ", " + (date.getFullYear()) + " @ " + (date.getHours()) + ":" + (date.getMinutes());
219
+ };
220
+ FilesPage.prototype.size = function(bytes) {
221
+ var fmt, gb, kb, mb;
222
+ kb = bytes / 1024;
223
+ mb = kb / 1024;
224
+ gb = mb / 1024;
225
+ fmt = function(num) {
226
+ if (num >= 100) {
227
+ return Math.round(num);
228
+ } else {
229
+ return num.toFixed(1).replace('.0', '');
230
+ }
231
+ };
232
+ if (kb < 1) {
233
+ return "" + bytes + " b";
234
+ } else if (mb < 1) {
235
+ return "" + (fmt(kb)) + " k";
236
+ } else if (gb < 1) {
237
+ return "" + (fmt(mb)) + " m";
238
+ } else {
239
+ return "" + (fmt(gb)) + " g";
240
+ }
241
+ };
242
+ FilesPage.prototype.draw = function() {
243
+ var fn, layout;
244
+ if (!this.session.connected()) {
245
+ window.location.hash = '';
246
+ return;
247
+ }
248
+ $('body').attr('id', 'files-page');
249
+ $('#container').hide().empty();
250
+ $("<div id=\"alpha\" class=\"sidebar column y-fill\">\n <h2>Labels</h2>\n <ul id=\"labels\" class=\"selectable scroll y-fill\"></ul>\n <div id=\"alpha-controls\" class=\"controls\"></div>\n</div>\n<div id=\"beta\" class=\"primary column x-fill y-fill\">\n <h2 id=\"files-title\">Files <div id=\"search-files-icon\"></div></h2>\n <div id=\"search-files-form\"></div>\n <ul id=\"files\" class=\"scroll y-fill\"></ul>\n</div>\n<div id=\"charlie\" class=\"sidebar column y-fill\">\n <h2>Uploads</h2>\n <div id=\"upload-dnd\" class=\"float\">Drag files here to upload.</div>\n <ul id=\"uploads\" class=\"scroll y-fill\"></ul>\n <div id=\"charlie-controls\" class=\"controls\">\n <form id=\"file-form\">\n <input id=\"open-file-chooser\" type=\"submit\" value=\"Select files to upload\"/>\n <input id=\"file-chooser\" type=\"file\" multiple=\"true\" />\n </form>\n </div>\n</div>").appendTo('#container');
251
+ if (this.api.user.permissions.files) {
252
+ $('#file-chooser').change(__bind(function(event) {
253
+ this.uploads.queue(event.target.files);
254
+ return $('#file-chooser').val('');
255
+ }, this));
256
+ $('#file-form').submit(function() {
257
+ $('#file-chooser').click();
258
+ return false;
259
+ });
260
+ $('#upload-dnd').bind('dragenter', function(event) {
261
+ event.stopPropagation();
262
+ event.preventDefault();
263
+ return $('#upload-dnd').css('color', '#444');
264
+ });
265
+ $('#upload-dnd').bind('dragleave', function(event) {
266
+ return $('#upload-dnd').css('color', '#ababab');
267
+ });
268
+ $('#upload-dnd').bind('dragover', function(event) {
269
+ event.stopPropagation();
270
+ return event.preventDefault();
271
+ });
272
+ $('#upload-dnd').bind('drop', __bind(function(event) {
273
+ event.stopPropagation();
274
+ event.preventDefault();
275
+ $('#upload-dnd').css('color', '#ababab');
276
+ return this.uploads.queue(event.originalEvent.dataTransfer.files);
277
+ }, this));
278
+ } else {
279
+ $('#upload-dnd').text("Your account cannot upload files.");
280
+ $('#file-form').remove();
281
+ }
282
+ this.findLabels();
283
+ this.findFiles();
284
+ $('#container').show();
285
+ layout = this.resize();
286
+ fn = function() {
287
+ layout.resize();
288
+ return layout.resize();
289
+ };
290
+ return new Filter({
291
+ list: '#files',
292
+ icon: '#search-files-icon',
293
+ form: '#search-files-form',
294
+ attrs: ['data-name', 'data-created'],
295
+ open: fn,
296
+ close: fn
297
+ });
298
+ };
299
+ FilesPage.prototype.resize = function() {
300
+ var a, b, c, dnd, up;
301
+ a = $('#alpha');
302
+ b = $('#beta');
303
+ c = $('#charlie');
304
+ up = $('#uploads');
305
+ dnd = $('#upload-dnd');
306
+ return new Layout(function() {
307
+ c.css('left', a.width() + b.width());
308
+ dnd.height(up.height());
309
+ return dnd.css('line-height', up.height() + 'px');
310
+ });
311
+ };
312
+ Uploads = (function() {
313
+ function Uploads(options) {
314
+ this.session = options.session;
315
+ this.serviceJid = options.jid;
316
+ this.size = options.size;
317
+ this.complete = options.complete;
318
+ this.uploads = [];
319
+ this.sending = null;
320
+ }
321
+ Uploads.prototype.queue = function(files) {
322
+ var file, _i, _len;
323
+ for (_i = 0, _len = files.length; _i < _len; _i++) {
324
+ file = files[_i];
325
+ if (!this.find(file)) {
326
+ this.add(file);
327
+ }
328
+ }
329
+ return this.process();
330
+ };
331
+ Uploads.prototype.add = function(file) {
332
+ var meter, node;
333
+ node = this.node(file);
334
+ meter = $('.meter', node);
335
+ return this.uploads.push(new Transfer({
336
+ to: this.serviceJid(),
337
+ file: file,
338
+ session: this.session,
339
+ progress: function(pct) {
340
+ return meter.css('width', pct + '%');
341
+ },
342
+ complete: __bind(function() {
343
+ this.remove(file);
344
+ if (this.complete) {
345
+ this.complete(file);
346
+ }
347
+ if (file.name === this.sending.name) {
348
+ this.sending = null;
349
+ }
350
+ return this.process();
351
+ }, this)
352
+ }));
353
+ };
354
+ Uploads.prototype.process = function() {
355
+ var upload;
356
+ if (this.sending) {
357
+ return;
358
+ }
359
+ if (upload = this.uploads[0]) {
360
+ this.sending = upload.file;
361
+ return upload.start();
362
+ } else {
363
+ return this.sending = null;
364
+ }
365
+ };
366
+ Uploads.prototype.find = function(file) {
367
+ var up;
368
+ return ((function() {
369
+ var _i, _len, _ref, _results;
370
+ _ref = this.uploads;
371
+ _results = [];
372
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
373
+ up = _ref[_i];
374
+ if (up.file.name === file.name) {
375
+ _results.push(up);
376
+ }
377
+ }
378
+ return _results;
379
+ }).call(this)).shift();
380
+ };
381
+ Uploads.prototype.remove = function(file) {
382
+ var node, up;
383
+ this.uploads = (function() {
384
+ var _i, _len, _ref, _results;
385
+ _ref = this.uploads;
386
+ _results = [];
387
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
388
+ up = _ref[_i];
389
+ if (up.file.name !== file.name) {
390
+ _results.push(up);
391
+ }
392
+ }
393
+ return _results;
394
+ }).call(this);
395
+ node = $("#uploads li[data-file='" + file.name + "']");
396
+ return node.fadeOut(200, function() {
397
+ return node.remove();
398
+ });
399
+ };
400
+ Uploads.prototype.node = function(file) {
401
+ var node;
402
+ node = $("<li data-file=\"\" style=\"display:none;\">\n <form class=\"inset\">\n <h2></h2>\n <div class=\"progress\">\n <div class=\"meter\"></div>\n <span class=\"text\">" + (this.size(file.size)) + "</span>\n <div class=\"cancel\"></div>\n </div>\n </form>\n</li>").appendTo('#uploads');
403
+ node.fadeIn(200);
404
+ $('h2', node).text(file.name);
405
+ node.attr('data-file', file.name);
406
+ new Button($('.cancel', node).get(0), ICONS.cross, {
407
+ translation: '-8 -8',
408
+ scale: 0.5
409
+ });
410
+ $('.cancel', node).click(__bind(function() {
411
+ return this.cancel(file);
412
+ }, this));
413
+ return node;
414
+ };
415
+ Uploads.prototype.cancel = function(file) {
416
+ var upload;
417
+ if (upload = this.find(file)) {
418
+ return upload.stop();
419
+ }
420
+ };
421
+ return Uploads;
422
+ })();
423
+ return FilesPage;
424
+ })();
@@ -0,0 +1,27 @@
1
+ $(function() {
2
+ var buttons, icon, label, nav, pages, session;
3
+ session = new Session();
4
+ nav = new NavBar(session);
5
+ nav.draw();
6
+ buttons = {
7
+ Systems: ICONS.commandline,
8
+ Services: ICONS.magic,
9
+ Files: ICONS.page2,
10
+ Setup: ICONS.gear2,
11
+ Logout: ICONS.power
12
+ };
13
+ for (label in buttons) {
14
+ icon = buttons[label];
15
+ nav.addButton(label, icon);
16
+ }
17
+ pages = {
18
+ '/systems': new SystemsPage(session),
19
+ '/services': new ServicesPage(session),
20
+ '/files': new FilesPage(session),
21
+ '/setup': new SetupPage(session),
22
+ '/logout': new LogoutPage(session),
23
+ 'default': new LoginPage(session, '/systems/')
24
+ };
25
+ new Router(pages).draw();
26
+ return nav.select($('#nav-link-systems').parent());
27
+ });