vines 0.4.6 → 0.4.7
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +4 -4
- data/Rakefile +2 -36
- data/lib/vines/version.rb +1 -1
- data/vines.gemspec +0 -3
- data/web/404.html +11 -34
- metadata +3 -81
- data/web/chat/coffeescripts/chat.coffee +0 -362
- data/web/chat/coffeescripts/init.coffee +0 -15
- data/web/chat/index.html +0 -16
- data/web/chat/javascripts/app.js +0 -1
- data/web/chat/stylesheets/chat.css +0 -144
- data/web/lib/coffeescripts/button.coffee +0 -25
- data/web/lib/coffeescripts/contact.coffee +0 -32
- data/web/lib/coffeescripts/filter.coffee +0 -49
- data/web/lib/coffeescripts/layout.coffee +0 -30
- data/web/lib/coffeescripts/login.coffee +0 -68
- data/web/lib/coffeescripts/logout.coffee +0 -5
- data/web/lib/coffeescripts/navbar.coffee +0 -84
- data/web/lib/coffeescripts/notification.coffee +0 -14
- data/web/lib/coffeescripts/router.coffee +0 -40
- data/web/lib/coffeescripts/session.coffee +0 -229
- data/web/lib/coffeescripts/transfer.coffee +0 -106
- data/web/lib/images/dark-gray.png +0 -0
- data/web/lib/images/default-user.png +0 -0
- data/web/lib/images/light-gray.png +0 -0
- data/web/lib/images/logo-large.png +0 -0
- data/web/lib/images/logo-small.png +0 -0
- data/web/lib/images/white.png +0 -0
- data/web/lib/javascripts/base.js +0 -12
- data/web/lib/javascripts/icons.js +0 -110
- data/web/lib/javascripts/jquery.cookie.js +0 -91
- data/web/lib/javascripts/jquery.js +0 -4
- data/web/lib/javascripts/raphael.js +0 -6
- data/web/lib/javascripts/strophe.js +0 -1
- data/web/lib/stylesheets/base.css +0 -385
- data/web/lib/stylesheets/login.css +0 -68
@@ -1,15 +0,0 @@
|
|
1
|
-
$ ->
|
2
|
-
session = new Session()
|
3
|
-
nav = new NavBar(session)
|
4
|
-
nav.draw()
|
5
|
-
buttons =
|
6
|
-
Messages: ICONS.chat
|
7
|
-
Logout: ICONS.power
|
8
|
-
nav.addButton(label, icon) for label, icon of buttons
|
9
|
-
|
10
|
-
pages =
|
11
|
-
'/messages': new ChatPage(session)
|
12
|
-
'/logout': new LogoutPage(session)
|
13
|
-
'default': new LoginPage(session, '/messages/')
|
14
|
-
new Router(pages).draw()
|
15
|
-
nav.select $('#nav-link-messages').parent()
|
data/web/chat/index.html
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
<!DOCTYPE html>
|
2
|
-
<html>
|
3
|
-
<head>
|
4
|
-
<meta charset="utf-8"/>
|
5
|
-
<meta name="apple-mobile-web-app-capable" content="yes"/>
|
6
|
-
<title>Vines</title>
|
7
|
-
<link rel="shortcut icon" type="image/png" href="/favicon.png"/>
|
8
|
-
<link rel="stylesheet" href="/lib/stylesheets/base.css"/>
|
9
|
-
<link rel="stylesheet" href="/lib/stylesheets/login.css"/>
|
10
|
-
<link rel="stylesheet" href="stylesheets/chat.css"/>
|
11
|
-
<script type="text/javascript" src="/lib/javascripts/base.js"></script>
|
12
|
-
<script type="text/javascript" src="javascripts/app.js"></script>
|
13
|
-
</head>
|
14
|
-
<body>
|
15
|
-
</body>
|
16
|
-
</html>
|
data/web/chat/javascripts/app.js
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
(function(){this.ChatPage=function(){function e(e){var t=this;this.session=e,this.session.onRoster(function(){return t.roster()}),this.session.onCard(function(e){return t.card(e)}),this.session.onMessage(function(e){return t.message(e)}),this.session.onPresence(function(e){return t.presence(e)}),this.chats={},this.currentContact=null,this.layout=null}return e.prototype.datef=function(e){var t,n,r,i;return t=new Date(e),r=t.getHours()>=12?" pm":" am",n=t.getHours()>12?t.getHours()-12:t.getHours(),n===0&&(n=12),i=t.getMinutes()+"",i.length===1&&(i="0"+i),n+":"+i+r},e.prototype.card=function(e){var t=this;return this.eachContact(e.jid,function(n){return $(".vcard-img",n).attr("src",t.session.avatar(e.jid))})},e.prototype.roster=function(){var e,t,n,r,i,s,o,u,a=this;i=$("#roster"),$("li",i).each(function(e,t){var n;n=$(t).attr("data-jid");if(!a.session.roster[n])return $(t).remove()}),s=function(e,t){return $(".text",e).text(t.name||t.jid),e.attr("data-name",t.name||"")},o=this.session.roster,u=[];for(n in o)e=o[n],t=$("#roster li[data-jid='"+n+"']"),s(t,e),t.length===0?(r=$('<li data-jid="'+n+'" data-name="" class="offline">\n <span class="text"></span>\n <span class="status-msg">Offline</span>\n <span class="unread" style="display:none;"></span>\n <img class="vcard-img" alt="'+n+'" src="'+this.session.avatar(n)+'"/>\n</li>').appendTo(i),s(r,e),u.push(r.click(function(e){return a.selectContact(e)}))):u.push(void 0);return u},e.prototype.message=function(e){var t,n,r,i;if(e.type!=="chat"||!e.text)return;this.queueMessage(e),i=e.from===this.session.jid(),r=e.from.split("/")[0];if(!i&&r!==this.currentContact)return n=this.chat(e.from),n.unread++,this.eachContact(r,function(e){return $(".unread",e).text(n.unread).show()});t=this.atBottom(),this.appendMessage(e);if(t)return this.scroll()},e.prototype.eachContact=function(e,t){var n,r,i,s,o;s=$("#roster li[data-jid='"+e+"']").get(),o=[];for(r=0,i=s.length;r<i;r++)n=s[r],o.push(t($(n)));return o},e.prototype.appendMessage=function(e){var t,n,r,i;return n=e.from.split("/")[0],t=this.session.roster[n],r=t?t.name||n:n,e.from===this.session.jid()&&(r="Me"),i=$('<li data-jid="'+n+'" style="display:none;">\n <p></p>\n <img alt="'+n+'" src="'+this.session.avatar(n)+'"/>\n <footer>\n <span class="author"></span>\n <span class="time">'+this.datef(e.received)+"</span>\n </footer>\n</li>").appendTo("#messages"),$("p",i).text(e.text),$(".author",i).text(r),i.fadeIn(200)},e.prototype.queueMessage=function(e){var t,n,r;return r=e.from===this.session.jid(),n=e[r?"to":"from"],t=this.chat(n),t.jid=n,t.messages.push(e)},e.prototype.chat=function(e){var t,n;return t=e.split("/")[0],n=this.chats[t],n||(n={jid:e,messages:[],unread:0},this.chats[t]=n),n},e.prototype.presence=function(e){var t,n,r,i=this;n=e.from.split("/")[0];if(n===this.session.bareJid())return;if(!e.type||e.offline)t=this.session.roster[n],this.eachContact(n,function(e){return $(".status-msg",e).text(t.status()),t.offline()?e.addClass("offline"):e.removeClass("offline")});e.offline&&(this.chat(n).jid=n);if(e.type==="subscribe")return r=$('<li data-jid="'+e.from+'" style="display:none;">\n <form class="inset">\n <h2>Buddy Approval</h2>\n <p>'+e.from+' wants to add you as a buddy.</p>\n <fieldset class="buttons">\n <input type="button" value="Decline"/>\n <input type="submit" value="Accept"/>\n </fieldset>\n </form>\n</li>').appendTo("#notifications"),r.fadeIn(200),$("form",r).submit(function(){return i.acceptContact(r,e.from)}),$('input[type="button"]',r).click(function(){return i.rejectContact(r,e.from)})},e.prototype.acceptContact=function(e,t){return e.fadeOut(200,function(){return e.remove()}),this.session.sendSubscribed(t),this.session.sendSubscribe(t),!1},e.prototype.rejectContact=function(e,t){return e.fadeOut(200,function(){return e.remove()}),this.session.sendUnsubscribed(t)},e.prototype.selectContact=function(e){var t,n,r,i,s,o,u;r=$(e.currentTarget).attr("data-jid"),n=this.session.roster[r];if(this.currentContact===r)return;this.currentContact=r,$("#roster li").removeClass("selected"),$(e.currentTarget).addClass("selected"),$("#chat-title").text("Chat with "+(n.name||n.jid)),$("#messages").empty(),t=this.chats[r],i=[],t&&(i=t.messages,t.unread=0,this.eachContact(r,function(e){return $(".unread",e).text("").hide()}));for(o=0,u=i.length;o<u;o++)s=i[o],this.appendMessage(s);return this.scroll(),$("#remove-contact-msg").html("Are you sure you want to remove "+("<strong>"+this.currentContact+"</strong> from your buddy list?")),$("#remove-contact-form .buttons").fadeIn(200),$("#edit-contact-jid").text(this.currentContact),$("#edit-contact-name").val(this.session.roster[this.currentContact].name),$("#edit-contact-form input").fadeIn(200),$("#edit-contact-form .buttons").fadeIn(200)},e.prototype.scroll=function(){var e;return e=$("#messages"),e.animate({scrollTop:e.prop("scrollHeight")},400)},e.prototype.atBottom=function(){var e,t;return t=$("#messages"),e=t.prop("scrollHeight")-t.outerHeight(),t.scrollTop()>=e},e.prototype.send=function(){var e,t,n,r;return this.currentContact?(t=$("#message"),r=t.val().trim(),r&&(e=this.chats[this.currentContact],n=e?e.jid:this.currentContact,this.message({from:this.session.jid(),text:r,to:n,type:"chat",received:new Date}),this.session.sendMessage(n,r)),t.val(""),!1):!1},e.prototype.addContact=function(){var e;return this.toggleForm("#add-contact-form"),e={jid:$("#add-contact-jid").val(),name:$("#add-contact-name").val(),groups:["Buddies"]},e.jid&&this.session.updateContact(e,!0),!1},e.prototype.removeContact=function(){return this.toggleForm("#remove-contact-form"),this.session.removeContact(this.currentContact),this.currentContact=null,$("#chat-title").text("Select a buddy to chat"),$("#messages").empty(),$("#remove-contact-msg").html("Select a buddy in the list above to remove."),$("#remove-contact-form .buttons").hide(),$("#edit-contact-jid").text("Select a buddy in the list above to update."),$("#edit-contact-name").val(""),$("#edit-contact-form input").hide(),$("#edit-contact-form .buttons").hide(),!1},e.prototype.updateContact=function(){var e;return this.toggleForm("#edit-contact-form"),e={jid:this.currentContact,name:$("#edit-contact-name").val(),groups:this.session.roster[this.currentContact].groups},this.session.updateContact(e),!1},e.prototype.toggleForm=function(e,t){var n=this;return e=$(e),$("form.overlay").each(function(){if(this.id!==e.attr("id"))return $(this).hide()}),e.is(":hidden")?(t&&t(),e.fadeIn(100)):e.fadeOut(100,function(){e[0].reset(),n.layout.resize();if(t)return t()})},e.prototype.draw=function(){var e,t=this;if(!this.session.connected()){window.location.hash="";return}return $("body").attr("id","chat-page"),$("#container").hide().empty(),$('<div id="alpha" class="sidebar column y-fill">\n <h2>Buddies <div id="search-roster-icon"></div></h2>\n <div id="search-roster-form"></div>\n <ul id="roster" class="selectable scroll y-fill"></ul>\n <div id="alpha-controls" class="controls">\n <div id="add-contact"></div>\n <div id="remove-contact"></div>\n <div id="edit-contact"></div>\n </div>\n <form id="add-contact-form" class="overlay" style="display:none;">\n <h2>Add Buddy</h2>\n <input id="add-contact-jid" type="email" maxlength="1024" placeholder="Account name"/>\n <input id="add-contact-name" type="text" maxlength="1024" placeholder="Real name"/>\n <fieldset class="buttons">\n <input id="add-contact-cancel" type="button" value="Cancel"/>\n <input id="add-contact-ok" type="submit" value="Add"/>\n </fieldset>\n </form>\n <form id="remove-contact-form" class="overlay" style="display:none;">\n <h2>Remove Buddy</h2>\n <p id="remove-contact-msg">Select a buddy in the list above to remove.</p>\n <fieldset class="buttons" style="display:none;">\n <input id="remove-contact-cancel" type="button" value="Cancel"/>\n <input id="remove-contact-ok" type="submit" value="Remove"/>\n </fieldset>\n </form>\n <form id="edit-contact-form" class="overlay" style="display:none;">\n <h2>Update Profile</h2>\n <p id="edit-contact-jid">Select a buddy in the list above to update.</p>\n <input id="edit-contact-name" type="text" maxlength="1024" placeholder="Real name" style="display:none;"/>\n <fieldset class="buttons" style="display:none;">\n <input id="edit-contact-cancel" type="button" value="Cancel"/>\n <input id="edit-contact-ok" type="submit" value="Save"/>\n </fieldset>\n </form>\n</div>\n<div id="beta" class="primary column x-fill y-fill">\n <h2 id="chat-title">Select a buddy to chat</h2>\n <ul id="messages" class="scroll y-fill"></ul>\n <form id="message-form">\n <input id="message" name="message" type="text" maxlength="1024" placeholder="Type a message and press enter to send"/>\n </form>\n</div>\n<div id="charlie" class="sidebar column y-fill">\n <h2>Notifications</h2>\n <ul id="notifications" class="scroll y-fill"></ul>\n <div id="charlie-controls" class="controls">\n <div id="clear-notices"></div>\n </div>\n</div>').appendTo("#container"),this.roster(),new Button("#clear-notices",ICONS.no),new Button("#add-contact",ICONS.plus),new Button("#remove-contact",ICONS.minus),new Button("#edit-contact",ICONS.user),$("#message").focus(function(){return $("form.overlay").fadeOut()}),$("#message-form").submit(function(){return t.send()}),$("#clear-notices").click(function(){return $("#notifications li").fadeOut(200)}),$("#add-contact").click(function(){return t.toggleForm("#add-contact-form")}),$("#remove-contact").click(function(){return t.toggleForm("#remove-contact-form")}),$("#edit-contact").click(function(){return t.toggleForm("#edit-contact-form",function(){if(t.currentContact)return $("#edit-contact-jid").text(t.currentContact),$("#edit-contact-name").val(t.session.roster[t.currentContact].name)})}),$("#add-contact-cancel").click(function(){return t.toggleForm("#add-contact-form")}),$("#remove-contact-cancel").click(function(){return t.toggleForm("#remove-contact-form")}),$("#edit-contact-cancel").click(function(){return t.toggleForm("#edit-contact-form")}),$("#add-contact-form").submit(function(){return t.addContact()}),$("#remove-contact-form").submit(function(){return t.removeContact()}),$("#edit-contact-form").submit(function(){return t.updateContact()}),$("#container").fadeIn(200),this.layout=this.resize(),e=function(){return t.layout.resize(),t.layout.resize()},new Filter({list:"#roster",icon:"#search-roster-icon",form:"#search-roster-form",attrs:["data-jid","data-name"],open:e,close:e})},e.prototype.resize=function(){var e,t,n,r,i;return e=$("#alpha"),t=$("#beta"),n=$("#charlie"),i=$("#message"),r=$("#message-form"),new Layout(function(){return n.css("left",e.width()+t.width()),i.width(r.width()-32)})},e}(),$(function(){var e,t,n,r,i,s;s=new Session,r=new NavBar(s),r.draw(),e={Messages:ICONS.chat,Logout:ICONS.power};for(n in e)t=e[n],r.addButton(n,t);return i={"/messages":new ChatPage(s),"/logout":new LogoutPage(s),"default":new LoginPage(s,"/messages/")},(new Router(i)).draw(),r.select($("#nav-link-messages").parent())})}).call(this);
|
@@ -1,144 +0,0 @@
|
|
1
|
-
#chat-page #container {
|
2
|
-
height: 100%;
|
3
|
-
}
|
4
|
-
#chat-page #chat-title {
|
5
|
-
background: #f8f8f8;
|
6
|
-
}
|
7
|
-
#chat-page #messages {
|
8
|
-
background: #fff;
|
9
|
-
height: 100%;
|
10
|
-
list-style: none;
|
11
|
-
text-shadow: 0 1px 1px #ddd;
|
12
|
-
width: 100%;
|
13
|
-
}
|
14
|
-
#chat-page #messages li {
|
15
|
-
border-bottom: 1px solid #f0f0f0;
|
16
|
-
min-height: 40px;
|
17
|
-
padding: 10px;
|
18
|
-
position: relative;
|
19
|
-
}
|
20
|
-
#chat-page #messages li:hover > span .time {
|
21
|
-
opacity: 0.3;
|
22
|
-
}
|
23
|
-
#chat-page #messages li img {
|
24
|
-
border: 3px solid #fff;
|
25
|
-
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2), 0 0 40px rgba(0, 0, 0, 0.06) inset;
|
26
|
-
position: absolute;
|
27
|
-
top: 7px;
|
28
|
-
right: 7px;
|
29
|
-
height: 40px;
|
30
|
-
width: 40px;
|
31
|
-
}
|
32
|
-
#chat-page #messages li p {
|
33
|
-
line-height: 1.5;
|
34
|
-
width: 90%;
|
35
|
-
}
|
36
|
-
#chat-page #messages li footer {
|
37
|
-
font-size: 9pt;
|
38
|
-
padding-right: 50px;
|
39
|
-
text-align: right;
|
40
|
-
}
|
41
|
-
#chat-page #messages li footer span {
|
42
|
-
color: #d8d8d8;
|
43
|
-
margin-right: 0.5em;
|
44
|
-
text-shadow: none;
|
45
|
-
}
|
46
|
-
#chat-page #messages li footer .author::before {
|
47
|
-
content: '\2014 ';
|
48
|
-
}
|
49
|
-
#chat-page #message-form {
|
50
|
-
background: #f8f8f8 -moz-linear-gradient(rgba(255, 255, 255, 0.1), rgba(0, 0, 0, 0.05));
|
51
|
-
background: #f8f8f8 -ms-linear-gradient(rgba(255, 255, 255, 0.1), rgba(0, 0, 0, 0.05));
|
52
|
-
background: #f8f8f8 -o-linear-gradient(rgba(255, 255, 255, 0.1), rgba(0, 0, 0, 0.05));
|
53
|
-
background: #f8f8f8 -webkit-linear-gradient(rgba(255, 255, 255, 0.1), rgba(0, 0, 0, 0.05));
|
54
|
-
border-top: 1px solid #dfdfdf;
|
55
|
-
height: 50px;
|
56
|
-
position: absolute;
|
57
|
-
bottom: 0;
|
58
|
-
width: 100%;
|
59
|
-
}
|
60
|
-
#chat-page #message {
|
61
|
-
display: block;
|
62
|
-
position: relative;
|
63
|
-
left: 10px;
|
64
|
-
top: 10px;
|
65
|
-
width: 428px;
|
66
|
-
}
|
67
|
-
#chat-page #roster,
|
68
|
-
#chat-page #notifications {
|
69
|
-
height: 100%;
|
70
|
-
list-style: none;
|
71
|
-
text-shadow: 0 1px 1px #fff;
|
72
|
-
width: 260px;
|
73
|
-
}
|
74
|
-
#chat-page #roster li,
|
75
|
-
#chat-page #notifications li {
|
76
|
-
cursor: pointer;
|
77
|
-
border-bottom: 1px solid #ddd;
|
78
|
-
font-weight: bold;
|
79
|
-
min-height: 42px;
|
80
|
-
padding: 0 10px;
|
81
|
-
position: relative;
|
82
|
-
-moz-transition: background 0.3s;
|
83
|
-
-o-transition: background 0.3s;
|
84
|
-
-webkit-transition: background 0.3s;
|
85
|
-
transition: background 0.3s;
|
86
|
-
}
|
87
|
-
#chat-page #notifications li {
|
88
|
-
font-weight: normal;
|
89
|
-
padding: 10px 0 0 0;
|
90
|
-
}
|
91
|
-
#chat-page #roster li:hover:not(.selected),
|
92
|
-
#chat-page #notifications li:hover {
|
93
|
-
background: rgba(255, 255, 255, 1.0);
|
94
|
-
}
|
95
|
-
#chat-page #roster li.offline > * {
|
96
|
-
opacity: 0.4;
|
97
|
-
}
|
98
|
-
#chat-page #roster li.selected > * {
|
99
|
-
opacity: 1.0;
|
100
|
-
}
|
101
|
-
#chat-page #roster li.selected .status-msg {
|
102
|
-
color: rgba(255, 255, 255, 0.85);
|
103
|
-
}
|
104
|
-
#chat-page #roster .status-msg {
|
105
|
-
display: block;
|
106
|
-
font-size: 11px;
|
107
|
-
font-weight: normal;
|
108
|
-
line-height: 11px;
|
109
|
-
}
|
110
|
-
#chat-page #roster .unread {
|
111
|
-
background: #319be7;
|
112
|
-
background: -moz-linear-gradient(#319be7, #1b78d9);
|
113
|
-
background: -ms-linear-gradient(#319be7, #1b78d9);
|
114
|
-
background: -o-linear-gradient(#319be7, #1b78d9);
|
115
|
-
background: -webkit-linear-gradient(#319be7, #1b78d9);
|
116
|
-
border-radius: 30px;
|
117
|
-
color: #fff;
|
118
|
-
display: inline-block;
|
119
|
-
font-size: 11px;
|
120
|
-
font-weight: normal;
|
121
|
-
line-height: 15px;
|
122
|
-
padding: 0px 6px;
|
123
|
-
position: absolute;
|
124
|
-
right: 50px;
|
125
|
-
top: 14px;
|
126
|
-
text-shadow: none;
|
127
|
-
}
|
128
|
-
#chat-page #roster .vcard-img {
|
129
|
-
background: #fff;
|
130
|
-
border: 1px solid #fff;
|
131
|
-
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2), 0 0 40px rgba(0, 0, 0, 0.06) inset;
|
132
|
-
height: 32px;
|
133
|
-
width: 32px;
|
134
|
-
position: absolute;
|
135
|
-
top: 4px;
|
136
|
-
right: 10px;
|
137
|
-
}
|
138
|
-
#chat-page #charlie-controls {
|
139
|
-
text-align: right;
|
140
|
-
}
|
141
|
-
#chat-page #edit-contact-jid {
|
142
|
-
color: #444;
|
143
|
-
margin-top: -5px;
|
144
|
-
}
|
@@ -1,25 +0,0 @@
|
|
1
|
-
class @Button
|
2
|
-
constructor: (node, path, options) ->
|
3
|
-
@node = $ node
|
4
|
-
@path = path
|
5
|
-
@options = options || {}
|
6
|
-
@options.animate = true unless @options.animate?
|
7
|
-
this.draw()
|
8
|
-
|
9
|
-
draw: ->
|
10
|
-
paper = Raphael @node.get(0)
|
11
|
-
|
12
|
-
transform = "s#{@options.scale || 0.85}"
|
13
|
-
transform += ",t#{@options.translation}" if @options.translation
|
14
|
-
|
15
|
-
icon = paper.path(@path).attr
|
16
|
-
fill: @options.fill || '#000'
|
17
|
-
stroke: @options.stroke || '#fff'
|
18
|
-
'stroke-width': @options['stroke-width'] || 0.3
|
19
|
-
opacity: @options.opacity || 0.6
|
20
|
-
transform: transform
|
21
|
-
|
22
|
-
if @options.animate
|
23
|
-
@node.hover(
|
24
|
-
-> icon.animate(opacity: 1.0, 200),
|
25
|
-
-> icon.animate(opacity: 0.6, 200))
|
@@ -1,32 +0,0 @@
|
|
1
|
-
class @Contact
|
2
|
-
constructor: (node) ->
|
3
|
-
node = $(node)
|
4
|
-
@jid = node.attr 'jid'
|
5
|
-
@name = node.attr 'name'
|
6
|
-
@ask = node.attr 'ask'
|
7
|
-
@subscription = node.attr 'subscription'
|
8
|
-
@groups = $('group', node).map(-> $(this).text()).get()
|
9
|
-
@presence = []
|
10
|
-
|
11
|
-
online: ->
|
12
|
-
@presence.length > 0
|
13
|
-
|
14
|
-
offline: ->
|
15
|
-
@presence.length == 0
|
16
|
-
|
17
|
-
available: ->
|
18
|
-
this.online() && (p for p in @presence when !p.away).length > 0
|
19
|
-
|
20
|
-
away: -> !this.available()
|
21
|
-
|
22
|
-
status: ->
|
23
|
-
available = (p.status for p in @presence when p.status && !p.away)[0] || 'Available'
|
24
|
-
away = (p.status for p in @presence when p.status && p.away)[0] || 'Away'
|
25
|
-
if this.offline() then 'Offline'
|
26
|
-
else if this.away() then away
|
27
|
-
else available
|
28
|
-
|
29
|
-
update: (presence) ->
|
30
|
-
@presence = (p for p in @presence when p.from != presence.from)
|
31
|
-
@presence.push presence unless presence.type
|
32
|
-
@presence = [] if presence.type == 'unsubscribed'
|
@@ -1,49 +0,0 @@
|
|
1
|
-
class @Filter
|
2
|
-
constructor: (options) ->
|
3
|
-
@list = options.list
|
4
|
-
@icon = options.icon
|
5
|
-
@form = options.form
|
6
|
-
@attrs = options.attrs
|
7
|
-
@open = options.open
|
8
|
-
@close = options.close
|
9
|
-
this.draw()
|
10
|
-
|
11
|
-
draw: ->
|
12
|
-
$(@icon).addClass 'filter-button'
|
13
|
-
form = $('<form class="filter-form" style="display:none;"></form>').appendTo @form
|
14
|
-
text = $('<input class="filter-text" type="search" placeholder="Filter" results="5"/>').appendTo form
|
15
|
-
|
16
|
-
if @icon
|
17
|
-
new Button @icon, ICONS.search,
|
18
|
-
scale: 0.5
|
19
|
-
translation: '-16,-16'
|
20
|
-
|
21
|
-
form.submit -> false
|
22
|
-
text.keyup => this.filter(text)
|
23
|
-
text.change => this.filter(text)
|
24
|
-
text.click => this.filter(text)
|
25
|
-
$(@icon).click =>
|
26
|
-
if form.is ':hidden'
|
27
|
-
this.filter(text)
|
28
|
-
form.show()
|
29
|
-
this.open() if this.open
|
30
|
-
else
|
31
|
-
form.hide()
|
32
|
-
form[0].reset()
|
33
|
-
this.filter(text)
|
34
|
-
this.close() if this.close
|
35
|
-
|
36
|
-
filter: (input) ->
|
37
|
-
text = input.val().toLowerCase()
|
38
|
-
if text == ''
|
39
|
-
$('li', @list).show()
|
40
|
-
return
|
41
|
-
|
42
|
-
test = (node, attr) ->
|
43
|
-
val = (node.attr(attr) || '').toLowerCase()
|
44
|
-
val.indexOf(text) != -1
|
45
|
-
|
46
|
-
$('> li', @list).each (ix, node) =>
|
47
|
-
node = $ node
|
48
|
-
matches = (true for attr in @attrs when test node, attr)
|
49
|
-
if matches.length > 0 then node.show() else node.hide()
|
@@ -1,30 +0,0 @@
|
|
1
|
-
class @Layout
|
2
|
-
constructor: (@fn) ->
|
3
|
-
this.resize()
|
4
|
-
this.listen()
|
5
|
-
setTimeout (=> this.resize()), 250
|
6
|
-
|
7
|
-
resize: ->
|
8
|
-
this.fill '.x-fill', 'outerWidth', 'width'
|
9
|
-
this.fill '.y-fill', 'outerHeight', 'height'
|
10
|
-
this.fn()
|
11
|
-
|
12
|
-
fill: (selector, get, set) ->
|
13
|
-
$(selector).filter(':visible').each (ix, node) =>
|
14
|
-
node = $(node)
|
15
|
-
getter = node[get]
|
16
|
-
parent = getter.call node.parent(), true
|
17
|
-
fixed = this.fixed node, selector, (n) -> getter.call(n, true)
|
18
|
-
node[set].call node, parent - fixed
|
19
|
-
|
20
|
-
fixed: (node, selector, fn) ->
|
21
|
-
node.siblings().not(selector).not('.float').filter(':visible')
|
22
|
-
.map(-> fn $ this).get()
|
23
|
-
.reduce ((sum, num) -> sum + num), 0
|
24
|
-
|
25
|
-
listen: ->
|
26
|
-
id = null
|
27
|
-
$(window).resize =>
|
28
|
-
clearTimeout id
|
29
|
-
id = setTimeout (=> this.resize()), 10
|
30
|
-
this.resize()
|
@@ -1,68 +0,0 @@
|
|
1
|
-
class @LoginPage
|
2
|
-
constructor: (@session, @startPage) ->
|
3
|
-
|
4
|
-
start: ->
|
5
|
-
$('#error').hide()
|
6
|
-
|
7
|
-
[jid, password] = ($(id).val().trim() for id in ['#jid', '#password'])
|
8
|
-
if jid.length == 0 || password.length == 0 || jid.indexOf('@') == -1
|
9
|
-
$('#error').show()
|
10
|
-
return
|
11
|
-
|
12
|
-
@session.connect jid, password, (success) =>
|
13
|
-
unless success
|
14
|
-
@session.disconnect()
|
15
|
-
$('#error').show()
|
16
|
-
$('#password').val('').focus()
|
17
|
-
return
|
18
|
-
|
19
|
-
localStorage['jid'] = jid
|
20
|
-
$('#current-user-name').text @session.bareJid()
|
21
|
-
$('#current-user-avatar').attr 'src', @session.avatar @session.jid()
|
22
|
-
$('#current-user-avatar').attr 'alt', @session.bareJid()
|
23
|
-
$('#container').fadeOut 200, =>
|
24
|
-
$('#navbar').show()
|
25
|
-
window.location.hash = @startPage
|
26
|
-
|
27
|
-
draw: ->
|
28
|
-
@session.disconnect()
|
29
|
-
jid = localStorage['jid'] || ''
|
30
|
-
$('#navbar').hide()
|
31
|
-
$('body').attr 'id', 'login-page'
|
32
|
-
$('#container').hide().empty()
|
33
|
-
$("""
|
34
|
-
<form id="login-form">
|
35
|
-
<div id="icon"></div>
|
36
|
-
<h1>vines</h1>
|
37
|
-
<fieldset id="login-form-controls">
|
38
|
-
<input id="jid" name="jid" type="email" maxlength="1024" value="#{jid}" placeholder="Your user name"/>
|
39
|
-
<input id="password" name="password" type="password" maxlength="1024" placeholder="Your password"/>
|
40
|
-
<input id="start" type="submit" value="Sign in"/>
|
41
|
-
</fieldset>
|
42
|
-
<p id="error" style="display:none;">User name and password not found.</p>
|
43
|
-
</form>
|
44
|
-
""").appendTo '#container'
|
45
|
-
$('#container').fadeIn 1000
|
46
|
-
$('#login-form').submit => this.start(); false
|
47
|
-
$('#jid').keydown -> $('#error').fadeOut()
|
48
|
-
$('#password').keydown -> $('#error').fadeOut()
|
49
|
-
this.resize()
|
50
|
-
this.icon()
|
51
|
-
|
52
|
-
icon: ->
|
53
|
-
opts =
|
54
|
-
fill: '90-#ccc-#fff'
|
55
|
-
stroke: '#fff'
|
56
|
-
'stroke-width': 1.1
|
57
|
-
opacity: 0.95
|
58
|
-
scale: 3.0
|
59
|
-
translation: '10,8'
|
60
|
-
animate: false
|
61
|
-
new Button('#icon', ICONS.chat, opts)
|
62
|
-
|
63
|
-
resize: ->
|
64
|
-
win = $ window
|
65
|
-
form = $ '#login-form'
|
66
|
-
sizer = -> form.css 'top', win.height() / 2 - form.height() / 2
|
67
|
-
win.resize sizer
|
68
|
-
sizer()
|
@@ -1,84 +0,0 @@
|
|
1
|
-
class @NavBar
|
2
|
-
constructor: (@session) ->
|
3
|
-
@session.onCard (card) =>
|
4
|
-
if card.jid == @session.bareJid()
|
5
|
-
$('#current-user-avatar').attr 'src', @session.avatar card.jid
|
6
|
-
|
7
|
-
draw: ->
|
8
|
-
$("""
|
9
|
-
<header id="navbar" class="x-fill">
|
10
|
-
<h1 id="logo">vines></h1>
|
11
|
-
<div id="current-user">
|
12
|
-
<img id="current-user-avatar" alt="#{@session.bareJid()}" src="#{@session.avatar(@session.jid())}"/>
|
13
|
-
<div id="current-user-info">
|
14
|
-
<h1 id="current-user-name">#{@session.bareJid()}</h1>
|
15
|
-
<form id="current-user-presence-form">
|
16
|
-
<span class="select">
|
17
|
-
<span class="text">Available</span>
|
18
|
-
<select id="current-user-presence">
|
19
|
-
<optgroup label="Available">
|
20
|
-
<option>Available</option>
|
21
|
-
<option>Surfing the web</option>
|
22
|
-
<option>Reading email</option>
|
23
|
-
</optgroup>
|
24
|
-
<optgroup label="Away">
|
25
|
-
<option value="xa">Away</option>
|
26
|
-
<option value="xa">Out to lunch</option>
|
27
|
-
<option value="xa">On the phone</option>
|
28
|
-
<option value="xa">In a meeting</option>
|
29
|
-
</optgroup>
|
30
|
-
</select>
|
31
|
-
</span>
|
32
|
-
</form>
|
33
|
-
</div>
|
34
|
-
</div>
|
35
|
-
<nav id="app-nav" class="x-fill">
|
36
|
-
<ul id="nav-links"></ul>
|
37
|
-
</nav>
|
38
|
-
</header>
|
39
|
-
""").appendTo 'body'
|
40
|
-
$('<div id="container" class="x-fill y-fill"></div>').appendTo 'body'
|
41
|
-
|
42
|
-
$('#current-user-presence').change (event) =>
|
43
|
-
selected = $ 'option:selected', event.currentTarget
|
44
|
-
$('#current-user-presence-form .text').text selected.text()
|
45
|
-
@session.sendPresence selected.val() == 'xa', selected.text()
|
46
|
-
|
47
|
-
addButton: (label, icon) ->
|
48
|
-
id = "nav-link-#{label.toLowerCase()}"
|
49
|
-
node = $("""
|
50
|
-
<li>
|
51
|
-
<a id="#{id}" href="#/#{label.toLowerCase()}">
|
52
|
-
<span>#{label}</span>
|
53
|
-
</a>
|
54
|
-
</li>
|
55
|
-
""").appendTo '#nav-links'
|
56
|
-
this.button(id, icon)
|
57
|
-
node.click (event) => this.select(event.currentTarget)
|
58
|
-
|
59
|
-
select: (button) ->
|
60
|
-
button = $(button)
|
61
|
-
$('#nav-links li').removeClass('selected')
|
62
|
-
$('#nav-links li a').removeClass('selected')
|
63
|
-
button.addClass('selected')
|
64
|
-
$('a', button).addClass('selected')
|
65
|
-
dark = $('#nav-links svg path')
|
66
|
-
dark.attr 'opacity', '0.6'
|
67
|
-
dark.css 'opacity', '0.6'
|
68
|
-
light = $('svg path', button)
|
69
|
-
light.attr 'opacity', '1.0'
|
70
|
-
light.css 'opacity', '1.0'
|
71
|
-
|
72
|
-
button: (id, path) ->
|
73
|
-
paper = Raphael(id)
|
74
|
-
icon = paper.path(path).attr
|
75
|
-
fill: '#fff'
|
76
|
-
stroke: '#000'
|
77
|
-
'stroke-width': 0.3
|
78
|
-
opacity: 0.6
|
79
|
-
|
80
|
-
node = $('#' + id)
|
81
|
-
node.hover(
|
82
|
-
-> icon.animate(opacity: 1.0, 200),
|
83
|
-
-> icon.animate(opacity: 0.6, 200) unless node.hasClass('selected'))
|
84
|
-
node.get 0
|