diff --git a/addons/mail/static/src/js/composer.js b/addons/mail/static/src/js/composer.js index 31cba1ab60a..0238a80c123 100644 --- a/addons/mail/static/src/js/composer.js +++ b/addons/mail/static/src/js/composer.js @@ -100,24 +100,6 @@ var MentionManager = Widget.extend({ return selections; }, - proposition_navigation: function (keycode) { - var $active = this.$('.o_mention_proposition.active'); - if (keycode === $.ui.keyCode.ENTER) { // selecting proposition - $active.click(); - } else { // navigation in propositions - var $to; - if (keycode === $.ui.keyCode.DOWN) { - $to = $active.nextAll('.o_mention_proposition').first(); - } else { - $to = $active.prevAll('.o_mention_proposition').first(); - } - if ($to.length) { - $active.removeClass('active'); - $to.addClass('active'); - } - } - }, - /** * Detects if the user is currently typing a mention word * @return the search string if it is, false otherwise @@ -215,7 +197,10 @@ var MentionManager = Widget.extend({ }); }, - // Private functions + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + /** * Returns the matches (as RexExp.exec does) for the mention in the input text * @@ -269,6 +254,32 @@ var MentionManager = Widget.extend({ } return -1; }, + /** + * @private + * @param {integer} keycode + */ + _propositionNavigation: function (keycode) { + var $active = this.$('.o_mention_proposition.active'); + if (keycode === $.ui.keyCode.ENTER) { // selecting proposition + $active.click(); + } else { // navigation in propositions + var $to; + if (keycode === $.ui.keyCode.DOWN) { + $to = $active.nextAll('.o_mention_proposition').first(); + } else if (keycode === $.ui.keyCode.UP) { + $to = $active.prevAll('.o_mention_proposition').first(); + } else if (keycode === $.ui.keyCode.TAB) { + $to = $active.nextAll('.o_mention_proposition').first(); + if (!$to.length) { + $to = $active.prevAll('.o_mention_proposition').last(); + } + } + if ($to && $to.length) { + $active.removeClass('active'); + $to.addClass('active'); + } + } + }, _render_suggestions: function () { var suggestions = []; if (_.find(this.get('mention_suggestions'), _.isArray)) { @@ -583,6 +594,7 @@ var BasicComposer = Widget.extend({ // UP, DOWN: prevent moving cursor if navigation in mention propositions case $.ui.keyCode.UP: case $.ui.keyCode.DOWN: + case $.ui.keyCode.TAB: if (this.mention_manager.is_open()) { event.preventDefault(); } @@ -627,12 +639,13 @@ var BasicComposer = Widget.extend({ this.trigger_up("escape_pressed"); } break; - // ENTER, UP, DOWN: check if navigation in mention propositions + // ENTER, UP, DOWN, TAB: check if navigation in mention propositions case $.ui.keyCode.ENTER: case $.ui.keyCode.UP: case $.ui.keyCode.DOWN: + case $.ui.keyCode.TAB: if (this.mention_manager.is_open()) { - this.mention_manager.proposition_navigation(event.which); + this.mention_manager._propositionNavigation(event.which); } break; // Otherwise, check if a mention is typed diff --git a/addons/mail/static/tests/discuss_tests.js b/addons/mail/static/tests/discuss_tests.js index 3d38bae8732..7df25bad130 100644 --- a/addons/mail/static/tests/discuss_tests.js +++ b/addons/mail/static/tests/discuss_tests.js @@ -63,7 +63,7 @@ QUnit.test('basic rendering', function (assert) { }); QUnit.test('@ mention in channel', function (assert) { - assert.expect(12); + assert.expect(34); var done = assert.async(); // Remove throttles to speed up the test @@ -96,7 +96,11 @@ QUnit.test('@ mention in channel', function (assert) { mockRPC: function (route, args) { if (args.method === 'channel_fetch_listeners') { fetchListenersDef.resolve(); - return $.when([ {id: 2, name: 'TestUser'} ]); + return $.when([ + {id: 1, name: 'Admin'}, + {id: 2, name: 'TestUser'}, + {id: 3, name: 'DemoUser'} + ]); } if (args.method === 'message_post') { var data = { @@ -138,18 +142,81 @@ QUnit.test('@ mention in channel', function (assert) { assert.strictEqual(discuss.$('.dropup.o_composer_mention_dropdown.open').length, 1, "dropup menu for partner mentions should be open"); - var $mentionProposition = discuss.$('.o_mention_proposition'); - assert.strictEqual($mentionProposition.length, 1, - "should display one partner mention proposition"); - assert.strictEqual($mentionProposition.data('id'), 2, - "partner mention should link to the correct partner id"); - assert.strictEqual($mentionProposition.find('.o_mention_name').text(), "TestUser", - "partner mention should display the correct partner name"); + var $mentionPropositions = discuss.$('.o_mention_proposition'); + assert.strictEqual($mentionPropositions.length, 3, + "should display 3 partner mention propositions"); - $mentionProposition.click(); + var $mention1 = $mentionPropositions.first(); + var $mention2 = $mentionPropositions.first().next(); + var $mention3 = $mentionPropositions.first().next().next(); + + // correct 1st mention proposition + assert.ok($mention1.hasClass('active'), + "first partner mention should be active"); + assert.strictEqual($mention1.data('id'), 1, + "first partner mention should link to the correct partner id"); + assert.strictEqual($mention1.find('.o_mention_name').text(), "Admin", + "first partner mention should display the correct partner name"); + // correct 2nd mention proposition + assert.notOk($mention2.hasClass('active'), + "second partner mention should not be active"); + assert.strictEqual($mention2.data('id'), 2, + "second partner mention should link to the correct partner id"); + assert.strictEqual($mention2.find('.o_mention_name').text(), "TestUser", + "second partner mention should display the correct partner name"); + // correct 3rd mention proposition + assert.notOk($mention3.hasClass('active'), + "third partner mention should not be active"); + assert.strictEqual($mention3.data('id'), 3, + "third partner mention should link to the correct partner id"); + assert.strictEqual($mention3.find('.o_mention_name').text(), "DemoUser", + "third partner mention should display the correct partner name"); + + $input.trigger($.Event('keyup', {which: $.ui.keyCode.DOWN})); + assert.notOk($mention1.hasClass('active'), + "first partner mention should not be active"); + assert.ok($mention2.hasClass('active'), + "second partner mention should be active"); + assert.notOk($mention3.hasClass('active'), + "third partner mention should not be active"); + + $input.trigger($.Event('keyup', {which: $.ui.keyCode.UP})); + assert.ok($mention1.hasClass('active'), + "first partner mention should be active"); + assert.notOk($mention2.hasClass('active'), + "second partner mention should not be active"); + assert.notOk($mention3.hasClass('active'), + "third partner mention should not be active"); + + $input.trigger($.Event('keyup', {which: $.ui.keyCode.TAB})); + assert.notOk($mention1.hasClass('active'), + "first partner mention should not be active"); + assert.ok($mention2.hasClass('active'), + "second partner mention should be active"); + assert.notOk($mention3.hasClass('active'), + "third partner mention should not be active"); + + $input.trigger($.Event('keyup', {which: $.ui.keyCode.TAB})); + assert.notOk($mention1.hasClass('active'), + "first partner mention should not be active"); + assert.notOk($mention2.hasClass('active'), + "second partner mention should not be active"); + assert.ok($mention3.hasClass('active'), + "third partner mention should be active"); + + $input.trigger($.Event('keyup', {which: $.ui.keyCode.TAB})); + assert.ok($mention1.hasClass('active'), + "first partner mention should be active"); + assert.notOk($mention2.hasClass('active'), + "second partner mention should not be active"); + assert.notOk($mention3.hasClass('active'), + "third partner mention should not be active"); + + // $mentionPropositions.find('active').click(); + $input.trigger($.Event('keyup', {which: $.ui.keyCode.ENTER})); assert.strictEqual(discuss.$('.o_mention_proposition').length, 0, - "should not have any partner mention proposition after clicking on it"); - assert.strictEqual($input.find('a').text() , "@TestUser", + "should not have any partner mention proposition after ENTER"); + assert.strictEqual($input.find('a').text() , "@Admin", "should have the correct mention link in the composer input"); // send message @@ -163,7 +230,7 @@ QUnit.test('@ mention in channel', function (assert) { assert.strictEqual(discuss.$('.o_thread_message_content a').length, 1, "should contain a link in the message content"); assert.strictEqual(discuss.$('.o_thread_message_content a').text(), - "@TestUser", "should have correct mention link in the message content"); + "@Admin", "should have correct mention link in the message content"); // Restore throttles and window.getSelection BasicComposer.prototype.MENTION_THROTTLE = mentionThrottle;