vines 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +5 -0
- data/lib/vines/config.rb +1 -1
- data/lib/vines/stream/http.rb +3 -3
- data/lib/vines/version.rb +1 -1
- data/web/chat/coffeescripts/chat.coffee +34 -61
- data/web/chat/javascripts/app.js +1 -1
- data/web/chat/javascripts/chat.js +22 -74
- data/web/chat/stylesheets/chat.css +2 -145
- data/web/lib/coffeescripts/button.coffee +21 -0
- data/web/lib/coffeescripts/filter.coffee +48 -0
- data/web/lib/coffeescripts/session.coffee +63 -48
- data/web/lib/coffeescripts/transfer.coffee +103 -0
- data/web/lib/javascripts/base.js +2 -1
- data/web/lib/javascripts/button.js +31 -0
- data/web/lib/javascripts/filter.js +86 -0
- data/web/lib/javascripts/session.js +43 -77
- data/web/lib/javascripts/transfer.js +134 -0
- data/web/lib/stylesheets/base.css +129 -5
- metadata +8 -2
data/README
CHANGED
@@ -6,6 +6,11 @@ CouchDB, Redis, the file system, or a custom storage implementation that you pro
|
|
6
6
|
LDAP authentication can be used so user names and passwords aren't stored in the chat
|
7
7
|
database. SSL encryption is mandatory on all client and server connections.
|
8
8
|
|
9
|
+
The Vines XMPP server includes a web chat client. The web application is available
|
10
|
+
immediately after starting the chat server at http://localhost:5280/chat/
|
11
|
+
|
12
|
+
Additional documentation can be found at www.getvines.com.
|
13
|
+
|
9
14
|
== Usage
|
10
15
|
|
11
16
|
1. gem install vines
|
data/lib/vines/config.rb
CHANGED
@@ -5,7 +5,7 @@ module Vines
|
|
5
5
|
# A Config object is passed to the stream handlers to give them access
|
6
6
|
# to server configuration information like virtual host names, storage
|
7
7
|
# systems, etc. This class provides the DSL methods used in the
|
8
|
-
# config
|
8
|
+
# conf/config.rb file.
|
9
9
|
class Config
|
10
10
|
LOG_LEVELS = %w[debug info warn error fatal].freeze
|
11
11
|
|
data/lib/vines/stream/http.rb
CHANGED
@@ -43,11 +43,11 @@ module Vines
|
|
43
43
|
if request.path == self.bind
|
44
44
|
body = Nokogiri::XML(request.body).root
|
45
45
|
if session = Sessions[body['sid']]
|
46
|
-
session
|
46
|
+
@session = session
|
47
47
|
else
|
48
48
|
@session = Http::Session.new(self)
|
49
|
-
@session.request(request)
|
50
49
|
end
|
50
|
+
@session.request(request)
|
51
51
|
@nodes.push(body)
|
52
52
|
else
|
53
53
|
request.reply_with_file(self.root)
|
@@ -152,4 +152,4 @@ module Vines
|
|
152
152
|
end
|
153
153
|
end
|
154
154
|
end
|
155
|
-
end
|
155
|
+
end
|
data/lib/vines/version.rb
CHANGED
@@ -118,7 +118,7 @@ class ChatPage
|
|
118
118
|
if presence.type == 'subscribe'
|
119
119
|
node = $("""
|
120
120
|
<li data-jid="#{presence.from}" style="display:none;">
|
121
|
-
<form class="
|
121
|
+
<form class="inset">
|
122
122
|
<h2>Buddy Approval</h2>
|
123
123
|
<p>#{presence.from} wants to add you as a buddy.</p>
|
124
124
|
<fieldset class="buttons">
|
@@ -235,7 +235,7 @@ class ChatPage
|
|
235
235
|
|
236
236
|
toggleForm: (form, fn) ->
|
237
237
|
form = $(form)
|
238
|
-
$('.
|
238
|
+
$('form.overlay').each ->
|
239
239
|
$(this).hide() unless this.id == form.attr 'id'
|
240
240
|
if form.is ':hidden'
|
241
241
|
fn() if fn
|
@@ -245,19 +245,6 @@ class ChatPage
|
|
245
245
|
form[0].reset()
|
246
246
|
fn() if fn
|
247
247
|
|
248
|
-
filterRoster: ->
|
249
|
-
text = $('#search-roster-text').val().toLowerCase()
|
250
|
-
if text == ''
|
251
|
-
$('#roster li').show()
|
252
|
-
return
|
253
|
-
|
254
|
-
$('#roster li').each ->
|
255
|
-
node = $(this)
|
256
|
-
jid = (node.attr('data-jid') || '').toLowerCase()
|
257
|
-
name = (node.attr('data-name') || '').toLowerCase()
|
258
|
-
match = jid.indexOf(text) != -1 || name.indexOf(text) != -1
|
259
|
-
if match then node.show() else node.hide()
|
260
|
-
|
261
248
|
draw: ->
|
262
249
|
unless @session.connected()
|
263
250
|
window.location.hash = ''
|
@@ -266,18 +253,16 @@ class ChatPage
|
|
266
253
|
$('body').attr 'id', 'chat-page'
|
267
254
|
$('#container').hide().empty()
|
268
255
|
$("""
|
269
|
-
<div id="alpha" class="y-fill">
|
270
|
-
<h2>Buddies <div id="search-roster"></div></h2>
|
271
|
-
<
|
272
|
-
|
273
|
-
|
274
|
-
<ul id="roster" class="y-fill"></ul>
|
275
|
-
<div id="roster-controls">
|
256
|
+
<div id="alpha" class="sidebar column y-fill">
|
257
|
+
<h2>Buddies <div id="search-roster-icon"></div></h2>
|
258
|
+
<div id="search-roster-form"></div>
|
259
|
+
<ul id="roster" class="selectable scroll y-fill"></ul>
|
260
|
+
<div id="alpha-controls" class="controls">
|
276
261
|
<div id="add-contact"></div>
|
277
262
|
<div id="remove-contact"></div>
|
278
263
|
<div id="edit-contact"></div>
|
279
264
|
</div>
|
280
|
-
<form id="add-contact-form" class="
|
265
|
+
<form id="add-contact-form" class="overlay" style="display:none;">
|
281
266
|
<h2>Add Buddy</h2>
|
282
267
|
<input id="add-contact-jid" type="email" maxlength="1024" placeholder="Account name"/>
|
283
268
|
<input id="add-contact-name" type="text" maxlength="1024" placeholder="Real name"/>
|
@@ -286,7 +271,7 @@ class ChatPage
|
|
286
271
|
<input id="add-contact-ok" type="submit" value="Add"/>
|
287
272
|
</fieldset>
|
288
273
|
</form>
|
289
|
-
<form id="remove-contact-form" class="
|
274
|
+
<form id="remove-contact-form" class="overlay" style="display:none;">
|
290
275
|
<h2>Remove Buddy</h2>
|
291
276
|
<p id="remove-contact-msg">Select a buddy in the list above to remove.</p>
|
292
277
|
<fieldset class="buttons" style="display:none;">
|
@@ -294,7 +279,7 @@ class ChatPage
|
|
294
279
|
<input id="remove-contact-ok" type="submit" value="Remove"/>
|
295
280
|
</fieldset>
|
296
281
|
</form>
|
297
|
-
<form id="edit-contact-form" class="
|
282
|
+
<form id="edit-contact-form" class="overlay" style="display:none;">
|
298
283
|
<h2>Update Profile</h2>
|
299
284
|
<p id="edit-contact-jid">Select a buddy in the list above to update.</p>
|
300
285
|
<input id="edit-contact-name" type="text" maxlength="1024" placeholder="Real name" style="display:none;"/>
|
@@ -304,30 +289,30 @@ class ChatPage
|
|
304
289
|
</fieldset>
|
305
290
|
</form>
|
306
291
|
</div>
|
307
|
-
<div id="beta" class="x-fill y-fill">
|
292
|
+
<div id="beta" class="primary column x-fill y-fill">
|
308
293
|
<h2 id="chat-title">Select a buddy to chat</h2>
|
309
|
-
<ul id="messages" class="y-fill"></ul>
|
294
|
+
<ul id="messages" class="scroll y-fill"></ul>
|
310
295
|
<form id="message-form">
|
311
296
|
<input id="message" name="message" type="text" maxlength="1024" placeholder="Type a message and press enter to send"/>
|
312
297
|
</form>
|
313
298
|
</div>
|
314
|
-
<div id="charlie" class="y-fill">
|
299
|
+
<div id="charlie" class="sidebar column y-fill">
|
315
300
|
<h2>Notifications</h2>
|
316
|
-
<ul id="notifications" class="y-fill"></ul>
|
317
|
-
<div id="
|
301
|
+
<ul id="notifications" class="scroll y-fill"></ul>
|
302
|
+
<div id="charlie-controls" class="controls">
|
318
303
|
<div id="clear-notices"></div>
|
319
304
|
</div>
|
320
305
|
</div>
|
321
306
|
""").appendTo '#container'
|
322
307
|
|
323
308
|
this.roster()
|
324
|
-
this.button 'clear-notices', ICONS.no
|
325
|
-
this.button 'add-contact', ICONS.plus
|
326
|
-
this.button 'remove-contact', ICONS.minus
|
327
|
-
this.button 'edit-contact', ICONS.user
|
328
|
-
this.button 'search-roster', ICONS.search, scale: 0.5, translation: '-8 -8'
|
329
309
|
|
330
|
-
|
310
|
+
new Button '#clear-notices', ICONS.no
|
311
|
+
new Button '#add-contact', ICONS.plus
|
312
|
+
new Button '#remove-contact', ICONS.minus
|
313
|
+
new Button '#edit-contact', ICONS.user
|
314
|
+
|
315
|
+
$('#message').focus -> $('form.overlay').fadeOut()
|
331
316
|
$('#message-form').submit => this.send()
|
332
317
|
|
333
318
|
$('#clear-notices').click -> $('#notifications li').fadeOut 200
|
@@ -346,16 +331,21 @@ class ChatPage
|
|
346
331
|
$('#add-contact-form').submit => this.addContact()
|
347
332
|
$('#remove-contact-form').submit => this.removeContact()
|
348
333
|
$('#edit-contact-form').submit => this.updateContact()
|
349
|
-
$('#search-roster-form').submit -> false
|
350
|
-
|
351
|
-
$('#search-roster-text').keyup => this.filterRoster()
|
352
|
-
$('#search-roster-text').change => this.filterRoster()
|
353
|
-
$('#search-roster-text').click => this.filterRoster()
|
354
|
-
$('#search-roster').click =>
|
355
|
-
this.toggleForm '#search-roster-form', => this.filterRoster()
|
356
334
|
|
357
335
|
$('#container').fadeIn 200
|
358
|
-
this.resize()
|
336
|
+
layout = this.resize()
|
337
|
+
|
338
|
+
fn = ->
|
339
|
+
layout.resize()
|
340
|
+
layout.resize() # not sure why two are needed
|
341
|
+
|
342
|
+
new Filter
|
343
|
+
list: '#roster'
|
344
|
+
icon: '#search-roster-icon'
|
345
|
+
form: '#search-roster-form'
|
346
|
+
attrs: ['data-jid', 'data-name']
|
347
|
+
open: fn
|
348
|
+
close: fn
|
359
349
|
|
360
350
|
resize: ->
|
361
351
|
a = $ '#alpha'
|
@@ -366,20 +356,3 @@ class ChatPage
|
|
366
356
|
new Layout ->
|
367
357
|
c.css 'left', a.width() + b.width()
|
368
358
|
msg.width form.width() - 32
|
369
|
-
|
370
|
-
button: (id, path, options) ->
|
371
|
-
options ||= {}
|
372
|
-
paper = Raphael(id)
|
373
|
-
icon = paper.path(path).attr
|
374
|
-
fill: '#000'
|
375
|
-
stroke: '#fff'
|
376
|
-
'stroke-width': 0.3
|
377
|
-
opacity: 0.6
|
378
|
-
scale: options.scale || 0.85
|
379
|
-
translation: options.translation || ''
|
380
|
-
|
381
|
-
node = $('#' + id)
|
382
|
-
node.hover(
|
383
|
-
-> icon.animate(opacity: 1.0, 200),
|
384
|
-
-> icon.animate(opacity: 0.6, 200))
|
385
|
-
node.get 0
|
data/web/chat/javascripts/app.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
var ChatPage,__bind=function(a,b){return function(){return a.apply(b,arguments)}};ChatPage=function(){function a(a){this.session=a,this.session.onRoster(__bind(function(){return this.roster()},this)),this.session.onCard(__bind(function(a){return this.card(a)},this)),this.session.onMessage(__bind(function(a){return this.message(a)},this)),this.session.onPresence(__bind(function(a){return this.presence(a)},this)),this.chats={},this.currentContact=null}a.prototype.datef=function(a){var b,c,d,e;b=new Date(a),d=b.getHours()>=12?" pm":" am",c=b.getHours()>12?b.getHours()-12:b.getHours(),c===0&&(c=12),e=b.getMinutes()+"",e.length===1&&(e="0"+e);return c+":"+e+d},a.prototype.card=function(a){return this.eachContact(a.jid,__bind(function(b){return $(".vcard-img",b).attr("src",this.session.avatar(a.jid))},this))},a.prototype.roster=function(){var a,b,c,d,e,f,g,h;e=$("#roster"),$("li",e).each(__bind(function(a,b){var c;c=$(b).attr("data-jid");if(!this.session.roster[c])return $(b).remove()},this)),f=function(a,b){$(".text",a).text(b.name||b.jid);return a.attr("data-name",b.name||"")},g=this.session.roster,h=[];for(c in g)a=g[c],b=$("#roster li[data-jid='"+c+"']"),f(b,a),h.push(b.length===0?(d=$('<li data-jid="'+c+'" 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="'+c+'" src="'+this.session.avatar(c)+'"/>\n</li>').appendTo(e),f(d,a),d.click(__bind(function(a){return this.selectContact(a)},this))):void 0);return h},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){c=this.chat(a.from),c.unread++;return this.eachContact(d,function(a){return $(".unread",a).text(c.unread).show()})}b=this.atBottom(),this.appendMessage(a);if(b)return this.scroll()},a.prototype.eachContact=function(a,b){var c,d,e,f,g;f=$("#roster 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;c=a.from.split("/")[0],b=this.session.roster[c],d=b?b.name||c:c,a.from===this.session.jid()&&(d="Me"),e=$('<li data-jid="'+c+'" style="display:none;">\n <p></p>\n <img alt="'+c+'" src="'+this.session.avatar(c)+'"/>\n <footer>\n <span class="author"></span>\n <span class="time">'+this.datef(a.received)+"</span>\n </footer>\n</li>").appendTo("#messages"),$("p",e).text(a.text),$(".author",e).text(d);return e.fadeIn(200)},a.prototype.queueMessage=function(a){var b,c,d;d=a.from===this.session.jid(),c=a[d?"to":"from"],b=this.chat(c),b.jid=c;return b.messages.push(a)},a.prototype.chat=function(a){var b,c;b=a.split("/")[0],c=this.chats[b],c||(c={jid:a,messages:[],unread:0},this.chats[b]=c);return c},a.prototype.presence=function(a){var b,c,d;c=a.from.split("/")[0];if(c!==this.session.bareJid()){if(!a.type||a.offline)b=this.session.roster[c],this.eachContact(c,function(a){$(".status-msg",a).text(b.status());return b.offline()?a.addClass("offline"):a.removeClass("offline")});a.offline&&(this.chat(c).jid=c);if(a.type==="subscribe"){d=$('<li data-jid="'+a.from+'" style="display:none;">\n <form class="notify-form">\n <h2>Buddy Approval</h2>\n <p>'+a.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"),d.fadeIn(200),$("form",d).submit(__bind(function(){return this.acceptContact(d,a.from)},this));return $('input[type="button"]',d).click(__bind(function(){return this.rejectContact(d,a.from)},this))}}},a.prototype.acceptContact=function(a,b){a.fadeOut(200,function(){return a.remove()}),this.session.sendSubscribed(b),this.session.sendSubscribe(b);return!1},a.prototype.rejectContact=function(a,b){a.fadeOut(200,function(){return a.remove()});return this.session.sendUnsubscribed(b)},a.prototype.selectContact=function(a){var b,c,d,e,f,g,h;d=$(a.currentTarget).attr("data-jid"),c=this.session.roster[d];if(this.currentContact!==d){this.currentContact=d,$("#roster li").removeClass("selected"),$(a.currentTarget).addClass("selected"),$("#chat-title").text("Chat with "+(c.name||c.jid)),$("#messages").empty(),b=this.chats[d],e=[],b&&(e=b.messages,b.unread=0,this.eachContact(d,function(a){return $(".unread",a).text("").hide()}));for(g=0,h=e.length;g<h;g++)f=e[g],this.appendMessage(f);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);return $("#edit-contact-form .buttons").fadeIn(200)}},a.prototype.scroll=function(){var a;a=$("#messages");return a.animate({scrollTop:a.prop("scrollHeight")},400)},a.prototype.atBottom=function(){var a,b;b=$("#messages"),a=b.prop("scrollHeight")-b.height();return b.scrollTop()===a},a.prototype.send=function(){var a,b,c,d;if(!this.currentContact)return!1;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)),b.val("");return!1},a.prototype.addContact=function(){var a;this.toggleForm("#add-contact-form"),a={jid:$("#add-contact-jid").val(),name:$("#add-contact-name").val(),groups:["Buddies"]},a.jid&&this.session.updateContact(a,!0);return!1},a.prototype.removeContact=function(){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();return!1},a.prototype.updateContact=function(){var a;this.toggleForm("#edit-contact-form"),a={jid:this.currentContact,name:$("#edit-contact-name").val(),groups:this.session.roster[this.currentContact].groups},this.session.updateContact(a);return!1},a.prototype.toggleForm=function(a,b){a=$(a),$(".contact-form").each(function(){if(this.id!==a.attr("id"))return $(this).hide()});if(a.is(":hidden")){b&&b();return a.fadeIn(100)}return a.fadeOut(100,function(){a[0].reset();if(b)return b()})},a.prototype.filterRoster=function(){var a;a=$("#search-roster-text").val().toLowerCase();if(a==="")$("#roster li").show();else return $("#roster li").each(function(){var b,c,d,e;e=$(this),b=(e.attr("data-jid")||"").toLowerCase(),d=(e.attr("data-name")||"").toLowerCase(),c=b.indexOf(a)!==-1||d.indexOf(a)!==-1;return c?e.show():e.hide()})},a.prototype.draw=function(){if(!this.session.connected())window.location.hash="";else{$("body").attr("id","chat-page"),$("#container").hide().empty(),$('<div id="alpha" class="y-fill">\n <h2>Buddies <div id="search-roster"></div></h2>\n <form id="search-roster-form" style="display:none;">\n <input id="search-roster-text" type="search" placeholder="Filter" results="5"/>\n </form>\n <ul id="roster" class="y-fill"></ul>\n <div id="roster-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="contact-form" 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="contact-form" 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="contact-form" 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="x-fill y-fill">\n <h2 id="chat-title">Select a buddy to chat</h2>\n <ul id="messages" class="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="y-fill">\n <h2>Notifications</h2>\n <ul id="notifications" class="y-fill"></ul>\n <div id="notification-controls">\n <div id="clear-notices"></div>\n </div>\n</div>').appendTo("#container"),this.roster(),this.button("clear-notices",ICONS.no),this.button("add-contact",ICONS.plus),this.button("remove-contact",ICONS.minus),this.button("edit-contact",ICONS.user),this.button("search-roster",ICONS.search,{scale:.5,translation:"-8 -8"}),$("#message").focus(function(){return $(".contact-form").fadeOut()}),$("#message-form").submit(__bind(function(){return this.send()},this)),$("#clear-notices").click(function(){return $("#notifications li").fadeOut(200)}),$("#add-contact").click(__bind(function(){return this.toggleForm("#add-contact-form")},this)),$("#remove-contact").click(__bind(function(){return this.toggleForm("#remove-contact-form")},this)),$("#edit-contact").click(__bind(function(){return this.toggleForm("#edit-contact-form",__bind(function(){if(this.currentContact){$("#edit-contact-jid").text(this.currentContact);return $("#edit-contact-name").val(this.session.roster[this.currentContact].name)}},this))},this)),$("#add-contact-cancel").click(__bind(function(){return this.toggleForm("#add-contact-form")},this)),$("#remove-contact-cancel").click(__bind(function(){return this.toggleForm("#remove-contact-form")},this)),$("#edit-contact-cancel").click(__bind(function(){return this.toggleForm("#edit-contact-form")},this)),$("#add-contact-form").submit(__bind(function(){return this.addContact()},this)),$("#remove-contact-form").submit(__bind(function(){return this.removeContact()},this)),$("#edit-contact-form").submit(__bind(function(){return this.updateContact()},this)),$("#search-roster-form").submit(function(){return!1}),$("#search-roster-text").keyup(__bind(function(){return this.filterRoster()},this)),$("#search-roster-text").change(__bind(function(){return this.filterRoster()},this)),$("#search-roster-text").click(__bind(function(){return this.filterRoster()},this)),$("#search-roster").click(__bind(function(){return this.toggleForm("#search-roster-form",__bind(function(){return this.filterRoster()},this))},this)),$("#container").fadeIn(200);return this.resize()}},a.prototype.resize=function(){var a,b,c,d,e;a=$("#alpha"),b=$("#beta"),c=$("#charlie"),e=$("#message"),d=$("#message-form");return new Layout(function(){c.css("left",a.width()+b.width());return e.width(d.width()-32)})},a.prototype.button=function(a,b,c){var d,e,f;c||(c={}),f=Raphael(a),d=f.path(b).attr({fill:"#000",stroke:"#fff","stroke-width":.3,opacity:.6,scale:c.scale||.85,translation:c.translation||""}),e=$("#"+a),e.hover(function(){return d.animate({opacity:1},200)},function(){return d.animate({opacity:.6},200)});return e.get(0)};return a}();var LogoutPage;LogoutPage=function(){function a(a){this.session=a}a.prototype.draw=function(){window.location.hash="";return window.location.reload()};return a}(),$(function(){var a,b,c,d,e,f;f=new Session,d=new NavBar(f),d.draw(),a={Messages:ICONS.chat,Logout:ICONS.power};for(c in a)b=a[c],d.addButton(c,b);e={"/messages":new ChatPage(f),"/logout":new LogoutPage(f),"default":new LoginPage(f,"/messages/")},(new Router(e)).draw();return d.select($("#nav-link-messages").parent())})
|
1
|
+
var ChatPage,__bind=function(a,b){return function(){return a.apply(b,arguments)}};ChatPage=function(){function a(a){this.session=a,this.session.onRoster(__bind(function(){return this.roster()},this)),this.session.onCard(__bind(function(a){return this.card(a)},this)),this.session.onMessage(__bind(function(a){return this.message(a)},this)),this.session.onPresence(__bind(function(a){return this.presence(a)},this)),this.chats={},this.currentContact=null}a.prototype.datef=function(a){var b,c,d,e;b=new Date(a),d=b.getHours()>=12?" pm":" am",c=b.getHours()>12?b.getHours()-12:b.getHours(),c===0&&(c=12),e=b.getMinutes()+"",e.length===1&&(e="0"+e);return c+":"+e+d},a.prototype.card=function(a){return this.eachContact(a.jid,__bind(function(b){return $(".vcard-img",b).attr("src",this.session.avatar(a.jid))},this))},a.prototype.roster=function(){var a,b,c,d,e,f,g,h;e=$("#roster"),$("li",e).each(__bind(function(a,b){var c;c=$(b).attr("data-jid");if(!this.session.roster[c])return $(b).remove()},this)),f=function(a,b){$(".text",a).text(b.name||b.jid);return a.attr("data-name",b.name||"")},g=this.session.roster,h=[];for(c in g)a=g[c],b=$("#roster li[data-jid='"+c+"']"),f(b,a),h.push(b.length===0?(d=$('<li data-jid="'+c+'" 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="'+c+'" src="'+this.session.avatar(c)+'"/>\n</li>').appendTo(e),f(d,a),d.click(__bind(function(a){return this.selectContact(a)},this))):void 0);return h},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){c=this.chat(a.from),c.unread++;return this.eachContact(d,function(a){return $(".unread",a).text(c.unread).show()})}b=this.atBottom(),this.appendMessage(a);if(b)return this.scroll()},a.prototype.eachContact=function(a,b){var c,d,e,f,g;f=$("#roster 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;c=a.from.split("/")[0],b=this.session.roster[c],d=b?b.name||c:c,a.from===this.session.jid()&&(d="Me"),e=$('<li data-jid="'+c+'" style="display:none;">\n <p></p>\n <img alt="'+c+'" src="'+this.session.avatar(c)+'"/>\n <footer>\n <span class="author"></span>\n <span class="time">'+this.datef(a.received)+"</span>\n </footer>\n</li>").appendTo("#messages"),$("p",e).text(a.text),$(".author",e).text(d);return e.fadeIn(200)},a.prototype.queueMessage=function(a){var b,c,d;d=a.from===this.session.jid(),c=a[d?"to":"from"],b=this.chat(c),b.jid=c;return b.messages.push(a)},a.prototype.chat=function(a){var b,c;b=a.split("/")[0],c=this.chats[b],c||(c={jid:a,messages:[],unread:0},this.chats[b]=c);return c},a.prototype.presence=function(a){var b,c,d;c=a.from.split("/")[0];if(c!==this.session.bareJid()){if(!a.type||a.offline)b=this.session.roster[c],this.eachContact(c,function(a){$(".status-msg",a).text(b.status());return b.offline()?a.addClass("offline"):a.removeClass("offline")});a.offline&&(this.chat(c).jid=c);if(a.type==="subscribe"){d=$('<li data-jid="'+a.from+'" style="display:none;">\n <form class="inset">\n <h2>Buddy Approval</h2>\n <p>'+a.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"),d.fadeIn(200),$("form",d).submit(__bind(function(){return this.acceptContact(d,a.from)},this));return $('input[type="button"]',d).click(__bind(function(){return this.rejectContact(d,a.from)},this))}}},a.prototype.acceptContact=function(a,b){a.fadeOut(200,function(){return a.remove()}),this.session.sendSubscribed(b),this.session.sendSubscribe(b);return!1},a.prototype.rejectContact=function(a,b){a.fadeOut(200,function(){return a.remove()});return this.session.sendUnsubscribed(b)},a.prototype.selectContact=function(a){var b,c,d,e,f,g,h;d=$(a.currentTarget).attr("data-jid"),c=this.session.roster[d];if(this.currentContact!==d){this.currentContact=d,$("#roster li").removeClass("selected"),$(a.currentTarget).addClass("selected"),$("#chat-title").text("Chat with "+(c.name||c.jid)),$("#messages").empty(),b=this.chats[d],e=[],b&&(e=b.messages,b.unread=0,this.eachContact(d,function(a){return $(".unread",a).text("").hide()}));for(g=0,h=e.length;g<h;g++)f=e[g],this.appendMessage(f);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);return $("#edit-contact-form .buttons").fadeIn(200)}},a.prototype.scroll=function(){var a;a=$("#messages");return a.animate({scrollTop:a.prop("scrollHeight")},400)},a.prototype.atBottom=function(){var a,b;b=$("#messages"),a=b.prop("scrollHeight")-b.height();return b.scrollTop()===a},a.prototype.send=function(){var a,b,c,d;if(!this.currentContact)return!1;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)),b.val("");return!1},a.prototype.addContact=function(){var a;this.toggleForm("#add-contact-form"),a={jid:$("#add-contact-jid").val(),name:$("#add-contact-name").val(),groups:["Buddies"]},a.jid&&this.session.updateContact(a,!0);return!1},a.prototype.removeContact=function(){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();return!1},a.prototype.updateContact=function(){var a;this.toggleForm("#edit-contact-form"),a={jid:this.currentContact,name:$("#edit-contact-name").val(),groups:this.session.roster[this.currentContact].groups},this.session.updateContact(a);return!1},a.prototype.toggleForm=function(a,b){a=$(a),$("form.overlay").each(function(){if(this.id!==a.attr("id"))return $(this).hide()});if(a.is(":hidden")){b&&b();return a.fadeIn(100)}return a.fadeOut(100,function(){a[0].reset();if(b)return b()})},a.prototype.draw=function(){var a,b;if(!this.session.connected())window.location.hash="";else{$("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(__bind(function(){return this.send()},this)),$("#clear-notices").click(function(){return $("#notifications li").fadeOut(200)}),$("#add-contact").click(__bind(function(){return this.toggleForm("#add-contact-form")},this)),$("#remove-contact").click(__bind(function(){return this.toggleForm("#remove-contact-form")},this)),$("#edit-contact").click(__bind(function(){return this.toggleForm("#edit-contact-form",__bind(function(){if(this.currentContact){$("#edit-contact-jid").text(this.currentContact);return $("#edit-contact-name").val(this.session.roster[this.currentContact].name)}},this))},this)),$("#add-contact-cancel").click(__bind(function(){return this.toggleForm("#add-contact-form")},this)),$("#remove-contact-cancel").click(__bind(function(){return this.toggleForm("#remove-contact-form")},this)),$("#edit-contact-cancel").click(__bind(function(){return this.toggleForm("#edit-contact-form")},this)),$("#add-contact-form").submit(__bind(function(){return this.addContact()},this)),$("#remove-contact-form").submit(__bind(function(){return this.removeContact()},this)),$("#edit-contact-form").submit(__bind(function(){return this.updateContact()},this)),$("#container").fadeIn(200),b=this.resize(),a=function(){b.resize();return b.resize()};return new Filter({list:"#roster",icon:"#search-roster-icon",form:"#search-roster-form",attrs:["data-jid","data-name"],open:a,close:a})}},a.prototype.resize=function(){var a,b,c,d,e;a=$("#alpha"),b=$("#beta"),c=$("#charlie"),e=$("#message"),d=$("#message-form");return new Layout(function(){c.css("left",a.width()+b.width());return e.width(d.width()-32)})};return a}();var LogoutPage;LogoutPage=function(){function a(a){this.session=a}a.prototype.draw=function(){window.location.hash="";return window.location.reload()};return a}(),$(function(){var a,b,c,d,e,f;f=new Session,d=new NavBar(f),d.draw(),a={Messages:ICONS.chat,Logout:ICONS.power};for(c in a)b=a[c],d.addButton(c,b);e={"/messages":new ChatPage(f),"/logout":new LogoutPage(f),"default":new LoginPage(f,"/messages/")},(new Router(e)).draw();return d.select($("#nav-link-messages").parent())})
|
@@ -148,7 +148,7 @@ ChatPage = (function() {
|
|
148
148
|
this.chat(from).jid = from;
|
149
149
|
}
|
150
150
|
if (presence.type === 'subscribe') {
|
151
|
-
node = $("<li data-jid=\"" + presence.from + "\" style=\"display:none;\">\n <form class=\"
|
151
|
+
node = $("<li data-jid=\"" + presence.from + "\" style=\"display:none;\">\n <form class=\"inset\">\n <h2>Buddy Approval</h2>\n <p>" + presence.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');
|
152
152
|
node.fadeIn(200);
|
153
153
|
$('form', node).submit(__bind(function() {
|
154
154
|
return this.acceptContact(node, presence.from);
|
@@ -279,7 +279,7 @@ ChatPage = (function() {
|
|
279
279
|
};
|
280
280
|
ChatPage.prototype.toggleForm = function(form, fn) {
|
281
281
|
form = $(form);
|
282
|
-
$('.
|
282
|
+
$('form.overlay').each(function() {
|
283
283
|
if (this.id !== form.attr('id')) {
|
284
284
|
return $(this).hide();
|
285
285
|
}
|
@@ -298,45 +298,22 @@ ChatPage = (function() {
|
|
298
298
|
});
|
299
299
|
}
|
300
300
|
};
|
301
|
-
ChatPage.prototype.filterRoster = function() {
|
302
|
-
var text;
|
303
|
-
text = $('#search-roster-text').val().toLowerCase();
|
304
|
-
if (text === '') {
|
305
|
-
$('#roster li').show();
|
306
|
-
return;
|
307
|
-
}
|
308
|
-
return $('#roster li').each(function() {
|
309
|
-
var jid, match, name, node;
|
310
|
-
node = $(this);
|
311
|
-
jid = (node.attr('data-jid') || '').toLowerCase();
|
312
|
-
name = (node.attr('data-name') || '').toLowerCase();
|
313
|
-
match = jid.indexOf(text) !== -1 || name.indexOf(text) !== -1;
|
314
|
-
if (match) {
|
315
|
-
return node.show();
|
316
|
-
} else {
|
317
|
-
return node.hide();
|
318
|
-
}
|
319
|
-
});
|
320
|
-
};
|
321
301
|
ChatPage.prototype.draw = function() {
|
302
|
+
var fn, layout;
|
322
303
|
if (!this.session.connected()) {
|
323
304
|
window.location.hash = '';
|
324
305
|
return;
|
325
306
|
}
|
326
307
|
$('body').attr('id', 'chat-page');
|
327
308
|
$('#container').hide().empty();
|
328
|
-
$("<div id=\"alpha\" class=\"y-fill\">\n <h2>Buddies <div id=\"search-roster\"></div></h2>\n <
|
309
|
+
$("<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');
|
329
310
|
this.roster();
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
this.button('search-roster', ICONS.search, {
|
335
|
-
scale: 0.5,
|
336
|
-
translation: '-8 -8'
|
337
|
-
});
|
311
|
+
new Button('#clear-notices', ICONS.no);
|
312
|
+
new Button('#add-contact', ICONS.plus);
|
313
|
+
new Button('#remove-contact', ICONS.minus);
|
314
|
+
new Button('#edit-contact', ICONS.user);
|
338
315
|
$('#message').focus(function() {
|
339
|
-
return $('.
|
316
|
+
return $('form.overlay').fadeOut();
|
340
317
|
});
|
341
318
|
$('#message-form').submit(__bind(function() {
|
342
319
|
return this.send();
|
@@ -376,25 +353,20 @@ ChatPage = (function() {
|
|
376
353
|
$('#edit-contact-form').submit(__bind(function() {
|
377
354
|
return this.updateContact();
|
378
355
|
}, this));
|
379
|
-
$('#search-roster-form').submit(function() {
|
380
|
-
return false;
|
381
|
-
});
|
382
|
-
$('#search-roster-text').keyup(__bind(function() {
|
383
|
-
return this.filterRoster();
|
384
|
-
}, this));
|
385
|
-
$('#search-roster-text').change(__bind(function() {
|
386
|
-
return this.filterRoster();
|
387
|
-
}, this));
|
388
|
-
$('#search-roster-text').click(__bind(function() {
|
389
|
-
return this.filterRoster();
|
390
|
-
}, this));
|
391
|
-
$('#search-roster').click(__bind(function() {
|
392
|
-
return this.toggleForm('#search-roster-form', __bind(function() {
|
393
|
-
return this.filterRoster();
|
394
|
-
}, this));
|
395
|
-
}, this));
|
396
356
|
$('#container').fadeIn(200);
|
397
|
-
|
357
|
+
layout = this.resize();
|
358
|
+
fn = function() {
|
359
|
+
layout.resize();
|
360
|
+
return layout.resize();
|
361
|
+
};
|
362
|
+
return new Filter({
|
363
|
+
list: '#roster',
|
364
|
+
icon: '#search-roster-icon',
|
365
|
+
form: '#search-roster-form',
|
366
|
+
attrs: ['data-jid', 'data-name'],
|
367
|
+
open: fn,
|
368
|
+
close: fn
|
369
|
+
});
|
398
370
|
};
|
399
371
|
ChatPage.prototype.resize = function() {
|
400
372
|
var a, b, c, form, msg;
|
@@ -408,29 +380,5 @@ ChatPage = (function() {
|
|
408
380
|
return msg.width(form.width() - 32);
|
409
381
|
});
|
410
382
|
};
|
411
|
-
ChatPage.prototype.button = function(id, path, options) {
|
412
|
-
var icon, node, paper;
|
413
|
-
options || (options = {});
|
414
|
-
paper = Raphael(id);
|
415
|
-
icon = paper.path(path).attr({
|
416
|
-
fill: '#000',
|
417
|
-
stroke: '#fff',
|
418
|
-
'stroke-width': 0.3,
|
419
|
-
opacity: 0.6,
|
420
|
-
scale: options.scale || 0.85,
|
421
|
-
translation: options.translation || ''
|
422
|
-
});
|
423
|
-
node = $('#' + id);
|
424
|
-
node.hover(function() {
|
425
|
-
return icon.animate({
|
426
|
-
opacity: 1.0
|
427
|
-
}, 200);
|
428
|
-
}, function() {
|
429
|
-
return icon.animate({
|
430
|
-
opacity: 0.6
|
431
|
-
}, 200);
|
432
|
-
});
|
433
|
-
return node.get(0);
|
434
|
-
};
|
435
383
|
return ChatPage;
|
436
384
|
})();
|
@@ -1,41 +1,6 @@
|
|
1
1
|
#chat-page #container {
|
2
2
|
height: 100%;
|
3
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
4
|
#chat-page #chat-title {
|
40
5
|
background: #f8f8f8;
|
41
6
|
}
|
@@ -43,25 +8,9 @@
|
|
43
8
|
background: #fff;
|
44
9
|
height: 100%;
|
45
10
|
list-style: none;
|
46
|
-
overflow-y: auto;
|
47
11
|
text-shadow: 0 1px 1px #ddd;
|
48
12
|
width: 100%;
|
49
13
|
}
|
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
14
|
#chat-page #messages li {
|
66
15
|
border-bottom: 1px solid #f0f0f0;
|
67
16
|
min-height: 40px;
|
@@ -122,7 +71,6 @@
|
|
122
71
|
#chat-page #notifications {
|
123
72
|
height: 100%;
|
124
73
|
list-style: none;
|
125
|
-
overflow-y: auto;
|
126
74
|
text-shadow: 0 1px 1px #fff;
|
127
75
|
width: 260px;
|
128
76
|
}
|
@@ -143,7 +91,7 @@
|
|
143
91
|
font-weight: normal;
|
144
92
|
padding: 10px 0 0 0;
|
145
93
|
}
|
146
|
-
#chat-page #roster li:hover,
|
94
|
+
#chat-page #roster li:hover:not(.selected),
|
147
95
|
#chat-page #notifications li:hover {
|
148
96
|
background: rgba(255, 255, 255, 1.0);
|
149
97
|
}
|
@@ -153,15 +101,6 @@
|
|
153
101
|
#chat-page #roster li.selected > * {
|
154
102
|
opacity: 1.0;
|
155
103
|
}
|
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
104
|
#chat-page #roster li.selected .status-msg {
|
166
105
|
color: rgba(255, 255, 255, 0.85);
|
167
106
|
}
|
@@ -199,92 +138,10 @@
|
|
199
138
|
top: 4px;
|
200
139
|
right: 10px;
|
201
140
|
}
|
202
|
-
#chat-page #
|
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;
|
141
|
+
#chat-page #charlie-controls {
|
259
142
|
text-align: right;
|
260
143
|
}
|
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
144
|
#chat-page #edit-contact-jid {
|
269
145
|
color: #444;
|
270
146
|
margin-top: -5px;
|
271
147
|
}
|
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
|
-
}
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class Button
|
2
|
+
constructor: (node, path, options) ->
|
3
|
+
@node = $ node
|
4
|
+
@path = path
|
5
|
+
@options = options || {}
|
6
|
+
this.draw()
|
7
|
+
|
8
|
+
draw: ->
|
9
|
+
paper = Raphael @node.get(0)
|
10
|
+
|
11
|
+
icon = paper.path(@path).attr
|
12
|
+
fill: @options.fill || '#000'
|
13
|
+
stroke: @options.stroke || '#fff'
|
14
|
+
'stroke-width': @options['stroke-width'] || 0.3
|
15
|
+
opacity: @options.opacity || 0.6
|
16
|
+
scale: @options.scale || 0.85
|
17
|
+
translation: @options.translation || ''
|
18
|
+
|
19
|
+
@node.hover(
|
20
|
+
-> icon.animate(opacity: 1.0, 200),
|
21
|
+
-> icon.animate(opacity: 0.6, 200))
|