vines-services 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/Gemfile +3 -0
  2. data/{README → README.md} +19 -9
  3. data/Rakefile +20 -113
  4. data/{web/coffeescripts → app/assets/javascripts}/api.coffee +1 -1
  5. data/{web/coffeescripts/init.coffee → app/assets/javascripts/application.coffee} +9 -0
  6. data/{web/coffeescripts → app/assets/javascripts}/commands.coffee +1 -1
  7. data/{web/coffeescripts → app/assets/javascripts}/files.coffee +1 -1
  8. data/{web/coffeescripts → app/assets/javascripts}/services.coffee +1 -1
  9. data/{web/coffeescripts → app/assets/javascripts}/setup.coffee +1 -1
  10. data/{web/coffeescripts → app/assets/javascripts}/systems.coffee +1 -1
  11. data/app/assets/stylesheets/application.css +9 -0
  12. data/{web → app/assets}/stylesheets/common.css +0 -0
  13. data/{web → app/assets}/stylesheets/files.css +0 -0
  14. data/{web → app/assets}/stylesheets/services.css +0 -0
  15. data/{web → app/assets}/stylesheets/setup.css +0 -0
  16. data/{web → app/assets}/stylesheets/systems.css +0 -0
  17. data/config.ru +12 -0
  18. data/lib/vines/services/command/init.rb +4 -1
  19. data/lib/vines/services/version.rb +1 -1
  20. data/{web/stylesheets/app.css → public/assets/application.css} +854 -395
  21. data/public/assets/application.js +10 -0
  22. data/{web → public}/images/default-service.png +0 -0
  23. data/{web → public}/images/linux.png +0 -0
  24. data/{web → public}/images/mac.png +0 -0
  25. data/{web → public}/images/run.png +0 -0
  26. data/{web → public}/images/windows.png +0 -0
  27. data/public/index.html +13 -0
  28. data/test/config_test.rb +1 -1
  29. data/test/priority_queue_test.rb +1 -1
  30. data/test/storage/couchdb_test.rb +1 -1
  31. data/test/vql/compiler_test.rb +1 -1
  32. data/test/vql/vql_test.rb +1 -1
  33. data/vines-services.gemspec +44 -0
  34. metadata +233 -59
  35. data/web/index.html +0 -17
  36. data/web/javascripts/api.js +0 -69
  37. data/web/javascripts/app.js +0 -2
  38. data/web/javascripts/commands.js +0 -28
  39. data/web/javascripts/files.js +0 -424
  40. data/web/javascripts/init.js +0 -27
  41. data/web/javascripts/services.js +0 -409
  42. data/web/javascripts/setup.js +0 -507
  43. data/web/javascripts/systems.js +0 -391
