diff --git a/assets/css/subway.css b/assets/css/subway.css
index 432f838..21927e5 100644
--- a/assets/css/subway.css
+++ b/assets/css/subway.css
@@ -179,6 +179,15 @@
background: #F9F9F9;
}
+.joinpart{
+ padding: 1% 0% 1% 1%;
+}
+
+.joinpart img{
+ padding-right: 1%;
+ vertical-align: text-bottom;
+}
+
.chat_name{
display: table-cell;
width: 14%;
@@ -227,3 +236,32 @@
overflow-y: auto;
height: 95%;
}
+
+.userlist_user{
+ border-bottom: 1px solid #CCCCCC;
+ display: table;
+ width: 100%;
+}
+
+.userlist_user_activity{
+ width: 13%;
+ display: table-cell;
+ padding: 2%;
+ background: #EFEFEF;
+ text-align: center;
+ border-right: 1px solid #DDDDDD;
+}
+
+.userlist_user_info{
+ display: table-cell;
+ width: 87%;
+ padding: 3% 0% 3% 5%;
+}
+
+.userlist_user_name{
+ font-weight: bold;
+}
+
+.userlist_user_active{
+ color: #666666;
+}
diff --git a/assets/images/active.png b/assets/images/active.png
new file mode 100644
index 0000000..af0ee80
Binary files /dev/null and b/assets/images/active.png differ
diff --git a/assets/images/idle.png b/assets/images/idle.png
new file mode 100644
index 0000000..91630b6
Binary files /dev/null and b/assets/images/idle.png differ
diff --git a/assets/images/join.png b/assets/images/join.png
new file mode 100644
index 0000000..7f38880
Binary files /dev/null and b/assets/images/join.png differ
diff --git a/assets/images/part.png b/assets/images/part.png
new file mode 100644
index 0000000..bb5e0b1
Binary files /dev/null and b/assets/images/part.png differ
diff --git a/assets/js/client.js b/assets/js/client.js
index 725c967..dec5da7 100644
--- a/assets/js/client.js
+++ b/assets/js/client.js
@@ -56,7 +56,7 @@ $(function() {
irc.chatWindows.add({name: data.channel});
} else {
var channel = irc.chatWindows.getByName(data.channel);
- channel.participants.add({nick: data.nick});
+ channel.userList.add({nick: data.nick, role: data.role, idle:0, user_status: 'active', activity: 'Joined'});
var joinMessage = new Message({type: 'join', nick: data.nick});
joinMessage.setText();
channel.stream.add(joinMessage);
@@ -69,13 +69,23 @@ $(function() {
if (data.nick === irc.me.nick) {
channel.part();
} else {
- channel.participants.getByNick(data.nick).destroy();
+ var user = channel.userList.getByNick(data.nick);
+ user.view.remove();
+ user.destroy();
var partMessage = new Message({type: 'part', nick: data.nick});
partMessage.setText();
channel.stream.add(partMessage);
}
});
+ irc.socket.on('names', function(data) {
+ var channel = irc.chatWindows.getByName(data.channel);
+ channel.userList = new UserList(channel);
+ $.each(data.nicks, function(nick, role){
+ channel.userList.add(new User({nick: nick, role: role, idle:0, user_status: 'active', activity: 'Joined'}))
+ });
+ });
+
irc.socket.on('topic', function(data) {
var channel = irc.chatWindows.getByName(data.channel);
channel.set({topic: data.topic});
diff --git a/assets/js/collections.js b/assets/js/collections.js
index 6105bf3..7203fd5 100644
--- a/assets/js/collections.js
+++ b/assets/js/collections.js
@@ -55,10 +55,24 @@ var WindowList = Backbone.Collection.extend({
var UserList = Backbone.Collection.extend({
model: User,
+
+ initialize: function(channel) {
+ this.channel = channel;
+ this.view = new UserListView({collection:this});
+ },
+
getByNick: function(nick) {
return this.detect(function(user) {
return user.get('nick') == nick;
});
+ },
+
+ getUsers: function() {
+ var users = [];
+ for (var i=0; i' + this.get('nick') + ' joined the channel';
break;
case 'part':
- text = this.get('nick') + ' left the channel';
+ text = '' + this.get('nick') + ' left the channel';
break;
case 'nick':
- text = this.get('oldNick') + ' is now known as ' + this.get('newNick');
+ text = '' + this.get('oldNick') + ' is now known as ' + this.get('newNick');
break;
}
this.set({text: text});
@@ -136,8 +136,10 @@ var ChatWindow = Backbone.Model.extend({
});
var User = Backbone.Model.extend({
+ initialize: function(){
+ },
+
defaults: {
opStatus: ''
}
});
-
diff --git a/assets/js/views/chat.js b/assets/js/views/chat.js
index 167e9fa..e7b5ec5 100644
--- a/assets/js/views/chat.js
+++ b/assets/js/views/chat.js
@@ -57,21 +57,21 @@ var ChatView = Backbone.View.extend({
$(this).val('');
$('#chat_button').addClass('disabled');
} else if (event.keyCode == 9) {
- console.log(event);
+ var channel = irc.chatWindows.getActive();
// Tab completion of user names
- var sentence = $(this).val().split(' ');
+ var sentence = $('#chat_input').val().split(' ');
var partialMatch = sentence.pop();
// TODO: Make this work (copy-paste from old code; it doesn't work)
// All the below code is busted until this is resolved.
- // channel = app.model.chatApp.channels.findChannel(app.activeChannel);
- var users = channel.attributes.users;
- for (user in users) {
+ var users = channel.userList.getUsers();
+ for (var i=0; i 0 && user.search(partialMatch) === 0) {
sentence.push(user);
if (sentence.length === 1) {
- $(this).val(sentence.join(' ') + ":");
+ $('#chat_input').val(sentence.join(' ') + ":");
} else {
- $(this).val(sentence.join(' '));
+ $('#chat_input').val(sentence.join(' '));
}
}
}
@@ -88,12 +88,24 @@ var ChatView = Backbone.View.extend({
addMessage: function(msg) {
var $chatWindow = this.$('#chat-contents');
var view = new MessageView({model: msg});
+ var sender = msg.get('sender');
+ var type = msg.get('type');
+ if (sender !== '' && type === 'message'){
+ var user = this.model.userList.getByNick(sender);
+ user.set({idle: 0});
+ user.view.addToIdle();
+ }
+
$chatWindow.append(view.el);
- if (msg.get('sender') === irc.me.nick) {
+ if (sender === irc.me.nick) {
$(view.el).addClass('message-me');
}
+ if(type === 'join' || type === 'part'){
+ $(view.el).addClass('joinpart');
+ }
+
// Scroll down to show new message
var chatWindowHeight = ($chatWindow[0].scrollHeight - 555);
// If the window is large enough to be scrollable
diff --git a/assets/js/views/user_list.js b/assets/js/views/user_list.js
new file mode 100644
index 0000000..d10230a
--- /dev/null
+++ b/assets/js/views/user_list.js
@@ -0,0 +1,47 @@
+var UserView = Backbone.View.extend({
+ initialize: function(user) {
+ this.user = user;
+ this.setStatus();
+ },
+
+ className: 'userlist_user',
+
+ render: function() {
+ $(this.el).html(ich.userlist_user(this.user.model.attributes));
+ return this;
+ },
+
+ addToIdle: function(){
+ var idle_time = this.user.model.get('idle') + 1;
+ if (idle_time > 60) {
+ this.user.model.set({activity: 'idle', user_status: 'idle'});
+ } else {
+ this.user.model.set({activity: 'Last active ' + idle_time + ' minutes ago', idle: idle_time});
+ }
+ this.render();
+ },
+
+ setStatus: function(){
+ //One minute delays
+ var self = this;
+ var interval = 60000;
+ window.setInterval(function() { self.addToIdle() }, interval);
+ }
+});
+
+var UserListView = Backbone.View.extend({
+ initialize: function() {
+ this.el = this.collection.channel.view.$('#user-list');
+ this.collection.bind('add', this.add, this);
+ },
+
+ render: function() {
+ return this;
+ },
+
+ add: function(User) {
+ var userView = new UserView({model: User});
+ User.view = userView;
+ $(this.el).append(userView.render().el);
+ }
+});
diff --git a/views/templates.jade b/views/templates.jade
index c32e24e..678479f 100644
--- a/views/templates.jade
+++ b/views/templates.jade
@@ -71,7 +71,11 @@ script(id="unread_mentions", type="text/html")
span(class="unread_mentions", title="Mentions in channel") {{unread_mentions}}
script(id="userlist_user", type="text/html")
- li {{username}}
+ div(class="userlist_user_activity")
+ img(src="/assets/images/{{user_status}}.png")
+ div(class="userlist_user_info")
+ div(class="userlist_user_name") {{role}}{{nick}}
+ div(class="userlist_user_active") {{activity}}
script(id="link", type="text/html")
a(target="_blank", href="{{link}}") {{link}}