Commit e02c044a authored by JC Brand's avatar JC Brand

Refactored notification code

responsible for showing messages based on the extended presence information.

- Use DOM API instead of jQuery
- Make info messages overridable (allows also for disabling them)
- Break up large function with inline callbacks into smaller ones
parent ebc7409d
...@@ -529,7 +529,7 @@ ...@@ -529,7 +529,7 @@
expect($occupants.children().first(0).text()).toBe("oldnick"); expect($occupants.children().first(0).text()).toBe("oldnick");
expect($chat_content.find('div.chat-info').length).toBe(1); expect($chat_content.find('div.chat-info').length).toBe(1);
expect($chat_content.find('div.chat-info').html()).toBe(__(view.newNicknameMessages["210"], "oldnick")); expect($chat_content.find('div.chat-info').html()).toBe(__(converse.muc.newNicknameMessages["210"], "oldnick"));
presence = $pres().attrs({ presence = $pres().attrs({
from:'lounge@localhost/oldnick', from:'lounge@localhost/oldnick',
...@@ -549,7 +549,7 @@ ...@@ -549,7 +549,7 @@
converse.connection._dataRecv(test_utils.createRequest(presence)); converse.connection._dataRecv(test_utils.createRequest(presence));
expect($chat_content.find('div.chat-info').length).toBe(2); expect($chat_content.find('div.chat-info').length).toBe(2);
expect($chat_content.find('div.chat-info').last().html()).toBe(__(view.newNicknameMessages["303"], "newnick")); expect($chat_content.find('div.chat-info').last().html()).toBe(__(converse.muc.newNicknameMessages["303"], "newnick"));
$occupants = view.$('.occupant-list'); $occupants = view.$('.occupant-list');
expect($occupants.children().length).toBe(0); expect($occupants.children().length).toBe(0);
...@@ -569,7 +569,7 @@ ...@@ -569,7 +569,7 @@
converse.connection._dataRecv(test_utils.createRequest(presence)); converse.connection._dataRecv(test_utils.createRequest(presence));
expect($chat_content.find('div.chat-info').length).toBe(2); expect($chat_content.find('div.chat-info').length).toBe(2);
expect($chat_content.find('div.chat-info').last().html()).toBe(__(view.newNicknameMessages["303"], "newnick")); expect($chat_content.find('div.chat-info').last().html()).toBe(__(converse.muc.newNicknameMessages["303"], "newnick"));
$occupants = view.$('.occupant-list'); $occupants = view.$('.occupant-list');
expect($occupants.children().length).toBe(1); expect($occupants.children().length).toBe(1);
expect($occupants.children().first(0).text()).toBe("newnick"); expect($occupants.children().first(0).text()).toBe("newnick");
......
...@@ -79,6 +79,74 @@ ...@@ -79,6 +79,74 @@
var __ = utils.__.bind(converse); var __ = utils.__.bind(converse);
var ___ = utils.___; var ___ = utils.___;
/* http://xmpp.org/extensions/xep-0045.html
* ----------------------------------------
* 100 message Entering a room Inform user that any occupant is allowed to see the user's full JID
* 101 message (out of band) Affiliation change Inform user that his or her affiliation changed while not in the room
* 102 message Configuration change Inform occupants that room now shows unavailable members
* 103 message Configuration change Inform occupants that room now does not show unavailable members
* 104 message Configuration change Inform occupants that a non-privacy-related room configuration change has occurred
* 110 presence Any room presence Inform user that presence refers to one of its own room occupants
* 170 message or initial presence Configuration change Inform occupants that room logging is now enabled
* 171 message Configuration change Inform occupants that room logging is now disabled
* 172 message Configuration change Inform occupants that the room is now non-anonymous
* 173 message Configuration change Inform occupants that the room is now semi-anonymous
* 174 message Configuration change Inform occupants that the room is now fully-anonymous
* 201 presence Entering a room Inform user that a new room has been created
* 210 presence Entering a room Inform user that the service has assigned or modified the occupant's roomnick
* 301 presence Removal from room Inform user that he or she has been banned from the room
* 303 presence Exiting a room Inform all occupants of new room nickname
* 307 presence Removal from room Inform user that he or she has been kicked from the room
* 321 presence Removal from room Inform user that he or she is being removed from the room because of an affiliation change
* 322 presence Removal from room Inform user that he or she is being removed from the room because the room has been changed to members-only and the user is not a member
* 332 presence Removal from room Inform user that he or she is being removed from the room because of a system shutdown
*/
converse.muc = {
infoMessages: {
100: __('This room is not anonymous'),
102: __('This room now shows unavailable members'),
103: __('This room does not show unavailable members'),
104: __('Non-privacy-related room configuration has changed'),
170: __('Room logging is now enabled'),
171: __('Room logging is now disabled'),
172: __('This room is now non-anonymous'),
173: __('This room is now semi-anonymous'),
174: __('This room is now fully-anonymous'),
201: __('A new room has been created')
},
disconnectMessages: {
301: __('You have been banned from this room'),
307: __('You have been kicked from this room'),
321: __("You have been removed from this room because of an affiliation change"),
322: __("You have been removed from this room because the room has changed to members-only and you're not a member"),
332: __("You have been removed from this room because the MUC (Multi-user chat) service is being shut down.")
},
actionInfoMessages: {
/* XXX: Note the triple underscore function and not double
* underscore.
*
* This is a hack. We can't pass the strings to __ because we
* don't yet know what the variable to interpolate is.
*
* Triple underscore will just return the string again, but we
* can then at least tell gettext to scan for it so that these
* strings are picked up by the translation machinery.
*/
301: ___("<strong>%1$s</strong> has been banned"),
303: ___("<strong>%1$s</strong>'s nickname has changed"),
307: ___("<strong>%1$s</strong> has been kicked out"),
321: ___("<strong>%1$s</strong> has been removed because of an affiliation change"),
322: ___("<strong>%1$s</strong> has been removed for not being a member")
},
newNicknameMessages: {
210: ___('Your nickname has been automatically set to: <strong>%1$s</strong>'),
303: ___('Your nickname has been changed to: <strong>%1$s</strong>')
}
};
// Add Strophe Namespaces // Add Strophe Namespaces
Strophe.addNamespace('MUC_ADMIN', Strophe.NS.MUC + "#admin"); Strophe.addNamespace('MUC_ADMIN', Strophe.NS.MUC + "#admin");
Strophe.addNamespace('MUC_OWNER', Strophe.NS.MUC + "#owner"); Strophe.addNamespace('MUC_OWNER', Strophe.NS.MUC + "#owner");
...@@ -977,130 +1045,103 @@ ...@@ -977,130 +1045,103 @@
this.$('.chatroom-body').append($('<p>'+msg+'</p>')); this.$('.chatroom-body').append($('<p>'+msg+'</p>'));
}, },
/* http://xmpp.org/extensions/xep-0045.html getMessageFromStatus: function (stat, is_self, from_nick, item) {
* ---------------------------------------- var code = stat.getAttribute('code');
* 100 message Entering a room Inform user that any occupant is allowed to see the user's full JID if (is_self && code === "210") {
* 101 message (out of band) Affiliation change Inform user that his or her affiliation changed while not in the room return __(converse.muc.newNicknameMessages[code], from_nick);
* 102 message Configuration change Inform occupants that room now shows unavailable members } else if (is_self && code === "303") {
* 103 message Configuration change Inform occupants that room now does not show unavailable members return __(converse.muc.newNicknameMessages[code], item.getAttribute('nick'));
* 104 message Configuration change Inform occupants that a non-privacy-related room configuration change has occurred } else if (!is_self && (code in converse.muc.actionInfoMessages)) {
* 110 presence Any room presence Inform user that presence refers to one of its own room occupants return __(converse.muc.actionInfoMessages[code], from_nick);
* 170 message or initial presence Configuration change Inform occupants that room logging is now enabled } else if (code in converse.muc.infoMessages) {
* 171 message Configuration change Inform occupants that room logging is now disabled return converse.muc.infoMessages[code];
* 172 message Configuration change Inform occupants that the room is now non-anonymous } else if (code !== '110') {
* 173 message Configuration change Inform occupants that the room is now semi-anonymous if (stat.textContent) {
* 174 message Configuration change Inform occupants that the room is now fully-anonymous // Sometimes the status contains human readable text and not a code.
* 201 presence Entering a room Inform user that a new room has been created return stat.textContent;
* 210 presence Entering a room Inform user that the service has assigned or modified the occupant's roomnick }
* 301 presence Removal from room Inform user that he or she has been banned from the room }
* 303 presence Exiting a room Inform all occupants of new room nickname return;
* 307 presence Removal from room Inform user that he or she has been kicked from the room
* 321 presence Removal from room Inform user that he or she is being removed from the room because of an affiliation change
* 322 presence Removal from room Inform user that he or she is being removed from the room because the room has been changed to members-only and the user is not a member
* 332 presence Removal from room Inform user that he or she is being removed from the room because of a system shutdown
*/
infoMessages: {
100: __('This room is not anonymous'),
102: __('This room now shows unavailable members'),
103: __('This room does not show unavailable members'),
104: __('Non-privacy-related room configuration has changed'),
170: __('Room logging is now enabled'),
171: __('Room logging is now disabled'),
172: __('This room is now non-anonymous'),
173: __('This room is now semi-anonymous'),
174: __('This room is now fully-anonymous'),
201: __('A new room has been created')
},
disconnectMessages: {
301: __('You have been banned from this room'),
307: __('You have been kicked from this room'),
321: __("You have been removed from this room because of an affiliation change"),
322: __("You have been removed from this room because the room has changed to members-only and you're not a member"),
332: __("You have been removed from this room because the MUC (Multi-user chat) service is being shut down.")
},
actionInfoMessages: {
/* XXX: Note the triple underscore function and not double
* underscore.
*
* This is a hack. We can't pass the strings to __ because we
* don't yet know what the variable to interpolate is.
*
* Triple underscore will just return the string again, but we
* can then at least tell gettext to scan for it so that these
* strings are picked up by the translation machinery.
*/
301: ___("<strong>%1$s</strong> has been banned"),
303: ___("<strong>%1$s</strong>'s nickname has changed"),
307: ___("<strong>%1$s</strong> has been kicked out"),
321: ___("<strong>%1$s</strong> has been removed because of an affiliation change"),
322: ___("<strong>%1$s</strong> has been removed for not being a member")
},
newNicknameMessages: {
210: ___('Your nickname has been automatically set to: <strong>%1$s</strong>'),
303: ___('Your nickname has been changed to: <strong>%1$s</strong>')
}, },
showStatusMessages: function (el, is_self) { parseXUserElement: function (x, is_self, from_nick) {
/* Check for status codes and communicate their purpose to the user. /* Parse the passed-in <x xmlns='http://jabber.org/protocol/muc#user'>
* Allow user to configure chat room if they are the owner. * element and construct a map containing relevant
* See: http://xmpp.org/registrar/mucstatus.html * information.
*/ */
var $el = $(el), i, disconnect_msgs = [], msgs = [], reasons = []; // By using querySelector, we assume here there is one
// <item> per <x xmlns='http://jabber.org/protocol/muc#user'>
$el.find('x[xmlns="'+Strophe.NS.MUC_USER+'"]').each(function (idx, x) { // element. This appears to be a safe assumption, since
var $item = $(x).find('item'); // each <x/> element pertains to a single user.
if (Strophe.getBareJidFromJid($item.attr('jid')) === converse.bare_jid && $item.attr('affiliation') === 'owner') { var item = x.querySelector('item');
// Show the configure button if user is the room owner.
var jid = item.getAttribute('jid');
var affiliation = item.getAttribute('affiliation');
if (Strophe.getBareJidFromJid(jid) === converse.bare_jid && affiliation === 'owner') {
this.$el.find('a.configure-chatroom-button').show(); this.$el.find('a.configure-chatroom-button').show();
} }
$(x).find('item reason').each(function (idx, reason) { // Extract notification messages, reasons and
if ($(reason).text()) { // disconnection messages from the <x/> node.
reasons.push($(reason).text()); var statuses = x.querySelectorAll('status');
var mapper = _.partial(this.getMessageFromStatus, _, is_self, from_nick, item);
var notification = {
'messages': _.reject(_.map(statuses, mapper), _.isUndefined),
};
var reason = item.querySelector('reason');
if (reason) {
notification.reason = reason ? reason.textContent : undefined;
} }
}); var actor = item.querySelector('actor');
$(x).find('status').each(function (idx, stat) { if (actor) {
var code = stat.getAttribute('code'); notification.actor = actor ? actor.getAttribute('nick') : undefined;
var from_nick = Strophe.unescapeNode(Strophe.getResourceFromJid($el.attr('from')));
if (is_self && code === "210") {
msgs.push(__(this.newNicknameMessages[code], from_nick));
} else if (is_self && code === "303") {
msgs.push(__(this.newNicknameMessages[code], $item.attr('nick')));
} else if (is_self && _.contains(_.keys(this.disconnectMessages), code)) {
disconnect_msgs.push(this.disconnectMessages[code]);
} else if (!is_self && _.contains(_.keys(this.actionInfoMessages), code)) {
msgs.push(__(this.actionInfoMessages[code], from_nick));
} else if (_.contains(_.keys(this.infoMessages), code)) {
msgs.push(this.infoMessages[code]);
} else if (code !== '110') {
if ($(stat).text()) {
msgs.push($(stat).text()); // Sometimes the status contains human readable text and not a code.
} }
var codes = _.map(statuses, function (stat) { return stat.getAttribute('code'); });
var disconnection_codes = _.intersection(codes, _.keys(converse.muc.disconnectMessages));
var disconnected = is_self && disconnection_codes.length > 0;
if (disconnected) {
notification.disconnected = true;
notification.disconnection_message = converse.muc.disconnectMessages[disconnection_codes[0]];
} }
}.bind(this)); return notification;
}.bind(this)); },
if (disconnect_msgs.length > 0) { displayNotificationsforUser: function (notification) {
for (i=0; i<disconnect_msgs.length; i++) { /* Given the notification object generated by
this.showDisconnectMessage(disconnect_msgs[i]); * parseXUserElement, display any relevant messages and
} * information to the user.
for (i=0; i<reasons.length; i++) { */
this.showDisconnectMessage(__('The reason given is: "'+reasons[i]+'"'), true); var that = this;
if (notification.disconnected) {
this.showDisconnectMessage(notification.disconnection_message);
if (notification.reason) {
this.showDisconnectMessage(__('The reason given is: "'+notification.reason+'"'), true);
} }
this.model.set('connection_status', Strophe.Status.DISCONNECTED); this.model.set('connection_status', Strophe.Status.DISCONNECTED);
return; return;
} }
for (i=0; i<msgs.length; i++) { _.each(notification.messages, function (message) {
this.$content.append(converse.templates.info({message: msgs[i]})); that.$content.append(converse.templates.info({'message': message}));
} });
for (i=0; i<reasons.length; i++) { if (notification.reason) {
this.showStatusNotification(__('The reason given is: "'+reasons[i]+'"'), true); this.showStatusNotification(__('The reason given is: "'+notification.reason+'"'), true);
} }
if (disconnect_msgs.length || msgs.length || reasons.length) { if (notification.messages.length) {
this.scrollDown(); this.scrollDown();
} }
return el; },
showStatusMessages: function (presence, is_self) {
/* Check for status codes and communicate their purpose to the user.
* Allows user to configure chat room if they are the owner.
* See: http://xmpp.org/registrar/mucstatus.html
*/
var from_nick = Strophe.unescapeNode(Strophe.getResourceFromJid(presence.getAttribute('from')));
var notifications = _.map(
presence.querySelectorAll('x[xmlns="'+Strophe.NS.MUC_USER+'"]'),
_.partial(this.parseXUserElement.bind(this), _, is_self, from_nick)
);
_.each(notifications, this.displayNotificationsforUser.bind(this));
return presence;
}, },
showErrorMessage: function (presence) { showErrorMessage: function (presence) {
......
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