data/web/index.html DELETED
@@ -1,17 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
5
- <meta charset="utf-8">
6
- <meta name="apple-mobile-web-app-capable" content="yes">
7
- <title>Vines</title>
8
- <link rel="shortcut icon" type="image/png" href="/favicon.png">
9
- <script type="text/javascript" src="/lib/javascripts/base.js"></script>
10
- <script type="text/javascript" src="javascripts/app.js"></script>
11
- <link rel="stylesheet" href="/lib/stylesheets/base.css">
12
- <link rel="stylesheet" href="/lib/stylesheets/login.css">
13
- <link rel="stylesheet" href="stylesheets/app.css">
14
- </head>
15
- <body>
16
- </body>
17
- </html>
@@ -1,69 +0,0 @@
1
- var Api;
2
- var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
3
- Api = (function() {
4
- var USERS;
5
- USERS = 'http://getvines.com/protocol/users';
6
- function Api(session) {
7
- this.session = session;
8
- this.user = null;
9
- this.session.onRoster(__bind(function() {
10
- return this.get(USERS, {
11
- jid: this.session.bareJid()
12
- }, __bind(function(result) {
13
- return this.user = result;
14
- }, this));
15
- }, this));
16
- }
17
- Api.prototype.jid = function() {
18
- return "vines." + (this.session.bareJid().split('@')[1]);
19
- };
20
- Api.prototype.get = function(ns, criteria, callback) {
21
- var key, node, value;
22
- node = this.session.xml("<iq id=\"" + (this.session.uniqueId()) + "\" to=\"" + (this.jid()) + "\" type=\"get\">\n <query xmlns=\"" + ns + "\"/>\n</iq>");
23
- for (key in criteria) {
24
- value = criteria[key];
25
- $('query', node).attr(key, value);
26
- }
27
- return this.session.sendIQ(node, __bind(function(result) {
28
- var ok;
29
- ok = $(result).attr('type') === 'result';
30
- if (!ok) {
31
- return;
32
- }
33
- return callback(JSON.parse($('query', result).text()));
34
- }, this));
35
- };
36
- Api.prototype.get2 = function(ns, body, callback) {
37
- var node;
38
- node = this.session.xml("<iq id=\"" + (this.session.uniqueId()) + "\" to=\"" + (this.jid()) + "\" type=\"get\">\n <query xmlns=\"" + ns + "\"/>\n</iq>");
39
- $('query', node).text(body);
40
- return this.session.sendIQ(node, __bind(function(result) {
41
- var ok;
42
- ok = $(result).attr('type') === 'result';
43
- if (!ok) {
44
- return;
45
- }
46
- return callback(JSON.parse($('query', result).text()));
47
- }, this));
48
- };
49
- Api.prototype.remove = function(ns, id, callback) {
50
- var node;
51
- node = this.session.xml("<iq id=\"" + (this.session.uniqueId()) + "\" to=\"" + (this.jid()) + "\" type=\"set\">\n <query xmlns=\"" + ns + "\" action=\"delete\" id=\"\"/>\n</iq>");
52
- $('query', node).attr('id', id);
53
- return this.session.sendIQ(node, callback);
54
- };
55
- Api.prototype.save = function(ns, obj, callback) {
56
- var node;
57
- node = this.session.xml("<iq id=\"" + (this.session.uniqueId()) + "\" to=\"" + (this.jid()) + "\" type=\"set\">\n <query xmlns=\"" + ns + "\"/>\n</iq>");
58
- $('query', node).text(JSON.stringify(obj));
59
- return this.session.sendIQ(node, __bind(function(result) {
60
- var ok;
61
- ok = $(result).attr('type') === 'result';
62
- if (!ok) {
63
- return;
64
- }
65
- return callback(JSON.parse($('query', result).text()));
66
- }, this));
67
- };
68
- return Api;
69
- })();
@@ -1,2 +0,0 @@
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,m,n;d=this.groupContacts(),k=function(){var a;a=[];for(c in d)b=d[c],a.push(c);return a}(),k=k.sort(function(a,b){return a=a.toLowerCase(),b=b.toLowerCase(),a>b?1:a<b?-1:0}),f=$("#roster-items").empty(),n=[];for(l=0,m=k.length;l<m;l++)c=k[l],b=d[c],h=$('<li class="group"></li>').appendTo(f),h.text(c),h.attr("data-group",c),n.push(function(){var d,h,k;k=[];for(d=0,h=b.length;d<h;d++)a=b[d],i=$('<li data-jid="'+a.jid+'">\n <span class="icon"></span>\n <span class="text"></span>\n <span class="unread" style="display:none;"></span>\n</li>').appendTo(f),a.offline()&&i.addClass("offline"),i.click(__bind(function(a){return this.selectContact(a)},this)),g=a.name||a.jid.split("@")[0],i.attr("data-name",g),i.attr("data-group",c),$(".text",i).text(g),j={fill:"#fff",stroke:"#404040","stroke-width":.3,opacity:1,scale:.65},e=function(){switch(c){case"People":return ICONS.man;case"Services":return ICONS.magic;default:return ICONS.run}}(),k.push(new Button($(".icon",i),e,j));return k}.call(this));return n},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||e)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),$("#message-form").css("top","0px");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(),$("#message").focus(),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-form").css("top","10px"),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.showRoster=function(){var a,b,c,d,e,f,g;return a=$("#container"),b=$("#message-form"),f=$("#roster"),d=$("#roster-items"),e=$("#roster-form"),g=a.height()-b.position().top<a.height()/2,g?(f.css("top",""),f.css("bottom",b.outerHeight()+5+"px"),c=a.height()-b.outerHeight()-20):(f.css("bottom",""),f.css("top",b.position().top+b.outerHeight()+"px"),c=a.height()-b.position().top-30),d.css("max-height",c-e.outerHeight()-40+"px"),f.css("max-height",c+"px"),f.show()},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 this.showRoster(),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"></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").css("top","10px"),$("#message-form").submit(__bind(function(){return this.send()},this)),$("#messages").click(function(){return $("#roster").hide()}),$("#message").focus(function(){return $("#roster").hide()}),$(document).keyup(function(a){if(a.keyCode===27)return $("#roster").hide()}),this.roster(),$("#message-label").click(__bind(function(){var a;return a=$("#roster"),a.is(":visible")?a.hide():this.showRoster()},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(),$("#message").focus(),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;return a=$("#container"),e=$("#messages"),d=$("#message"),b=$("#message-form"),c=$("#message-label"),new Layout(function(){return d.width(b.width()-c.width()-32),e.css("max-height",a.height()-b.height())})},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=$("#syntax").val().trim(),$("#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(),$("#unix-users-error").empty(),b=!0,a=$("#name").val().trim(),a===""&&($("#name-error").text("Name is required."),b=!1),this.accounts().length===0&&($("#unix-users-error").text("At least one user account is required."),b=!1),b},f.prototype.accounts=function(){var a,b,c,d,e;a=$("#unix-users").val().split(","),e=[];for(c=0,d=a.length;c<d;c++)b=a[c],b.trim().length>0&&e.push(b.trim());return e},f.prototype.save=function(){var a,b;return this.validateForm()?(b=$("#users :checked").map(function(){return $(this).val()}).get(),a={name:$("#name").val(),code:$("#syntax").val(),accounts:this.accounts(),users:b},$("#id").val().length>0&&(a.id=$("#id").val()),this.api.save(c,a,__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):!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 <p id="unix-users-error" class="error"></p>\n <p class="hint">Comma separated user names like: apache, postgres, root, etc.</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("#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:"-20,-20",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:"-16,-16",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:"-16,-16",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
2
- ():this.drawSystemBlankSlate()},this))},this))},d.prototype.selectTask=function(a){this.selected=null,$("#setup li").removeClass("selected secondary"),$(a.currentTarget).addClass("selected secondary"),$("form.overlay").fadeOut(100,__bind(function(){return this.layout.resize()},this));switch($(a.currentTarget).attr("id")){case"users-nav":return $("#beta-header").text("Users"),$("#remove-user-form h2").text("Remove User"),$("#remove-user-msg").html("Select a user to delete."),$("#remove-user-form .buttons").hide(),this.drawUsers(),this.drawUserBlankSlate(),this.toggleBetaControls(this.api.user.permissions.users);case"systems-nav":return $("#beta-header").text("Systems"),$("#remove-user-form h2").text("Remove System"),$("#remove-user-msg").html("Select a system to delete."),$("#remove-user-form .buttons").hide(),this.drawUsers(),this.drawSystemBlankSlate(),this.toggleBetaControls(this.api.user.permissions.systems)}},d.prototype.toggleBetaControls=function(a){return a?$("#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,__bind(function(){a[0].reset(),this.layout.resize();if(b)return b()},this))},d.prototype.validateUser=function(){var a,b,c,d;$("#user-name-error").empty(),$("#password-error").empty(),d=!0,b=$("#password1").val().trim(),c=$("#password2").val().trim();if(this.selected)c.length>0&&c.length<8&&($("#password-error").text("Password must be at least 8 characters."),d=!1),this.session.bareJid()!==this.selected.jid&&b!==c&&($("#password-error").text("Passwords must match."),d=!1);else{a=$("#user-name").val().trim(),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,c,d;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)):(c=function(){var b,c,e,f;e=this.users,f=[];for(b=0,c=e.length;b<c;b++)d=e[b],d.jid===a.jid&&f.push(d);return f}.call(this)[0],c.name=this.userName(a),$(".text",b).text(this.userName(a)))},this)),!1):!1},d.prototype.validateSystem=function(){var a,b;return $("#user-name-error").empty(),b=!0,a=$("#user-name").val().trim(),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)):(this.selected.name=a.name,$(".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(),!1},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())})
@@ -1,28 +0,0 @@
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
- })();
@@ -1,424 +0,0 @@
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: '-20,-20',
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: '-16,-16',
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: '-16,-16',
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
- })();