diff --git a/spec/chatroom.js b/spec/chatroom.js index 671d082d7..e064dd5da 100644 --- a/spec/chatroom.js +++ b/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( diff --git a/spec/controlbox.js b/spec/controlbox.js index 0b972602d..ac8920d38 100644 --- a/spec/controlbox.js +++ b/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("shows the number of unread mentions received", mock.initConverse(function (_converse) { + test_utils.createContacts(_converse, 'all').openControlBox(); + test_utils.openContactsPanel(_converse); + + 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("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); - })); }); }); })); diff --git a/src/converse-controlbox.js b/src/converse-controlbox.js index d0d98e688..f727f8f42 100644 --- a/src/converse-controlbox.js +++ b/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 () { diff --git a/src/templates/contacts_tab.html b/src/templates/contacts_tab.html index b103d73d6..6447d9d75 100644 --- a/src/templates/contacts_tab.html +++ b/src/templates/contacts_tab.html @@ -1,4 +1,9 @@ -
  • {{{label_contacts}}} -
  • + {[ if (num_unread) { ]} + {{{ num_unread }}} + {[ } ]} +