diff --git a/docs/CHANGES.md b/docs/CHANGES.md
index 9503f4dcf..7f32809ea 100755
--- a/docs/CHANGES.md
+++ b/docs/CHANGES.md
@@ -2,6 +2,8 @@
## 3.0.0 (Unreleased)
- Use lodash instead of underscore.js [jcbrand]
+- Case insensitive matching of moderation commands. [jcbrand]
+- Add `/subject` as alias to `/topic` [jcbrand]
## 2.0.5 (2017-02-01)
- #743, #751, #753 Update to Strophe 1.2.12. SASL-EXTERNAL now has reduced priority, so it won't
diff --git a/spec/chatroom.js b/spec/chatroom.js
index 2aa7e0660..b8d4adb60 100644
--- a/spec/chatroom.js
+++ b/spec/chatroom.js
@@ -1151,6 +1151,43 @@
test_utils.clearBrowserStorage();
});
+ it("to set the room subject", mock.initConverse(function (converse) {
+ var sent_stanza;
+ test_utils.openChatRoom(converse, 'lounge', 'localhost', 'dummy');
+ var view = converse.chatboxviews.get('lounge@localhost');
+ spyOn(view, 'onMessageSubmitted').andCallThrough();
+ spyOn(view, 'clearChatRoomMessages');
+ spyOn(converse.connection, 'send').andCallFake(function (stanza) {
+ sent_stanza = stanza;
+ });
+ // Check the alias /topic
+ var $textarea = view.$el.find('.chat-textarea');
+ $textarea.val('/topic This is the room subject');
+ $textarea.trigger($.Event('keypress', {keyCode: 13}));
+ expect(view.onMessageSubmitted).toHaveBeenCalled();
+ expect(converse.connection.send).toHaveBeenCalled();
+ expect(sent_stanza.outerHTML).toBe(
+ ''+
+ 'This is the room subject'+
+ '');
+
+ // Check /subject
+ $textarea.val('/subject This is a new subject');
+ $textarea.trigger($.Event('keypress', {keyCode: 13}));
+ expect(sent_stanza.outerHTML).toBe(
+ ''+
+ 'This is a new subject'+
+ '');
+
+ // Check case insensitivity
+ $textarea.val('/Subject This is yet another subject');
+ $textarea.trigger($.Event('keypress', {keyCode: 13}));
+ expect(sent_stanza.outerHTML).toBe(
+ ''+
+ 'This is yet another subject'+
+ '');
+ }));
+
it("to clear messages", mock.initConverse(function (converse) {
test_utils.openChatRoom(converse, 'lounge', 'localhost', 'dummy');
var view = converse.chatboxviews.get('lounge@localhost');
@@ -1160,7 +1197,6 @@
view.$el.find('textarea.chat-textarea').trigger($.Event('keypress', {keyCode: 13}));
expect(view.onMessageSubmitted).toHaveBeenCalled();
expect(view.clearChatRoomMessages).toHaveBeenCalled();
-
}));
it("to make a user an owner", mock.initConverse(function (converse) {
diff --git a/src/converse-chatview.js b/src/converse-chatview.js
index e4a7941ab..ecc17118e 100644
--- a/src/converse-chatview.js
+++ b/src/converse-chatview.js
@@ -568,11 +568,12 @@
keyPressed: function (ev) {
/* Event handler for when a key is pressed in a chat box textarea.
*/
- var $textarea = $(ev.target), message;
+ var textarea = ev.target, message;
if (ev.keyCode === KEY.ENTER) {
ev.preventDefault();
- message = $textarea.val();
- $textarea.val('').focus();
+ message = textarea.value;
+ textarea.value = '';
+ textarea.focus();
if (message !== '') {
this.onMessageSubmitted(message);
converse.emit('messageSend', message);
diff --git a/src/converse-muc.js b/src/converse-muc.js
index df4ef5cb8..ea324a5c9 100755
--- a/src/converse-muc.js
+++ b/src/converse-muc.js
@@ -874,17 +874,18 @@
return this.sendChatRoomMessage(text);
}
var match = text.replace(/^\s*/, "").match(/^\/(.*?)(?: (.*))?$/) || [false, '', ''],
- args = match[2] && match[2].splitOnce(' ') || [];
- switch (match[1]) {
+ args = match[2] && match[2].splitOnce(' ') || [],
+ command = match[1].toLowerCase();
+ switch (command) {
case 'admin':
- if (!this.validateRoleChangeCommand(match[1], args)) { break; }
+ if (!this.validateRoleChangeCommand(command, args)) { break; }
this.setAffiliation('admin',
[{ 'jid': args[0],
'reason': args[1]
}]).fail(this.onCommandError.bind(this));
break;
case 'ban':
- if (!this.validateRoleChangeCommand(match[1], args)) { break; }
+ if (!this.validateRoleChangeCommand(command, args)) { break; }
this.setAffiliation('outcast',
[{ 'jid': args[0],
'reason': args[1]
@@ -894,44 +895,45 @@
this.clearChatRoomMessages();
break;
case 'deop':
- if (!this.validateRoleChangeCommand(match[1], args)) { break; }
+ if (!this.validateRoleChangeCommand(command, args)) { break; }
this.modifyRole(
this.model.get('jid'), args[0], 'occupant', args[1],
undefined, this.onCommandError.bind(this));
break;
case 'help':
this.showHelpMessages([
- '/admin: ' +__("Change user's affiliation to admin"),
- '/ban: ' +__('Ban user from room'),
- '/clear: ' +__('Remove messages'),
- '/deop: ' +__('Change user role to occupant'),
- '/help: ' +__('Show this menu'),
- '/kick: ' +__('Kick user from room'),
- '/me: ' +__('Write in 3rd person'),
- '/member: '+__('Grant membership to a user'),
- '/mute: ' +__("Remove user's ability to post messages"),
- '/nick: ' +__('Change your nickname'),
- '/op: ' +__('Grant moderator role to user'),
- '/owner: ' +__('Grant ownership of this room'),
- '/revoke: '+__("Revoke user's membership"),
- '/topic: ' +__('Set room topic'),
- '/voice: ' +__('Allow muted user to post messages')
+ '/admin: ' +__("Change user's affiliation to admin"),
+ '/ban: ' +__('Ban user from room'),
+ '/clear: ' +__('Remove messages'),
+ '/deop: ' +__('Change user role to occupant'),
+ '/help: ' +__('Show this menu'),
+ '/kick: ' +__('Kick user from room'),
+ '/me: ' +__('Write in 3rd person'),
+ '/member: ' +__('Grant membership to a user'),
+ '/mute: ' +__("Remove user's ability to post messages"),
+ '/nick: ' +__('Change your nickname'),
+ '/op: ' +__('Grant moderator role to user'),
+ '/owner: ' +__('Grant ownership of this room'),
+ '/revoke: ' +__("Revoke user's membership"),
+ '/subject: ' +__('Set room subject'),
+ '/topic: ' +__('Set room subject (alias for /subject)'),
+ '/voice: ' +__('Allow muted user to post messages')
]);
break;
case 'kick':
- if (!this.validateRoleChangeCommand(match[1], args)) { break; }
+ if (!this.validateRoleChangeCommand(command, args)) { break; }
this.modifyRole(
this.model.get('jid'), args[0], 'none', args[1],
undefined, this.onCommandError.bind(this));
break;
case 'mute':
- if (!this.validateRoleChangeCommand(match[1], args)) { break; }
+ if (!this.validateRoleChangeCommand(command, args)) { break; }
this.modifyRole(
this.model.get('jid'), args[0], 'visitor', args[1],
undefined, this.onCommandError.bind(this));
break;
case 'member':
- if (!this.validateRoleChangeCommand(match[1], args)) { break; }
+ if (!this.validateRoleChangeCommand(command, args)) { break; }
this.setAffiliation('member',
[{ 'jid': args[0],
'reason': args[1]
@@ -945,26 +947,27 @@
}).tree());
break;
case 'owner':
- if (!this.validateRoleChangeCommand(match[1], args)) { break; }
+ if (!this.validateRoleChangeCommand(command, args)) { break; }
this.setAffiliation('owner',
[{ 'jid': args[0],
'reason': args[1]
}]).fail(this.onCommandError.bind(this));
break;
case 'op':
- if (!this.validateRoleChangeCommand(match[1], args)) { break; }
+ if (!this.validateRoleChangeCommand(command, args)) { break; }
this.modifyRole(
this.model.get('jid'), args[0], 'moderator', args[1],
undefined, this.onCommandError.bind(this));
break;
case 'revoke':
- if (!this.validateRoleChangeCommand(match[1], args)) { break; }
+ if (!this.validateRoleChangeCommand(command, args)) { break; }
this.setAffiliation('none',
[{ 'jid': args[0],
'reason': args[1]
}]).fail(this.onCommandError.bind(this));
break;
case 'topic':
+ case 'subject':
converse.connection.send(
$msg({
to: this.model.get('jid'),
@@ -974,7 +977,7 @@
);
break;
case 'voice':
- if (!this.validateRoleChangeCommand(match[1], args)) { break; }
+ if (!this.validateRoleChangeCommand(command, args)) { break; }
this.modifyRole(
this.model.get('jid'), args[0], 'occupant', args[1],
undefined, this.onCommandError.bind(this));