From bb0f49cf4d0e0a80035039a78949fac1a01354fa Mon Sep 17 00:00:00 2001 From: JC Brand Date: Sun, 9 Mar 2014 13:10:57 +0200 Subject: [PATCH] Add a counter to show unread msgs when chat is minimized --- converse.css | 1 + converse.js | 44 +++++++++++++++++++++++-------- mockup/minimized.html | 4 +-- spec/chatbox.js | 52 ++++++++++++++++++++++++++++--------- src/templates/chatbox.html | 1 + src/templates/chatroom.html | 1 + 6 files changed, 78 insertions(+), 25 deletions(-) diff --git a/converse.css b/converse.css index 4180c3680..07f2454e9 100644 --- a/converse.css +++ b/converse.css @@ -672,6 +672,7 @@ form.search-xmpp-contact input { padding: 2px 10px; font-size: 18px; text-align: center; + display: none; } .chat-head-chatroom .chat-head-message-count { diff --git a/converse.js b/converse.js index 3f3fd95cc..968cda4b4 100644 --- a/converse.js +++ b/converse.js @@ -655,6 +655,7 @@ 'box_id' : hex_sha1(this.get('jid')), 'otr_status': this.get('otr_status') || UNENCRYPTED, 'minimized': this.get('minimized') || false, + 'time_minimized': this.get('time_minimized') || converse.toISOString(new Date()), 'height': height }); } else { @@ -892,7 +893,6 @@ this.model.on('showReceivedOTRMessage', function (text) { this.showMessage({'message': text, 'sender': 'them'}); }, this); - this.updateVCard(); this.$el.appendTo(converse.chatboxviews.$el); this.render().show().focus().model.messages.fetch({add: true}); @@ -938,23 +938,35 @@ this.scrollDown(); }, + updateUnreadMessagesCounter: function () { + /* If the chatbox is minimized, we show a counter with the + * number of unread messages. + */ + var $count = this.$el.find('.chat-head-message-count'); + var count = parseInt($count.data('count') || 0, 10) + 1; + $count.html(count).data('count', count); + if (!$count.is(':visible')) { $count.show('fast'); } + return this; + }, + showMessage: function (msg_dict) { - var $el = this.$el.find('.chat-content'), - msg_date = msg_dict.time ? converse.parseISO8601(msg_dict.time) : new Date(), + var $content = this.$el.find('.chat-content'), + iso_time = msg_dict.time || converse.toISOString(new Date()), + msg_date = converse.parseISO8601(iso_time), text = msg_dict.message, match = text.match(/^\/(.*?)(?: (.*))?$/), - fullname = msg_dict.fullname || this.model.get('fullname'), + fullname = msg_dict.fullname || this.model.get('fullname'), // XXX Perhaps always use model's? template, username; if ((match) && (match[1] === 'me')) { text = text.replace(/^\/me/, ''); - template = converse.templates.action_template; + template = converse.templates.action; username = fullname; } else { template = converse.templates.message; username = msg_dict.sender === 'me' && __('me') || fullname; } - $el.find('div.chat-event').remove(); + $content.find('div.chat-event').remove(); var message = template({ 'sender': msg_dict.sender, 'time': msg_date.toTimeString().substring(0,5), @@ -962,8 +974,11 @@ 'message': '', 'extra_classes': msg_dict.delayed && 'delayed' || '' }); - $el.append($(message).children('.chat-message-content').first().text(text).addHyperlinks().addEmoticons().parent()); - return this.scrollDown(); + $content.append($(message).children('.chat-message-content').first().text(text).addHyperlinks().addEmoticons().parent()); + if (this.model.get('minimized') && (iso_time > this.model.get('time_minimized'))) { + this.updateUnreadMessagesCounter(); + } + this.scrollDown(); }, showHelpMessages: function (msgs, type, spinner) { @@ -1284,19 +1299,26 @@ this.model.save({'minimized': false}); } else { flyout.addClass('minimized'); - this.model.save({'minimized': true}); + this.model.save({ + 'minimized': true, + 'time_minimized': converse.toISOString(new Date()) + }); } + return this; }, toggleChatBox: function (ev) { - this.$el.children('.box-flyout').attr('style', ''); + var $target = $(ev.target), $count; this.saveToggleState(); + this.$el.children('.box-flyout').attr('style', ''); this.$el.find('div.chat-body').slideToggle('fast'); - var $target = $(ev.target); if ($target.hasClass('icon-minus')) { $target.removeClass('icon-minus').addClass('icon-plus'); } else { $target.removeClass('icon-plus').addClass('icon-minus'); + $count = this.$el.find('.chat-head-message-count'); + $count.html(0).data('count', 0); + if ($count.is(':visible')) { $count.hide('fast'); } } // Toggle drag resize ability this.$el.find('.dragresize-tm').toggle(); diff --git a/mockup/minimized.html b/mockup/minimized.html index 6fd39dc2c..192270f66 100644 --- a/mockup/minimized.html +++ b/mockup/minimized.html @@ -24,7 +24,7 @@
-
3
+
3
@@ -105,7 +105,7 @@
-
42
+
42
diff --git a/spec/chatbox.js b/spec/chatbox.js index 5e6d9baf3..084e867b9 100644 --- a/spec/chatbox.js +++ b/spec/chatbox.js @@ -343,8 +343,7 @@ }, converse)); }, converse)); - // TODO: This feature is not yet implemented - xit("received for a minimized chat box will increment a counter on its header", $.proxy(function () { + it("received for a minimized chat box will increment a counter on its header", $.proxy(function () { var contact_name = mock.cur_names[0]; var contact_jid = contact_name.replace(' ','.').toLowerCase() + '@localhost'; spyOn(this, 'emit'); @@ -361,25 +360,54 @@ runs($.proxy(function () { var chatview = this.chatboxviews.get(contact_jid); expect(chatview.model.get('minimized')).toBeTruthy(); - var message = 'This message is sent to a minimized chatbox'; var sender_jid = mock.cur_names[0].replace(' ','.').toLowerCase() + '@localhost'; - msg = $msg({ - from: sender_jid, - to: this.connection.jid, - type: 'chat', - id: (new Date()).getTime() - }).c('body').t(message).up() - .c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree(); - + msg = $msg({ + from: sender_jid, + to: this.connection.jid, + type: 'chat', + id: (new Date()).getTime() + }).c('body').t(message).up() + .c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree(); this.chatboxes.onMessage(msg); expect(this.emit).toHaveBeenCalledWith('onMessage', msg); }, converse)); waits(250); runs($.proxy(function () { var chatview = this.chatboxviews.get(contact_jid); + var $count = chatview.$el.find('.chat-head-message-count'); expect(chatview.model.get('minimized')).toBeTruthy(); - expect(chatview.$el.find('.chat-head-message-count').length).toBe(1); + expect($count.is(':visible')).toBeTruthy(); + expect($count.data('count')).toBe(1); + expect($count.html()).toBe('1'); + this.chatboxes.onMessage( + $msg({ + from: mock.cur_names[0].replace(' ','.').toLowerCase() + '@localhost', + to: this.connection.jid, + type: 'chat', + id: (new Date()).getTime() + }).c('body').t('This message is also sent to a minimized chatbox').up() + .c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree() + ); + }, converse)); + waits(100); + runs($.proxy(function () { + var chatview = this.chatboxviews.get(contact_jid); + var $count = chatview.$el.find('.chat-head-message-count'); + expect(chatview.model.get('minimized')).toBeTruthy(); + expect($count.is(':visible')).toBeTruthy(); + expect($count.data('count')).toBe(2); + expect($count.html()).toBe('2'); + chatview.$el.find('.toggle-chatbox-button').click(); + }, converse)); + waits(250); + runs($.proxy(function () { + var chatview = this.chatboxviews.get(contact_jid); + var $count = chatview.$el.find('.chat-head-message-count'); + expect(chatview.model.get('minimized')).toBeFalsy(); + expect($count.is(':visible')).toBeFalsy(); + expect($count.data('count')).toBe(0); + expect($count.html()).toBe('0'); }, converse)); }, converse)); diff --git a/src/templates/chatbox.html b/src/templates/chatbox.html index 0b700e4fd..2e0f684a6 100644 --- a/src/templates/chatbox.html +++ b/src/templates/chatbox.html @@ -2,6 +2,7 @@ {[if (!minimized) {]} style="height: {{height}}px" {[}]}>