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));