Commit bb0f49cf authored by JC Brand's avatar JC Brand

Add a counter to show unread msgs when chat is minimized

parent 9849daac
...@@ -672,6 +672,7 @@ form.search-xmpp-contact input { ...@@ -672,6 +672,7 @@ form.search-xmpp-contact input {
padding: 2px 10px; padding: 2px 10px;
font-size: 18px; font-size: 18px;
text-align: center; text-align: center;
display: none;
} }
.chat-head-chatroom .chat-head-message-count { .chat-head-chatroom .chat-head-message-count {
......
...@@ -655,6 +655,7 @@ ...@@ -655,6 +655,7 @@
'box_id' : hex_sha1(this.get('jid')), 'box_id' : hex_sha1(this.get('jid')),
'otr_status': this.get('otr_status') || UNENCRYPTED, 'otr_status': this.get('otr_status') || UNENCRYPTED,
'minimized': this.get('minimized') || false, 'minimized': this.get('minimized') || false,
'time_minimized': this.get('time_minimized') || converse.toISOString(new Date()),
'height': height 'height': height
}); });
} else { } else {
...@@ -892,7 +893,6 @@ ...@@ -892,7 +893,6 @@
this.model.on('showReceivedOTRMessage', function (text) { this.model.on('showReceivedOTRMessage', function (text) {
this.showMessage({'message': text, 'sender': 'them'}); this.showMessage({'message': text, 'sender': 'them'});
}, this); }, this);
this.updateVCard(); this.updateVCard();
this.$el.appendTo(converse.chatboxviews.$el); this.$el.appendTo(converse.chatboxviews.$el);
this.render().show().focus().model.messages.fetch({add: true}); this.render().show().focus().model.messages.fetch({add: true});
...@@ -938,23 +938,35 @@ ...@@ -938,23 +938,35 @@
this.scrollDown(); 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) { showMessage: function (msg_dict) {
var $el = this.$el.find('.chat-content'), var $content = this.$el.find('.chat-content'),
msg_date = msg_dict.time ? converse.parseISO8601(msg_dict.time) : new Date(), iso_time = msg_dict.time || converse.toISOString(new Date()),
msg_date = converse.parseISO8601(iso_time),
text = msg_dict.message, text = msg_dict.message,
match = text.match(/^\/(.*?)(?: (.*))?$/), 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; template, username;
if ((match) && (match[1] === 'me')) { if ((match) && (match[1] === 'me')) {
text = text.replace(/^\/me/, ''); text = text.replace(/^\/me/, '');
template = converse.templates.action_template; template = converse.templates.action;
username = fullname; username = fullname;
} else { } else {
template = converse.templates.message; template = converse.templates.message;
username = msg_dict.sender === 'me' && __('me') || fullname; username = msg_dict.sender === 'me' && __('me') || fullname;
} }
$el.find('div.chat-event').remove(); $content.find('div.chat-event').remove();
var message = template({ var message = template({
'sender': msg_dict.sender, 'sender': msg_dict.sender,
'time': msg_date.toTimeString().substring(0,5), 'time': msg_date.toTimeString().substring(0,5),
...@@ -962,8 +974,11 @@ ...@@ -962,8 +974,11 @@
'message': '', 'message': '',
'extra_classes': msg_dict.delayed && 'delayed' || '' 'extra_classes': msg_dict.delayed && 'delayed' || ''
}); });
$el.append($(message).children('.chat-message-content').first().text(text).addHyperlinks().addEmoticons().parent()); $content.append($(message).children('.chat-message-content').first().text(text).addHyperlinks().addEmoticons().parent());
return this.scrollDown(); if (this.model.get('minimized') && (iso_time > this.model.get('time_minimized'))) {
this.updateUnreadMessagesCounter();
}
this.scrollDown();
}, },
showHelpMessages: function (msgs, type, spinner) { showHelpMessages: function (msgs, type, spinner) {
...@@ -1284,19 +1299,26 @@ ...@@ -1284,19 +1299,26 @@
this.model.save({'minimized': false}); this.model.save({'minimized': false});
} else { } else {
flyout.addClass('minimized'); flyout.addClass('minimized');
this.model.save({'minimized': true}); this.model.save({
'minimized': true,
'time_minimized': converse.toISOString(new Date())
});
} }
return this;
}, },
toggleChatBox: function (ev) { toggleChatBox: function (ev) {
this.$el.children('.box-flyout').attr('style', ''); var $target = $(ev.target), $count;
this.saveToggleState(); this.saveToggleState();
this.$el.children('.box-flyout').attr('style', '');
this.$el.find('div.chat-body').slideToggle('fast'); this.$el.find('div.chat-body').slideToggle('fast');
var $target = $(ev.target);
if ($target.hasClass('icon-minus')) { if ($target.hasClass('icon-minus')) {
$target.removeClass('icon-minus').addClass('icon-plus'); $target.removeClass('icon-minus').addClass('icon-plus');
} else { } else {
$target.removeClass('icon-plus').addClass('icon-minus'); $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 // Toggle drag resize ability
this.$el.find('.dragresize-tm').toggle(); this.$el.find('.dragresize-tm').toggle();
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
<div class="box-flyout minimized"> <div class="box-flyout minimized">
<div class="dragresize dragresize-tm"></div> <div class="dragresize dragresize-tm"></div>
<div class="chat-head chat-head-chatbox"> <div class="chat-head chat-head-chatbox">
<div class="chat-head-message-count">3</div> <div class="chat-head-message-count" style="display:block">3</div>
<a class="close-chatbox-button icon-close"></a> <a class="close-chatbox-button icon-close"></a>
<a class="toggle-chatbox-button icon-minus"></a> <a class="toggle-chatbox-button icon-minus"></a>
<canvas height="33px" width="33px" class="avatar" style="background-color: black"></canvas> <canvas height="33px" width="33px" class="avatar" style="background-color: black"></canvas>
...@@ -105,7 +105,7 @@ ...@@ -105,7 +105,7 @@
<div class="box-flyout minimized"> <div class="box-flyout minimized">
<div class="dragresize dragresize-tm"></div> <div class="dragresize dragresize-tm"></div>
<div class="chat-head chat-head-chatroom"> <div class="chat-head chat-head-chatroom">
<div class="chat-head-message-count">42</div> <div class="chat-head-message-count" style="display:block">42</div>
<a class="close-chatbox-button icon-close"></a> <a class="close-chatbox-button icon-close"></a>
<a class="toggle-chatbox-button icon-minus"></a> <a class="toggle-chatbox-button icon-minus"></a>
<a class="configure-chatroom-button icon-wrench" style=""></a> <a class="configure-chatroom-button icon-wrench" style=""></a>
......
...@@ -343,8 +343,7 @@ ...@@ -343,8 +343,7 @@
}, converse)); }, converse));
}, converse)); }, converse));
// TODO: This feature is not yet implemented it("received for a minimized chat box will increment a counter on its header", $.proxy(function () {
xit("received for a minimized chat box will increment a counter on its header", $.proxy(function () {
var contact_name = mock.cur_names[0]; var contact_name = mock.cur_names[0];
var contact_jid = contact_name.replace(' ','.').toLowerCase() + '@localhost'; var contact_jid = contact_name.replace(' ','.').toLowerCase() + '@localhost';
spyOn(this, 'emit'); spyOn(this, 'emit');
...@@ -361,25 +360,54 @@ ...@@ -361,25 +360,54 @@
runs($.proxy(function () { runs($.proxy(function () {
var chatview = this.chatboxviews.get(contact_jid); var chatview = this.chatboxviews.get(contact_jid);
expect(chatview.model.get('minimized')).toBeTruthy(); expect(chatview.model.get('minimized')).toBeTruthy();
var message = 'This message is sent to a minimized chatbox'; var message = 'This message is sent to a minimized chatbox';
var sender_jid = mock.cur_names[0].replace(' ','.').toLowerCase() + '@localhost'; var sender_jid = mock.cur_names[0].replace(' ','.').toLowerCase() + '@localhost';
msg = $msg({ msg = $msg({
from: sender_jid, from: sender_jid,
to: this.connection.jid, to: this.connection.jid,
type: 'chat', type: 'chat',
id: (new Date()).getTime() id: (new Date()).getTime()
}).c('body').t(message).up() }).c('body').t(message).up()
.c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree(); .c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree();
this.chatboxes.onMessage(msg); this.chatboxes.onMessage(msg);
expect(this.emit).toHaveBeenCalledWith('onMessage', msg); expect(this.emit).toHaveBeenCalledWith('onMessage', msg);
}, converse)); }, converse));
waits(250); waits(250);
runs($.proxy(function () { runs($.proxy(function () {
var chatview = this.chatboxviews.get(contact_jid); 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(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(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(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));
}, converse)); }, converse));
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
{[if (!minimized) {]} style="height: {{height}}px" {[}]}> {[if (!minimized) {]} style="height: {{height}}px" {[}]}>
<div class="dragresize dragresize-tm" {[ if (minimized) { ]} style="display:none" {[ } ]}></div> <div class="dragresize dragresize-tm" {[ if (minimized) { ]} style="display:none" {[ } ]}></div>
<div class="chat-head chat-head-chatbox"> <div class="chat-head chat-head-chatbox">
<div class="chat-head-message-count">0</div>
<a class="close-chatbox-button icon-close"></a> <a class="close-chatbox-button icon-close"></a>
<a class="toggle-chatbox-button <a class="toggle-chatbox-button
{[ if (minimized) { ]} icon-plus {[ } ]} {[ if (minimized) { ]} icon-plus {[ } ]}
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
{[if (!minimized) {]} style="height: {{height}}px" {[}]}> {[if (!minimized) {]} style="height: {{height}}px" {[}]}>
<div class="dragresize dragresize-tm" {[ if (minimized) { ]} style="display:none" {[ } ]}></div> <div class="dragresize dragresize-tm" {[ if (minimized) { ]} style="display:none" {[ } ]}></div>
<div class="chat-head chat-head-chatroom"> <div class="chat-head chat-head-chatroom">
<div class="chat-head-message-count">0</div>
<a class="close-chatbox-button icon-close"></a> <a class="close-chatbox-button icon-close"></a>
<a class="toggle-chatbox-button <a class="toggle-chatbox-button
{[ if (minimized) { ]} icon-plus {[ } ]} {[ if (minimized) { ]} icon-plus {[ } ]}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment