Browse Source

Show number of unread mesages on the "Contacts" tab

JC Brand 8 years ago
parent
commit
f897fbb7c0
4 changed files with 144 additions and 87 deletions
  1. 65 0
      spec/chatroom.js
  2. 33 62
      spec/controlbox.js
  3. 39 23
      src/converse-controlbox.js
  4. 7 2
      src/templates/contacts_tab.html

+ 65 - 0
spec/chatroom.js

@@ -2064,6 +2064,71 @@
 
         describe("The \"Rooms\" Panel", function () {
 
+            it("is opened by clicking the 'Chatrooms' tab", mock.initConverse(function (_converse) {
+                test_utils.openControlBox();
+                var cbview = _converse.chatboxviews.get('controlbox');
+                var $tabs = cbview.$el.find('#controlbox-tabs');
+                var $panels = cbview.$el.find('.controlbox-panes');
+                var $contacts = $panels.children().first();
+                var $chatrooms = $panels.children().last();
+                spyOn(cbview, 'switchTab').and.callThrough();
+                cbview.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
+                $tabs.find('li').last().find('a').click(); // Clicks the chatrooms tab
+                expect($contacts.is(':visible')).toBe(false);
+                expect($chatrooms.is(':visible')).toBe(true);
+                expect(cbview.switchTab).toHaveBeenCalled();
+            }));
+
+            it("contains a form through which a new chatroom can be created", mock.initConverse(function (_converse) {
+                test_utils.openControlBox();
+                var roomspanel = _converse.chatboxviews.get('controlbox').roomspanel;
+                var $input = roomspanel.$el.find('input.new-chatroom-name');
+                var $nick = roomspanel.$el.find('input.new-chatroom-nick');
+                var $server = roomspanel.$el.find('input.new-chatroom-server');
+                expect($input.length).toBe(1);
+                expect($server.length).toBe(1);
+                expect($('.chatroom:visible').length).toBe(0); // There shouldn't be any chatrooms open currently
+                spyOn(roomspanel, 'createChatRoom').and.callThrough();
+                spyOn(_converse.ChatRoomView.prototype, 'getRoomFeatures').and.callFake(function () {
+                    var deferred = new $.Deferred();
+                    deferred.resolve();
+                    return deferred.promise();
+                });
+
+                roomspanel.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
+                $input.val('Lounge');
+                $nick.val('dummy');
+                $server.val('muc.localhost');
+                roomspanel.$el.find('form').submit();
+                expect(roomspanel.createChatRoom).toHaveBeenCalled();
+                expect($('.chatroom:visible').length).toBe(1); // There should now be an open chatroom
+            }));
+
+            it("can list rooms publically available on the server", mock.initConverse(function (_converse) {
+                test_utils.openControlBox();
+                var panel = _converse.chatboxviews.get('controlbox').roomspanel;
+                $(panel.tabs).find('li').last().find('a').click(); // Click the chatrooms tab
+                panel.model.set({'muc_domain': 'muc.localhost'}); // Make sure the domain is set
+                // See: http://xmpp.org/extensions/xep-0045.html#disco-rooms
+                expect($('#available-chatrooms').children('dt').length).toBe(0);
+                expect($('#available-chatrooms').children('dd').length).toBe(0);
+
+                var iq = $iq({
+                    from:'muc.localhost',
+                    to:'dummy@localhost/pda',
+                    type:'result'
+                }).c('query')
+                  .c('item', { jid:'heath@chat.shakespeare.lit', name:'A Lonely Heath'}).up()
+                  .c('item', { jid:'coven@chat.shakespeare.lit', name:'A Dark Cave'}).up()
+                  .c('item', { jid:'forres@chat.shakespeare.lit', name:'The Palace'}).up()
+                  .c('item', { jid:'inverness@chat.shakespeare.lit', name:'Macbeth's Castle'}).nodeTree;
+
+                panel.onRoomsFound(iq);
+                expect(panel.$('#available-chatrooms').children('dt').length).toBe(1);
+                expect(panel.$('#available-chatrooms').children('dt').first().text()).toBe("Rooms on muc.localhost");
+                expect(panel.$('#available-chatrooms').children('dd').length).toBe(4);
+            }));
+
             it("shows the number of unread mentions received", mock.initConverse(function (_converse) {
                 var room_jid = 'kitchen@conference.shakespeare.lit';
                 test_utils.openAndEnterChatRoom(

+ 33 - 62
spec/controlbox.js

@@ -4,6 +4,7 @@
     var _ = converse.env._;
     var $ = converse.env.jQuery;
     var $pres = converse.env.$pres;
+    var $msg = converse.env.$msg;
     var $iq = converse.env.$iq;
 
     var checkHeaderToggling = function ($header) {
@@ -1127,72 +1128,42 @@
             expect(cbview.model.get('active-panel')).toBe('users');
         }));
 
-        describe("chatrooms panel", function () {
+        describe("The \"Contacts\" Panel", function () {
 
-            it("is opened by clicking the 'Chatrooms' tab", mock.initConverse(function (_converse) {
-                test_utils.openControlBox();
-                var cbview = _converse.chatboxviews.get('controlbox');
-                var $tabs = cbview.$el.find('#controlbox-tabs');
-                var $panels = cbview.$el.find('.controlbox-panes');
-                var $contacts = $panels.children().first();
-                var $chatrooms = $panels.children().last();
-                spyOn(cbview, 'switchTab').and.callThrough();
-                cbview.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
-                $tabs.find('li').last().find('a').click(); // Clicks the chatrooms tab
-                expect($contacts.is(':visible')).toBe(false);
-                expect($chatrooms.is(':visible')).toBe(true);
-                expect(cbview.switchTab).toHaveBeenCalled();
-            }));
-
-            it("contains a form through which a new chatroom can be created", mock.initConverse(function (_converse) {
-                test_utils.openControlBox();
-                var roomspanel = _converse.chatboxviews.get('controlbox').roomspanel;
-                var $input = roomspanel.$el.find('input.new-chatroom-name');
-                var $nick = roomspanel.$el.find('input.new-chatroom-nick');
-                var $server = roomspanel.$el.find('input.new-chatroom-server');
-                expect($input.length).toBe(1);
-                expect($server.length).toBe(1);
-                expect($('.chatroom:visible').length).toBe(0); // There shouldn't be any chatrooms open currently
-                spyOn(roomspanel, 'createChatRoom').and.callThrough();
-                spyOn(_converse.ChatRoomView.prototype, 'getRoomFeatures').and.callFake(function () {
-                    var deferred = new $.Deferred();
-                    deferred.resolve();
-                    return deferred.promise();
-                });
+            it("shows the number of unread mentions received", mock.initConverse(function (_converse) {
+                test_utils.createContacts(_converse, 'all').openControlBox();
+                test_utils.openContactsPanel(_converse);
 
-                roomspanel.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
-                $input.val('Lounge');
-                $nick.val('dummy');
-                $server.val('muc.localhost');
-                roomspanel.$el.find('form').submit();
-                expect(roomspanel.createChatRoom).toHaveBeenCalled();
-                expect($('.chatroom:visible').length).toBe(1); // There should now be an open chatroom
+                var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
+                test_utils.openChatBoxFor(_converse, sender_jid);
+                var chatview = _converse.chatboxviews.get(sender_jid);
+                chatview.model.set({'minimized': true});
+
+                var msg = $msg({
+                        from: sender_jid,
+                        to: _converse.connection.jid,
+                        type: 'chat',
+                        id: (new Date()).getTime()
+                    }).c('body').t('hello').up()
+                    .c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree();
+                _converse.chatboxes.onMessage(msg);
+                var contacts_panel = _converse.chatboxviews.get('controlbox').contactspanel;
+                expect(contacts_panel.tab_el.querySelector('.msgs-indicator').textContent).toBe('1');
+
+                msg = $msg({
+                        from: sender_jid,
+                        to: _converse.connection.jid,
+                        type: 'chat',
+                        id: (new Date()).getTime()
+                    }).c('body').t('hello again').up()
+                    .c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree();
+                _converse.chatboxes.onMessage(msg);
+                expect(contacts_panel.tab_el.querySelector('.msgs-indicator').textContent).toBe('2');
+
+                chatview.model.set({'minimized': false});
+                expect(_.includes(contacts_panel.tab_el.firstChild.classList, 'unread-msgs')).toBeFalsy();
             }));
 
-            it("can list rooms publically available on the server", mock.initConverse(function (_converse) {
-                test_utils.openControlBox();
-                var panel = _converse.chatboxviews.get('controlbox').roomspanel;
-                $(panel.tabs).find('li').last().find('a').click(); // Click the chatrooms tab
-                panel.model.set({'muc_domain': 'muc.localhost'}); // Make sure the domain is set
-                // See: http://xmpp.org/extensions/xep-0045.html#disco-rooms
-                expect($('#available-chatrooms').children('dt').length).toBe(0);
-                expect($('#available-chatrooms').children('dd').length).toBe(0);
-
-                var iq = $iq({
-                    from:'muc.localhost',
-                    to:'dummy@localhost/pda',
-                    type:'result'
-                }).c('query')
-                  .c('item', { jid:'heath@chat.shakespeare.lit', name:'A Lonely Heath'}).up()
-                  .c('item', { jid:'coven@chat.shakespeare.lit', name:'A Dark Cave'}).up()
-                  .c('item', { jid:'forres@chat.shakespeare.lit', name:'The Palace'}).up()
-                  .c('item', { jid:'inverness@chat.shakespeare.lit', name:'Macbeth's Castle'}).nodeTree;
-
-                panel.onRoomsFound(iq);
-                expect(panel.$('#available-chatrooms').children('dt').length).toBe(1);
-                expect(panel.$('#available-chatrooms').children('dt').first().text()).toBe("Rooms on muc.localhost");
-                expect(panel.$('#available-chatrooms').children('dd').length).toBe(4);
-            }));
         });
     });
 }));

+ 39 - 23
src/converse-controlbox.js

@@ -285,7 +285,7 @@
                     this.contactspanel = new _converse.ContactsPanel({
                         '$parent': this.$el.find('.controlbox-panes')
                     });
-                    this.contactspanel.render();
+                    this.contactspanel.insertIntoDOM();
                     _converse.xmppstatusview = new _converse.XMPPStatusView({
                         'model': _converse.xmppstatus
                     });
@@ -582,12 +582,20 @@
                 },
 
                 initialize: function (cfg) {
-                    cfg.$parent.append(this.$el);
-                    this.$tabs = cfg.$parent.parent().find('#controlbox-tabs');
+                    this.parent_el = cfg.$parent[0];
+                    this.tab_el = document.createElement('li');
+                    _converse.chatboxes.on('change:num_unread', this.render, this);
                 },
 
                 render: function () {
-                    var markup;
+                    var controlbox = _converse.chatboxes.get('controlbox');
+                    var is_current = controlbox.get('active-panel') === USERS_PANEL_ID;
+                    this.tab_el.innerHTML = tpl_contacts_tab({
+                        'label_contacts': LABEL_CONTACTS,
+                        'is_current': is_current,
+                        'num_unread': _.sum(_converse.chatboxes.pluck('num_unread'))
+                    });
+
                     var widgets = tpl_contacts_panel({
                         label_online: __('Online'),
                         label_busy: __('Busy'),
@@ -597,36 +605,44 @@
                         include_offline_state: _converse.include_offline_state,
                         allow_logout: _converse.allow_logout
                     });
-                    var controlbox = _converse.chatboxes.get('controlbox');
-                    this.$tabs.append(tpl_contacts_tab({
-                        'label_contacts': LABEL_CONTACTS,
-                        'is_current': controlbox.get('active-panel') === USERS_PANEL_ID
-                    }));
-                    if (_converse.xhr_user_search) {
-                        markup = tpl_search_contact({
-                            label_contact_name: __('Contact name'),
-                            label_search: __('Search')
-                        });
-                    } else {
-                        markup = tpl_add_contact_form({
-                            label_contact_username: __('e.g. user@example.org'),
-                            label_add: __('Add')
-                        });
-                    }
                     if (_converse.allow_contact_requests) {
                         widgets += tpl_add_contact_dropdown({
                             label_click_to_chat: __('Click to add new chat contacts'),
                             label_add_contact: __('Add a contact')
                         });
                     }
-                    this.$el.html(widgets);
-                    this.$el.find('.search-xmpp ul').append(markup);
-                    if (controlbox.get('active-panel') !== USERS_PANEL_ID) {
+                    this.el.innerHTML = widgets;
+
+                    if (!is_current) {
                         this.$el.addClass('hidden');
                     }
                     return this;
                 },
 
+                insertIntoDOM: function () {
+                    this.parent_el.appendChild(this.render().el);
+                    this.tabs = this.parent_el.parentNode.querySelector('#controlbox-tabs');
+                    this.tabs.appendChild(this.tab_el);
+                    this.$el.find('.search-xmpp ul').append(
+                        this.generateAddContactHTML()
+                    );
+                    return this;
+                },
+
+                generateAddContactHTML: function () {
+                    if (_converse.xhr_user_search) {
+                        return tpl_search_contact({
+                            label_contact_name: __('Contact name'),
+                            label_search: __('Search')
+                        });
+                    } else {
+                        return tpl_add_contact_form({
+                            label_contact_username: __('e.g. user@example.org'),
+                            label_add: __('Add')
+                        });
+                    }
+                },
+
                 toggleContactForm: function (ev) {
                     ev.preventDefault();
                     this.$el.find('.search-xmpp').toggle('fast', function () {

+ 7 - 2
src/templates/contacts_tab.html

@@ -1,4 +1,9 @@
-<li><a class="s {[ if (is_current) { ]} current {[ } ]}"
+<a class="s
+   {[ if (is_current) { ]} current {[ } ]}
+   {[ if (num_unread) { ]} unread-msgs {[ } ]}"
        data-id="users" href="#users">
     {{{label_contacts}}}
-</a></li>
+    {[ if (num_unread) { ]}
+        <span class="msgs-indicator">{{{ num_unread }}}</span>
+    {[ } ]}
+</a>