Show unread messages counter next to roster contacts
This commit is contained in:
parent
ce16e1bcef
commit
f3d29e016e
@ -2227,7 +2227,7 @@
|
||||
z-index: 1;
|
||||
opacity: 0; }
|
||||
#conversejs #converse-roster .roster-contacts dd .open-chat.unread-msgs .avatar.avatar-online .pulse {
|
||||
border: 0.7em solid #1A9707; }
|
||||
border: 0.7em solid #2A9D8F; }
|
||||
@-webkit-keyframes pulse {
|
||||
0% {
|
||||
-webkit-transform: scale(0);
|
||||
@ -2304,7 +2304,7 @@
|
||||
font-size: 11px;
|
||||
margin-left: -3em;
|
||||
font-weight: normal;
|
||||
padding: 2px 4px;
|
||||
padding: 0 4px;
|
||||
text-shadow: none; }
|
||||
#conversejs #converse-roster .roster-contacts dd .open-chat .contact-name {
|
||||
padding: 0;
|
||||
@ -2312,16 +2312,12 @@
|
||||
max-width: 80%;
|
||||
float: none;
|
||||
height: 60px; }
|
||||
#conversejs #converse-roster .roster-contacts dd .open-chat .contact-name.unread-msgs {
|
||||
max-width: 70%; }
|
||||
#conversejs #converse-roster .roster-contacts dd .open-chat .avatar {
|
||||
float: left;
|
||||
display: inline-block;
|
||||
height: 60px; }
|
||||
#conversejs #converse-roster .roster-contacts dd .open-chat .avatar .status-icon {
|
||||
color: #2A9D8F; }
|
||||
#conversejs #converse-roster .roster-contacts dd .open-chat .avatar .status-icon.icon-online {
|
||||
color: #1A9707; }
|
||||
#conversejs #converse-roster .roster-contacts dd:hover {
|
||||
background-color: #DCF9F6; }
|
||||
#conversejs #converse-roster .roster-contacts dd:hover .remove-xmpp-contact {
|
||||
@ -2349,7 +2345,6 @@
|
||||
background-color: #DCEAC5;
|
||||
/* Make this difference */ }
|
||||
#conversejs #converse-roster .roster-contacts dd a, #conversejs #converse-roster .roster-contacts dd span {
|
||||
text-shadow: 0 1px 0 #FAFAFA;
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
|
@ -1,5 +1,11 @@
|
||||
# Changelog
|
||||
|
||||
## 3.1.0 (Unreleased)
|
||||
|
||||
- Show unread messages next to roster contacts. [jcbrand]
|
||||
- API change: the `message` event now returns a data object with `stanza` and
|
||||
`chatbox` attributes, instead of just the stanza. [jcbrand]
|
||||
|
||||
## 3.0.2 (2017-04-23)
|
||||
|
||||
*Dependency updates*:
|
||||
|
@ -144,6 +144,19 @@ The user has logged out.
|
||||
|
||||
``_converse.on('logout', function () { ... });``
|
||||
|
||||
messageAdded
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Once a message has been added to a chat box. The passed in data object contains
|
||||
a `chatbox` attribute, referring to the chat box receiving the message, as well
|
||||
as a `message` attribute which refers to the Message model.
|
||||
|
||||
.. code-block:: javascript
|
||||
_converse.on('messageAdded', function (data) {
|
||||
// The message is at `data.message`
|
||||
// The original chat box is at `data.chatbox`.
|
||||
});
|
||||
|
||||
messageSend
|
||||
~~~~~~~~~~~
|
||||
|
||||
|
@ -140,7 +140,7 @@
|
||||
}
|
||||
&.avatar-online {
|
||||
.pulse {
|
||||
border: 0.7em solid $online-color;
|
||||
border: 0.7em solid $link-color;
|
||||
}
|
||||
}
|
||||
@include keyframes(pulse) {
|
||||
@ -176,7 +176,7 @@
|
||||
font-size: 11px;
|
||||
margin-left: -3em;
|
||||
font-weight: normal;
|
||||
padding: 2px 4px;
|
||||
padding: 0 4px;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
@ -186,9 +186,6 @@
|
||||
max-width: 80%;
|
||||
float: none;
|
||||
height: $roster-item-height;
|
||||
&.unread-msgs {
|
||||
max-width: 70%;
|
||||
}
|
||||
}
|
||||
|
||||
.avatar {
|
||||
@ -198,9 +195,6 @@
|
||||
|
||||
.status-icon {
|
||||
color: $link-color;
|
||||
&.icon-online {
|
||||
color: $online-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -242,7 +236,6 @@
|
||||
/* Make this difference */
|
||||
}
|
||||
a, span {
|
||||
text-shadow: 0 1px 0 $link-shadow-color;
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
|
@ -471,6 +471,10 @@
|
||||
} else {
|
||||
this.handleTextMessage(message);
|
||||
}
|
||||
_converse.emit('messageAdded', {
|
||||
'message': message,
|
||||
'chatbox': this.model
|
||||
});
|
||||
},
|
||||
|
||||
createMessageStanza: function (message) {
|
||||
|
@ -183,9 +183,11 @@
|
||||
Strophe.addNamespace('CSI', 'urn:xmpp:csi:0');
|
||||
Strophe.addNamespace('DELAY', 'urn:xmpp:delay');
|
||||
Strophe.addNamespace('HINTS', 'urn:xmpp:hints');
|
||||
Strophe.addNamespace('MAM', 'urn:xmpp:mam:0');
|
||||
Strophe.addNamespace('NICK', 'http://jabber.org/protocol/nick');
|
||||
Strophe.addNamespace('PUBSUB', 'http://jabber.org/protocol/pubsub');
|
||||
Strophe.addNamespace('ROSTERX', 'http://jabber.org/protocol/rosterx');
|
||||
Strophe.addNamespace('RSM', 'http://jabber.org/protocol/rsm');
|
||||
Strophe.addNamespace('XFORM', 'jabber:x:data');
|
||||
|
||||
// Instance level constants
|
||||
@ -786,7 +788,8 @@
|
||||
'groups': [],
|
||||
'image_type': DEFAULT_IMAGE_TYPE,
|
||||
'image': DEFAULT_IMAGE,
|
||||
'status': ''
|
||||
'status': '',
|
||||
'num_unread': 0
|
||||
}, attributes));
|
||||
|
||||
this.on('destroy', function () { this.removeFromRoster(); }.bind(this));
|
||||
@ -1476,7 +1479,7 @@
|
||||
*/
|
||||
var original_stanza = message,
|
||||
contact_jid, forwarded, delay, from_bare_jid,
|
||||
from_resource, is_me, msgid,
|
||||
from_resource, is_me, msgid, messages,
|
||||
chatbox, resource,
|
||||
from_jid = message.getAttribute('from'),
|
||||
to_jid = message.getAttribute('to'),
|
||||
@ -1517,7 +1520,6 @@
|
||||
from_bare_jid = Strophe.getBareJidFromJid(from_jid);
|
||||
from_resource = Strophe.getResourceFromJid(from_jid);
|
||||
is_me = from_bare_jid === _converse.bare_jid;
|
||||
msgid = message.getAttribute('id');
|
||||
if (is_me) {
|
||||
// I am the sender, so this must be a forwarded message...
|
||||
contact_jid = Strophe.getBareJidFromJid(to_jid);
|
||||
@ -1526,16 +1528,16 @@
|
||||
contact_jid = from_bare_jid;
|
||||
resource = from_resource;
|
||||
}
|
||||
_converse.emit('message', original_stanza);
|
||||
// Get chat box, but only create a new one when the message has a body.
|
||||
chatbox = this.getChatBox(contact_jid, !_.isNull(message.querySelector('body')));
|
||||
if (!chatbox) {
|
||||
return true;
|
||||
}
|
||||
if (msgid && chatbox.messages.findWhere({msgid: msgid})) {
|
||||
return true; // We already have this message stored.
|
||||
}
|
||||
msgid = message.getAttribute('id');
|
||||
messages = msgid && chatbox.messages.findWhere({msgid: msgid}) || [];
|
||||
if (chatbox && _.isEmpty(messages)) {
|
||||
// Only create the message when we're sure it's not a
|
||||
// duplicate
|
||||
chatbox.createMessage(message, delay, original_stanza);
|
||||
}
|
||||
_converse.emit('message', {'stanza': original_stanza, 'chatbox': chatbox});
|
||||
return true;
|
||||
},
|
||||
|
||||
|
@ -27,9 +27,6 @@
|
||||
// XEP-0313 Message Archive Management
|
||||
var MAM_ATTRIBUTES = ['with', 'start', 'end'];
|
||||
|
||||
Strophe.addNamespace('MAM', 'urn:xmpp:mam:0');
|
||||
Strophe.addNamespace('RSM', 'http://jabber.org/protocol/rsm');
|
||||
|
||||
converse.plugins.add('converse-mam', {
|
||||
|
||||
overrides: {
|
||||
|
@ -1952,7 +1952,10 @@
|
||||
this.model.createMessage(message, delay, original_stanza);
|
||||
if (sender !== this.model.get('nick')) {
|
||||
// We only emit an event if it's not our own message
|
||||
_converse.emit('message', original_stanza);
|
||||
_converse.emit(
|
||||
'message',
|
||||
{'stanza': original_stanza, 'chatbox': this.model}
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -231,10 +231,11 @@
|
||||
}
|
||||
};
|
||||
|
||||
_converse.handleMessageNotification = function (message) {
|
||||
_converse.handleMessageNotification = function (data) {
|
||||
/* Event handler for the on('message') event. Will call methods
|
||||
* to play sounds and show HTML5 notifications.
|
||||
*/
|
||||
var message = data.stanza;
|
||||
if (!_converse.shouldNotifyOfMessage(message)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -30,6 +30,7 @@
|
||||
Strophe = converse.env.Strophe,
|
||||
$iq = converse.env.$iq,
|
||||
b64_sha1 = converse.env.b64_sha1,
|
||||
sizzle = converse.env.sizzle,
|
||||
_ = converse.env._;
|
||||
|
||||
|
||||
@ -156,6 +157,7 @@
|
||||
label_groups: LABEL_GROUPS,
|
||||
label_state: __('State'),
|
||||
label_any: __('Any'),
|
||||
label_unread_messages: __('Unread'),
|
||||
label_online: __('Online'),
|
||||
label_chatty: __('Chatty'),
|
||||
label_busy: __('Busy'),
|
||||
@ -279,6 +281,8 @@
|
||||
_converse.on('rosterGroupsFetched', this.positionFetchedGroups, this);
|
||||
_converse.on('rosterContactsFetched', this.update, this);
|
||||
this.createRosterFilter();
|
||||
|
||||
|
||||
},
|
||||
|
||||
render: function () {
|
||||
@ -622,17 +626,25 @@
|
||||
));
|
||||
} else if (subscription === 'both' || subscription === 'to') {
|
||||
this.el.classList.add('current-xmpp-contact');
|
||||
this.$el.removeClass(_.without(['both', 'to'], subscription)[0]).addClass(subscription);
|
||||
this.el.classList.remove(_.without(['both', 'to'], subscription)[0])
|
||||
this.el.classList.add(subscription);
|
||||
this.renderRosterItem(item);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
renderRosterItem: function (item) {
|
||||
var chat_status = item.get('chat_status');
|
||||
this.$el.html(tpl_roster_item(
|
||||
_.extend(item.toJSON(), {
|
||||
'desc_status': STATUSES[chat_status||'offline'],
|
||||
'desc_chat': __('Click to chat with this contact'),
|
||||
'desc_remove': __('Click to remove this contact'),
|
||||
'title_fullname': __('Name'),
|
||||
'allow_contact_removal': _converse.allow_contact_removal
|
||||
'allow_contact_removal': _converse.allow_contact_removal,
|
||||
'num_unread': item.get('num_unread') || 0
|
||||
})
|
||||
));
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
@ -677,6 +689,7 @@
|
||||
|
||||
openChat: function (ev) {
|
||||
if (ev && ev.preventDefault) { ev.preventDefault(); }
|
||||
this.model.save({'num_unread': 0});
|
||||
return _converse.chatboxviews.showChat(this.model.attributes);
|
||||
},
|
||||
|
||||
@ -829,6 +842,8 @@
|
||||
return utils.contains.not('chat_status', q)(contact) && !contact.get('requesting');
|
||||
}
|
||||
);
|
||||
} else if (q === 'unread_messages') {
|
||||
matches = this.model.contacts.filter({'num_unread': 0});
|
||||
} else {
|
||||
matches = this.model.contacts.filter(
|
||||
utils.contains.not('chat_status', q)
|
||||
@ -918,6 +933,32 @@
|
||||
|
||||
/* -------- Event Handlers ----------- */
|
||||
|
||||
var onMessageReceived = function (data) {
|
||||
/* Given a newly received message, update the unread counter on
|
||||
* the relevant roster contact (TODO: or chat room).
|
||||
*/
|
||||
var chatbox = data.chatbox;
|
||||
if (_.isUndefined(chatbox)) {
|
||||
return;
|
||||
}
|
||||
if (_.isNull(data.stanza.querySelector('body'))) {
|
||||
return; // The message has no text
|
||||
}
|
||||
var new_message = !(sizzle('result[xmlns="'+Strophe.NS.MAM+'"]', data.stanza).length);
|
||||
var hidden_or_minimized_chatbox = chatbox.get('hidden') || chatbox.get('minimized');
|
||||
|
||||
if (hidden_or_minimized_chatbox && new_message) {
|
||||
if (chatbox.get('type') === 'chatroom') {
|
||||
// TODO
|
||||
} else {
|
||||
var contact = _.head(_converse.roster.where({'jid': chatbox.get('jid')}));
|
||||
if (!_.isUndefined(contact)) {
|
||||
contact.save({'num_unread': contact.get('num_unread') + 1});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var initRoster = function () {
|
||||
/* Create an instance of RosterView once the RosterGroups
|
||||
* collection has been created (in converse-core.js)
|
||||
@ -927,8 +968,9 @@
|
||||
});
|
||||
_converse.rosterview.render();
|
||||
};
|
||||
_converse.on('rosterInitialized', initRoster);
|
||||
_converse.on('rosterReadyAfterReconnection', initRoster);
|
||||
_converse.api.listen.on('rosterInitialized', initRoster);
|
||||
_converse.api.listen.on('rosterReadyAfterReconnection', initRoster);
|
||||
_converse.api.listen.on('message', onMessageReceived);
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
@ -4,6 +4,8 @@
|
||||
{[ if (filter_type === 'state') { ]} style="display: none" {[ } ]} >
|
||||
<select class="state-type" {[ if (filter_type !== 'state') { ]} style="display: none" {[ } ]} >
|
||||
<option value="">{{label_any}}</option>
|
||||
<option {[ if (chat_state === 'unread_messages') { ]} selected="selected" {[ } ]}
|
||||
value="unread_messages">{{label_unread_messages}}</option>
|
||||
<option {[ if (chat_state === 'online') { ]} selected="selected" {[ } ]}
|
||||
value="online">{{label_online}}</option>
|
||||
<option {[ if (chat_state === 'chat') { ]} selected="selected" {[ } ]}
|
||||
|
Loading…
Reference in New Issue
Block a user