vines 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +2 -2
- data/Rakefile +63 -8
- data/bin/vines +0 -1
- data/conf/config.rb +16 -7
- data/lib/vines.rb +21 -16
- data/lib/vines/command/init.rb +5 -3
- data/lib/vines/config.rb +34 -0
- data/lib/vines/contact.rb +14 -0
- data/lib/vines/stanza.rb +26 -0
- data/lib/vines/stanza/iq.rb +1 -1
- data/lib/vines/stanza/iq/disco_info.rb +3 -0
- data/lib/vines/stanza/iq/private_storage.rb +83 -0
- data/lib/vines/stanza/iq/roster.rb +26 -30
- data/lib/vines/stanza/presence.rb +0 -12
- data/lib/vines/stanza/presence/subscribe.rb +3 -20
- data/lib/vines/stanza/presence/subscribed.rb +9 -10
- data/lib/vines/stanza/presence/unsubscribe.rb +8 -15
- data/lib/vines/stanza/presence/unsubscribed.rb +8 -8
- data/lib/vines/storage.rb +28 -0
- data/lib/vines/storage/couchdb.rb +29 -0
- data/lib/vines/storage/local.rb +22 -0
- data/lib/vines/storage/redis.rb +26 -0
- data/lib/vines/storage/sql.rb +48 -5
- data/lib/vines/stream/client.rb +6 -8
- data/lib/vines/stream/http.rb +23 -21
- data/lib/vines/stream/http/auth.rb +1 -1
- data/lib/vines/stream/http/bind.rb +1 -1
- data/lib/vines/stream/http/bind_restart.rb +4 -3
- data/lib/vines/stream/http/ready.rb +1 -1
- data/lib/vines/stream/http/request.rb +94 -5
- data/lib/vines/stream/http/session.rb +8 -6
- data/lib/vines/version.rb +1 -1
- data/test/config_test.rb +12 -0
- data/test/contact_test.rb +40 -0
- data/test/rake_test_loader.rb +11 -3
- data/test/stanza/iq/private_storage_test.rb +177 -0
- data/test/stanza/iq/roster_test.rb +1 -1
- data/test/stanza/iq_test.rb +63 -0
- data/test/storage/couchdb_test.rb +7 -1
- data/test/storage/local_test.rb +8 -2
- data/test/storage/redis_test.rb +16 -7
- data/test/storage/sql_test.rb +8 -1
- data/test/storage/storage_tests.rb +50 -0
- data/test/stream/http/auth_test.rb +3 -0
- data/test/stream/http/ready_test.rb +3 -0
- data/test/stream/http/request_test.rb +86 -0
- data/test/stream/parser_test.rb +2 -0
- data/web/404.html +43 -0
- data/web/apple-touch-icon.png +0 -0
- data/web/chat/coffeescripts/chat.coffee +385 -0
- data/web/chat/coffeescripts/init.coffee +15 -0
- data/web/chat/coffeescripts/logout.coffee +5 -0
- data/web/chat/index.html +17 -0
- data/web/chat/javascripts/app.js +1 -0
- data/web/chat/javascripts/chat.js +436 -0
- data/web/chat/javascripts/init.js +21 -0
- data/web/chat/javascripts/logout.js +11 -0
- data/web/chat/stylesheets/chat.css +290 -0
- data/web/favicon.png +0 -0
- data/web/lib/coffeescripts/contact.coffee +32 -0
- data/web/lib/coffeescripts/layout.coffee +30 -0
- data/web/lib/coffeescripts/login.coffee +52 -0
- data/web/lib/coffeescripts/navbar.coffee +84 -0
- data/web/lib/coffeescripts/router.coffee +40 -0
- data/web/lib/coffeescripts/session.coffee +211 -0
- data/web/lib/images/default-user.png +0 -0
- data/web/lib/images/logo-large.png +0 -0
- data/web/lib/images/logo-small.png +0 -0
- data/web/lib/javascripts/base.js +9 -0
- data/web/lib/javascripts/contact.js +94 -0
- data/web/lib/javascripts/icons.js +101 -0
- data/web/lib/javascripts/jquery.cookie.js +91 -0
- data/web/lib/javascripts/jquery.js +18 -0
- data/web/lib/javascripts/layout.js +48 -0
- data/web/lib/javascripts/login.js +61 -0
- data/web/lib/javascripts/navbar.js +69 -0
- data/web/lib/javascripts/raphael.js +8 -0
- data/web/lib/javascripts/router.js +105 -0
- data/web/lib/javascripts/session.js +322 -0
- data/web/lib/javascripts/strophe.js +1 -0
- data/web/lib/stylesheets/base.css +223 -0
- data/web/lib/stylesheets/login.css +63 -0
- metadata +51 -9
@@ -0,0 +1,21 @@
|
|
1
|
+
$(function() {
|
2
|
+
var buttons, icon, label, nav, pages, session;
|
3
|
+
session = new Session();
|
4
|
+
nav = new NavBar(session);
|
5
|
+
nav.draw();
|
6
|
+
buttons = {
|
7
|
+
Messages: ICONS.chat,
|
8
|
+
Logout: ICONS.power
|
9
|
+
};
|
10
|
+
for (label in buttons) {
|
11
|
+
icon = buttons[label];
|
12
|
+
nav.addButton(label, icon);
|
13
|
+
}
|
14
|
+
pages = {
|
15
|
+
'/messages': new ChatPage(session),
|
16
|
+
'/logout': new LogoutPage(session),
|
17
|
+
'default': new LoginPage(session, '/messages/')
|
18
|
+
};
|
19
|
+
new Router(pages).draw();
|
20
|
+
return nav.select($('#nav-link-messages').parent());
|
21
|
+
});
|
@@ -0,0 +1,290 @@
|
|
1
|
+
#chat-page #container {
|
2
|
+
height: 100%;
|
3
|
+
}
|
4
|
+
#chat-page #alpha,
|
5
|
+
#chat-page #beta,
|
6
|
+
#chat-page #charlie {
|
7
|
+
height: 100%;
|
8
|
+
position: absolute;
|
9
|
+
}
|
10
|
+
#chat-page #alpha {
|
11
|
+
background: #f8f8f8;
|
12
|
+
-webkit-box-shadow: 0 0 40px rgba(0, 0, 0, 0.1) inset;
|
13
|
+
box-shadow: 0 0 40px rgba(0, 0, 0, 0.1) inset;
|
14
|
+
width: 260px;
|
15
|
+
}
|
16
|
+
#chat-page #alpha h2,
|
17
|
+
#chat-page #beta h2,
|
18
|
+
#chat-page #charlie h2 {
|
19
|
+
border-bottom: 1px solid #ddd;
|
20
|
+
font-size: 10pt;
|
21
|
+
padding-left: 10px;
|
22
|
+
position: relative;
|
23
|
+
text-shadow: 0 -1px 1px #fff;
|
24
|
+
}
|
25
|
+
#chat-page #beta {
|
26
|
+
-webkit-box-shadow: 0 0 5px rgba(0, 0, 0, 0.5), 0 0 40px rgba(0, 0, 0, 0.1) inset;
|
27
|
+
box-shadow: 0 0 5px rgba(0, 0, 0, 0.5), 0 0 40px rgba(0, 0, 0, 0.1) inset;
|
28
|
+
width: 460px;
|
29
|
+
left: 260px;
|
30
|
+
z-index: 1;
|
31
|
+
}
|
32
|
+
#chat-page #charlie {
|
33
|
+
background: #f8f8f8;
|
34
|
+
-webkit-box-shadow: 0 0 40px rgba(0, 0, 0, 0.1) inset;
|
35
|
+
box-shadow: 0 0 40px rgba(0, 0, 0, 0.1) inset;
|
36
|
+
width: 260px;
|
37
|
+
left: 720px;
|
38
|
+
}
|
39
|
+
#chat-page #chat-title {
|
40
|
+
background: #f8f8f8;
|
41
|
+
}
|
42
|
+
#chat-page #messages {
|
43
|
+
background: #fff;
|
44
|
+
height: 100%;
|
45
|
+
list-style: none;
|
46
|
+
overflow-y: auto;
|
47
|
+
text-shadow: 0 1px 1px #ddd;
|
48
|
+
width: 100%;
|
49
|
+
}
|
50
|
+
#chat-page #messages::-webkit-scrollbar,
|
51
|
+
#chat-page #roster::-webkit-scrollbar,
|
52
|
+
#chat-page #notifications::-webkit-scrollbar {
|
53
|
+
width: 6px;
|
54
|
+
}
|
55
|
+
#chat-page #messages::-webkit-scrollbar-thumb,
|
56
|
+
#chat-page #roster::-webkit-scrollbar-thumb,
|
57
|
+
#chat-page #notifications::-webkit-scrollbar-thumb {
|
58
|
+
border-radius: 10px;
|
59
|
+
}
|
60
|
+
#chat-page #messages::-webkit-scrollbar-thumb:vertical,
|
61
|
+
#chat-page #roster::-webkit-scrollbar-thumb:vertical,
|
62
|
+
#chat-page #notifications::-webkit-scrollbar-thumb:vertical {
|
63
|
+
background: rgba(0, 0, 0, .2);
|
64
|
+
}
|
65
|
+
#chat-page #messages li {
|
66
|
+
border-bottom: 1px solid #f0f0f0;
|
67
|
+
min-height: 40px;
|
68
|
+
padding: 10px;
|
69
|
+
position: relative;
|
70
|
+
}
|
71
|
+
#chat-page #messages li:hover > span .time {
|
72
|
+
opacity: 0.3;
|
73
|
+
}
|
74
|
+
#chat-page #messages li img {
|
75
|
+
border: 3px solid #fff;
|
76
|
+
-webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2), 0 0 40px rgba(0, 0, 0, 0.06) inset;
|
77
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2), 0 0 40px rgba(0, 0, 0, 0.06) inset;
|
78
|
+
position: absolute;
|
79
|
+
top: 7px;
|
80
|
+
right: 7px;
|
81
|
+
height: 40px;
|
82
|
+
width: 40px;
|
83
|
+
}
|
84
|
+
#chat-page #messages li p {
|
85
|
+
line-height: 1.5;
|
86
|
+
width: 90%;
|
87
|
+
}
|
88
|
+
#chat-page #messages li footer {
|
89
|
+
font-size: 9pt;
|
90
|
+
padding-right: 50px;
|
91
|
+
text-align: right;
|
92
|
+
}
|
93
|
+
#chat-page #messages li footer span {
|
94
|
+
color: #d8d8d8;
|
95
|
+
margin-right: 0.5em;
|
96
|
+
text-shadow: none;
|
97
|
+
}
|
98
|
+
#chat-page #messages li footer .author::before {
|
99
|
+
content: '\2014 ';
|
100
|
+
}
|
101
|
+
#chat-page #message-form {
|
102
|
+
background: #f8f8f8;
|
103
|
+
border-top: 1px solid #dfdfdf;
|
104
|
+
height: 50px;
|
105
|
+
position: absolute;
|
106
|
+
bottom: 0;
|
107
|
+
width: 100%;
|
108
|
+
}
|
109
|
+
#chat-page input[type="text"]:focus,
|
110
|
+
#chat-page input[type="email"]:focus {
|
111
|
+
-webkit-box-shadow: inset 1px 1px 2px rgba(0, 0, 0, 0.6);
|
112
|
+
box-shadow: inset 1px 1px 2px rgba(0, 0, 0, 0.6);
|
113
|
+
}
|
114
|
+
#chat-page #message {
|
115
|
+
display: block;
|
116
|
+
position: relative;
|
117
|
+
left: 10px;
|
118
|
+
top: 10px;
|
119
|
+
width: 428px;
|
120
|
+
}
|
121
|
+
#chat-page #roster,
|
122
|
+
#chat-page #notifications {
|
123
|
+
height: 100%;
|
124
|
+
list-style: none;
|
125
|
+
overflow-y: auto;
|
126
|
+
text-shadow: 0 1px 1px #fff;
|
127
|
+
width: 260px;
|
128
|
+
}
|
129
|
+
#chat-page #roster li,
|
130
|
+
#chat-page #notifications li {
|
131
|
+
cursor: pointer;
|
132
|
+
border-bottom: 1px solid #ddd;
|
133
|
+
font-weight: bold;
|
134
|
+
min-height: 42px;
|
135
|
+
padding: 0 10px;
|
136
|
+
position: relative;
|
137
|
+
-moz-transition: background 0.3s;
|
138
|
+
-o-transition: background 0.3s;
|
139
|
+
-webkit-transition: background 0.3s;
|
140
|
+
transition: background 0.3s;
|
141
|
+
}
|
142
|
+
#chat-page #notifications li {
|
143
|
+
font-weight: normal;
|
144
|
+
padding: 10px 0 0 0;
|
145
|
+
}
|
146
|
+
#chat-page #roster li:hover,
|
147
|
+
#chat-page #notifications li:hover {
|
148
|
+
background: rgba(255, 255, 255, 1.0);
|
149
|
+
}
|
150
|
+
#chat-page #roster li.offline > * {
|
151
|
+
opacity: 0.4;
|
152
|
+
}
|
153
|
+
#chat-page #roster li.selected > * {
|
154
|
+
opacity: 1.0;
|
155
|
+
}
|
156
|
+
#chat-page #roster li.selected {
|
157
|
+
background: #4693FF;
|
158
|
+
background: -moz-linear-gradient(#4693FF, #015de6);
|
159
|
+
background: -o-linear-gradient(#4693FF, #015de6);
|
160
|
+
background: -webkit-gradient(linear, left top, left bottom, from(#4693FF), to(#015de6));
|
161
|
+
border-bottom: 1px solid #fff;
|
162
|
+
color: #fff;
|
163
|
+
text-shadow: 0 -1px 1px #1b3a65;
|
164
|
+
}
|
165
|
+
#chat-page #roster li.selected .status-msg {
|
166
|
+
color: rgba(255, 255, 255, 0.85);
|
167
|
+
}
|
168
|
+
#chat-page #roster .status-msg {
|
169
|
+
display: block;
|
170
|
+
font-size: 11px;
|
171
|
+
font-weight: normal;
|
172
|
+
line-height: 11px;
|
173
|
+
}
|
174
|
+
#chat-page #roster .unread {
|
175
|
+
background: #4693FF;
|
176
|
+
background: -moz-linear-gradient(#4693FF, #015de6);
|
177
|
+
background: -o-linear-gradient(#4693FF, #015de6);
|
178
|
+
background: -webkit-gradient(linear, left top, left bottom, from(#4693FF), to(#015de6));
|
179
|
+
border-radius: 30px;
|
180
|
+
color: #fff;
|
181
|
+
display: inline-block;
|
182
|
+
font-size: 11px;
|
183
|
+
font-weight: normal;
|
184
|
+
line-height: 15px;
|
185
|
+
padding: 0px 6px;
|
186
|
+
position: absolute;
|
187
|
+
right: 50px;
|
188
|
+
top: 14px;
|
189
|
+
text-shadow: none;
|
190
|
+
}
|
191
|
+
#chat-page #roster .vcard-img {
|
192
|
+
background: #fff;
|
193
|
+
border: 1px solid #fff;
|
194
|
+
-webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2), 0 0 40px rgba(0, 0, 0, 0.06) inset;
|
195
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2), 0 0 40px rgba(0, 0, 0, 0.06) inset;
|
196
|
+
height: 32px;
|
197
|
+
width: 32px;
|
198
|
+
position: absolute;
|
199
|
+
top: 4px;
|
200
|
+
right: 10px;
|
201
|
+
}
|
202
|
+
#chat-page #roster-controls,
|
203
|
+
#chat-page #notification-controls {
|
204
|
+
background: rgba(255, 255, 255, 0.05);
|
205
|
+
border-top: 1px solid #ddd;
|
206
|
+
height: 50px;
|
207
|
+
position: absolute;
|
208
|
+
bottom: 0;
|
209
|
+
width: 260px;
|
210
|
+
}
|
211
|
+
#chat-page #notification-controls {
|
212
|
+
text-align: right;
|
213
|
+
}
|
214
|
+
#chat-page #roster-controls > div,
|
215
|
+
#chat-page #notification-controls > div {
|
216
|
+
cursor: pointer;
|
217
|
+
display: inline-block;
|
218
|
+
height: 27px;
|
219
|
+
margin: 0 10px;
|
220
|
+
position: relative;
|
221
|
+
top: 10px;
|
222
|
+
width: 27px;
|
223
|
+
}
|
224
|
+
#chat-page #roster-controls > div > svg,
|
225
|
+
#chat-page #notification-controls > div > svg {
|
226
|
+
height: 27px;
|
227
|
+
width: 27px;
|
228
|
+
}
|
229
|
+
#chat-page .contact-form {
|
230
|
+
background: inherit;
|
231
|
+
border-bottom: 1px solid #ddd;
|
232
|
+
border-top: 1px solid #fff;
|
233
|
+
-webkit-box-shadow: 0px -3px 5px rgba(0, 0, 0, 0.1);
|
234
|
+
box-shadow: 0px -3px 5px rgba(0, 0, 0, 0.1);
|
235
|
+
padding-top: 10px;
|
236
|
+
position: absolute;
|
237
|
+
bottom: 50px;
|
238
|
+
left: 0;
|
239
|
+
width: 260px;
|
240
|
+
}
|
241
|
+
#chat-page .contact-form h2,
|
242
|
+
#chat-page .notify-form h2 {
|
243
|
+
border: none !important;
|
244
|
+
line-height: 1;
|
245
|
+
margin-bottom: 10px;
|
246
|
+
}
|
247
|
+
#chat-page .contact-form p,
|
248
|
+
#chat-page .notify-form p {
|
249
|
+
line-height: 1.5;
|
250
|
+
margin: 0 10px 10px 10px;
|
251
|
+
text-shadow: 0 1px 1px #fff;
|
252
|
+
}
|
253
|
+
#chat-page .notify-form p {
|
254
|
+
margin-top: -5px;
|
255
|
+
}
|
256
|
+
#chat-page .contact-form .buttons,
|
257
|
+
#chat-page .notify-form .buttons {
|
258
|
+
padding-right: 10px;
|
259
|
+
text-align: right;
|
260
|
+
}
|
261
|
+
#chat-page .contact-form input[type="text"],
|
262
|
+
#chat-page .contact-form input[type="email"] {
|
263
|
+
margin-bottom: 10px;
|
264
|
+
width: 228px;
|
265
|
+
position: relative;
|
266
|
+
left: 10px;
|
267
|
+
}
|
268
|
+
#chat-page #edit-contact-jid {
|
269
|
+
color: #444;
|
270
|
+
margin-top: -5px;
|
271
|
+
}
|
272
|
+
#chat-page #search-roster {
|
273
|
+
cursor: pointer;
|
274
|
+
display: inline-block;
|
275
|
+
line-height: 1;
|
276
|
+
position: absolute;
|
277
|
+
right: 10px;
|
278
|
+
top: 6px;
|
279
|
+
}
|
280
|
+
#chat-page #search-roster svg {
|
281
|
+
height: 16px;
|
282
|
+
width: 16px;
|
283
|
+
}
|
284
|
+
#chat-page #search-roster-form {
|
285
|
+
border-bottom: 1px solid #ddd;
|
286
|
+
padding: 5px 10px;
|
287
|
+
}
|
288
|
+
#chat-page #search-roster-text {
|
289
|
+
width: 100%;
|
290
|
+
}
|
data/web/favicon.png
ADDED
Binary file
|
@@ -0,0 +1,32 @@
|
|
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'
|
@@ -0,0 +1,30 @@
|
|
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).each (ix, node) =>
|
14
|
+
node = $(node)
|
15
|
+
getter = node[get]
|
16
|
+
parent = getter.call node.parent()
|
17
|
+
fixed = this.fixed node, selector, (n) -> getter.call n
|
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()
|
@@ -0,0 +1,52 @@
|
|
1
|
+
class LoginPage
|
2
|
+
constructor: (@session, @startPage) ->
|
3
|
+
|
4
|
+
start: ->
|
5
|
+
$('#error').hide()
|
6
|
+
callback = (success) =>
|
7
|
+
unless success
|
8
|
+
@session.disconnect()
|
9
|
+
$('#error').show()
|
10
|
+
$('#password').val('').focus()
|
11
|
+
return
|
12
|
+
|
13
|
+
localStorage['jid'] = $('#jid').val()
|
14
|
+
$('#current-user-name').text @session.bareJid()
|
15
|
+
$('#current-user-avatar').attr 'src', @session.avatar(@session.jid())
|
16
|
+
$('#current-user-avatar').attr 'alt', @session.bareJid()
|
17
|
+
$('#container').fadeOut 200, =>
|
18
|
+
$('#navbar').show()
|
19
|
+
window.location.hash = @startPage
|
20
|
+
|
21
|
+
@session.connect $('#jid').val(), $('#password').val(), callback
|
22
|
+
false
|
23
|
+
|
24
|
+
draw: ->
|
25
|
+
@session.disconnect()
|
26
|
+
jid = localStorage['jid'] || ''
|
27
|
+
$('#navbar').hide()
|
28
|
+
$('body').attr 'id', 'login-page'
|
29
|
+
$('#container').hide().empty()
|
30
|
+
$("""
|
31
|
+
<form id="login-form">
|
32
|
+
<h1>vines></h1>
|
33
|
+
<fieldset id="login-form-controls">
|
34
|
+
<input id="jid" name="jid" type="email" maxlength="1024" value="#{jid}" placeholder="Your user name"/>
|
35
|
+
<input id="password" name="password" type="password" maxlength="1024" placeholder="Your password"/>
|
36
|
+
<input id="start" type="submit" value="Sign in"/>
|
37
|
+
</fieldset>
|
38
|
+
<p id="error" style="display:none;">User name and password not found.</p>
|
39
|
+
</form>
|
40
|
+
""").appendTo '#container'
|
41
|
+
$('#login-form').submit => this.start()
|
42
|
+
$('#container').fadeIn 1000
|
43
|
+
$('#jid').keydown -> $('#error').fadeOut()
|
44
|
+
$('#password').keydown -> $('#error').fadeOut()
|
45
|
+
this.resize()
|
46
|
+
|
47
|
+
resize: ->
|
48
|
+
win = $ window
|
49
|
+
form = $ '#login-form'
|
50
|
+
sizer = -> form.css 'top', win.height() / 2 - form.height() / 2
|
51
|
+
win.resize sizer
|
52
|
+
sizer()
|
@@ -0,0 +1,84 @@
|
|
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
|