diff --git a/Changelog.md b/Changelog.md index f09eae8f1..125fba639 100644 --- a/Changelog.md +++ b/Changelog.md @@ -37,6 +37,7 @@ Ruby 2.0 is no longer officially supported. * Hide post title of limited post in comment notification email [#5843](https://github.com/diaspora/diaspora/pull/5843) * More and better environment checks in script/server [#5891](https://github.com/diaspora/diaspora/pull/5891) * Enable aspect sorting again [#5559](https://github.com/diaspora/diaspora/pull/5559) +* Submit messages in conversations with Ctrl+Enter [#5910](https://github.com/diaspora/diaspora/pull/5910) # 0.5.0.0 diff --git a/app/assets/javascripts/app/views/conversations_form_view.js b/app/assets/javascripts/app/views/conversations_form_view.js index 30cec16d9..d1d2a3e32 100644 --- a/app/assets/javascripts/app/views/conversations_form_view.js +++ b/app/assets/javascripts/app/views/conversations_form_view.js @@ -2,11 +2,15 @@ app.views.ConversationsForm = Backbone.View.extend({ + events: { + "keydown textarea#conversation_text" : "keyDown", + }, + initialize: function(opts) { - this.contacts = _.has(opts, 'contacts') ? opts.contacts : null; + this.contacts = _.has(opts, "contacts") ? opts.contacts : null; this.prefill = []; - if (_.has(opts, 'prefillName') && _.has(opts, 'prefillValue')) { - this.prefill = [{name : opts.prefillName, + if (_.has(opts, "prefillName") && _.has(opts, "prefillValue")) { + this.prefill = [{name : opts.prefillName, value : opts.prefillValue}]; } this.autocompleteInput = $("#contact_autocomplete"); @@ -22,9 +26,15 @@ app.views.ConversationsForm = Backbone.View.extend({ minChars: 1, keyDelay: 0, startText: '', - emptyText: Diaspora.I18n.t('no_results'), - preFill: this.prefill + emptyText: Diaspora.I18n.t("no_results"), + preFill: this.prefill }).focus(); + }, + + keyDown : function(evt) { + if( evt.keyCode === 13 && evt.ctrlKey ) { + $(evt.target).parents("form").submit(); + } } }); // @license-end diff --git a/app/assets/javascripts/app/views/conversations_view.js b/app/assets/javascripts/app/views/conversations_view.js index e3810c1c2..cd4addf41 100644 --- a/app/assets/javascripts/app/views/conversations_view.js +++ b/app/assets/javascripts/app/views/conversations_view.js @@ -5,44 +5,54 @@ app.views.Conversations = Backbone.View.extend({ el: "#conversations_container", events: { + "keydown textarea#message_text" : "keyDown", "conversation:loaded" : "setupConversation" }, initialize: function() { - if($('#conversation_new:visible').length > 0) { - new app.views.ConversationsForm({contacts: gon.contacts}); + if($("#conversation_new:visible").length > 0) { + new app.views.ConversationsForm({ + el: $("#conversation_new"), + contacts: gon.contacts + }); } this.setupConversation(); }, setupConversation: function() { app.helpers.timeago($(this.el)); - $('.control-icons a').tooltip({placement: 'bottom'}); + $(".control-icons a").tooltip({placement: "bottom"}); - var conv = $('.conversation-wrapper .stream_element.selected'), - cBadge = $('#conversations_badge .badge_count'); + var conv = $(".conversation-wrapper .stream_element.selected"), + cBadge = $("#conversations_badge .badge_count"); - if(conv.hasClass('unread') ){ - var unreadCount = parseInt(conv.find('.unread_message_count').text(), 10); + if(conv.hasClass("unread") ){ + var unreadCount = parseInt(conv.find(".unread_message_count").text(), 10); - if(cBadge.text() !== '') { + if(cBadge.text() !== "") { cBadge.text().replace(/\d+/, function(num){ num = parseInt(num, 10) - unreadCount; if(num > 0) { cBadge.text(num); } else { - cBadge.text(0).addClass('hidden'); + cBadge.text(0).addClass("hidden"); } }); } - conv.removeClass('unread'); - conv.find('.unread_message_count').remove(); + conv.removeClass("unread"); + conv.find(".unread_message_count").remove(); - var pos = $('#first_unread').offset().top - 50; + var pos = $("#first_unread").offset().top - 50; $("html").animate({scrollTop:pos}); } else { $("html").animate({scrollTop:0}); } + }, + + keyDown : function(evt) { + if( evt.keyCode === 13 && evt.ctrlKey ) { + $(evt.target).parents("form").submit(); + } } }); // @license-end diff --git a/features/desktop/conversations.feature b/features/desktop/conversations.feature index 2737aef71..b9fc82d28 100644 --- a/features/desktop/conversations.feature +++ b/features/desktop/conversations.feature @@ -24,3 +24,15 @@ Feature: private conversations And I should have 1 email delivery When I reply with "hey, how you doing?" Then I should see "hey, how you doing?" within ".stream_container" + + Scenario: send a message using keyboard shortcuts + Given I send a message with subject "Greetings" and text "hello, alice!" to "Alice Awesome" using keyboard shortcuts + Then I should see "Greetings" within "#conversation_inbox" + And I should see "Greetings" within "#conversation_show" + And "Alice Awesome" should be part of active conversation + And I should see "hello, alice!" within ".stream_container" + When I reply with "hey, how you doing?" using keyboard shortcuts + Then I should see "hey, how you doing?" within ".stream_container" + When I sign in as "alice@alice.alice" + Then I should have 2 unread private messages + And I should have 2 email delivery diff --git a/features/step_definitions/conversations_steps.rb b/features/step_definitions/conversations_steps.rb index 586f799d5..8f5a78d99 100644 --- a/features/step_definitions/conversations_steps.rb +++ b/features/step_definitions/conversations_steps.rb @@ -19,6 +19,17 @@ Then /^I send a message with subject "([^"]*)" and text "([^"]*)" to "([^"]*)"$/ end end +Then /^I send a message with subject "([^"]*)" and text "([^"]*)" to "([^"]*)" using keyboard shortcuts$/ do |subject, text, person| + step %(I am on the conversations page) + within("#conversation_new", match: :first) do + step %(I fill in "contact_autocomplete" with "#{person}") + step %(I press the first ".as-result-item" within ".as-results") + step %(I fill in "conversation_subject" with "#{subject}") + step %(I fill in "conversation_text" with "#{text}") + find("#conversation_text").native.send_keys :control, :return + end +end + When /^I reply with "([^"]*)"$/ do |text| step %(I am on the conversations page) step %(I press the first ".conversation" within ".conversations") @@ -26,6 +37,13 @@ When /^I reply with "([^"]*)"$/ do |text| step %(I press "Reply") end +When /^I reply with "([^"]*)" using keyboard shortcuts$/ do |text| + step %(I am on the conversations page) + step %(I press the first ".conversation" within ".conversations") + step %(I fill in "message_text" with "#{text}") + find("#message_text").native.send_keys :control, :return +end + Then /^I send a mobile message with subject "([^"]*)" and text "([^"]*)" to "([^"]*)"$/ do |subject, text, person| step %(I am on the conversations page) step %(I follow "New conversation") diff --git a/spec/javascripts/app/views/comment_stream_view_spec.js b/spec/javascripts/app/views/comment_stream_view_spec.js index c9abb16f9..27cec303f 100644 --- a/spec/javascripts/app/views/comment_stream_view_spec.js +++ b/spec/javascripts/app/views/comment_stream_view_spec.js @@ -110,7 +110,7 @@ describe("app.views.CommentStream", function(){ form.submit(submitCallback); var e = $.Event("keydown", { keyCode: 13 }); - e.shiftKey = false; + e.ctrlKey = false; this.view.keyDownOnCommentBox(e); expect(submitCallback).not.toHaveBeenCalled(); diff --git a/spec/javascripts/app/views/conversations_view_spec.js b/spec/javascripts/app/views/conversations_view_spec.js index c0346cd73..898f88152 100644 --- a/spec/javascripts/app/views/conversations_view_spec.js +++ b/spec/javascripts/app/views/conversations_view_spec.js @@ -1,54 +1,76 @@ describe("app.views.Conversations", function(){ - describe('setupConversation', function() { - context('for unread conversations', function() { + describe("setupConversation", function() { + context("for unread conversations", function() { beforeEach(function() { - spec.loadFixture('conversations_unread'); + spec.loadFixture("conversations_unread"); }); - it('removes the unread class from the conversation', function() { - expect($('.conversation-wrapper > .conversation.selected')).toHaveClass('unread'); + it("removes the unread class from the conversation", function() { + expect($(".conversation-wrapper > .conversation.selected")).toHaveClass("unread"); new app.views.Conversations(); - expect($('.conversation-wrapper > .conversation.selected')).not.toHaveClass('unread'); + expect($(".conversation-wrapper > .conversation.selected")).not.toHaveClass("unread"); }); - it('removes the unread message counter from the conversation', function() { - expect($('.conversation-wrapper > .conversation.selected .unread_message_count').length).toEqual(1); + it("removes the unread message counter from the conversation", function() { + expect($(".conversation-wrapper > .conversation.selected .unread_message_count").length).toEqual(1); new app.views.Conversations(); - expect($('.conversation-wrapper > .conversation.selected .unread_message_count').length).toEqual(0); + expect($(".conversation-wrapper > .conversation.selected .unread_message_count").length).toEqual(0); }); - it('decreases the unread message count in the header', function() { - var badge = '
3
'; - $('header').append(badge); - expect($('#conversations_badge .badge_count').text().trim()).toEqual('3'); - expect($('.conversation-wrapper > .conversation.selected .unread_message_count').text().trim()).toEqual('2'); + it("decreases the unread message count in the header", function() { + var badge = "
3
"; + $("header").append(badge); + expect($("#conversations_badge .badge_count").text().trim()).toEqual("3"); + expect($(".conversation-wrapper > .conversation.selected .unread_message_count").text().trim()).toEqual("2"); new app.views.Conversations(); - expect($('#conversations_badge .badge_count').text().trim()).toEqual('1'); + expect($("#conversations_badge .badge_count").text().trim()).toEqual("1"); }); - it('removes the badge_count in the header if there are no unread messages left', function() { - var badge = '
2
'; - $('header').append(badge); - expect($('#conversations_badge .badge_count').text().trim()).toEqual('2'); - expect($('.conversation-wrapper > .conversation.selected .unread_message_count').text().trim()).toEqual('2'); + it("removes the badge_count in the header if there are no unread messages left", function() { + var badge = "
2
"; + $("header").append(badge); + expect($("#conversations_badge .badge_count").text().trim()).toEqual("2"); + expect($(".conversation-wrapper > .conversation.selected .unread_message_count").text().trim()).toEqual("2"); new app.views.Conversations(); - expect($('#conversations_badge .badge_count').text().trim()).toEqual('0'); - expect($('#conversations_badge .badge_count')).toHaveClass('hidden'); + expect($("#conversations_badge .badge_count").text().trim()).toEqual("0"); + expect($("#conversations_badge .badge_count")).toHaveClass("hidden"); }); }); - context('for read conversations', function() { + context("for read conversations", function() { beforeEach(function() { - spec.loadFixture('conversations_read'); + spec.loadFixture("conversations_read"); }); - it('does not change the badge_count in the header', function() { - var badge = '
3
'; - $('header').append(badge); - expect($('#conversations_badge .badge_count').text().trim()).toEqual('3'); + it("does not change the badge_count in the header", function() { + var badge = "
3
"; + $("header").append(badge); + expect($("#conversations_badge .badge_count").text().trim()).toEqual("3"); new app.views.Conversations(); - expect($('#conversations_badge .badge_count').text().trim()).toEqual('3'); + expect($("#conversations_badge .badge_count").text().trim()).toEqual("3"); }); }); }); + + describe("keyDown", function(){ + beforeEach(function() { + this.submitCallback = jasmine.createSpy().and.returnValue(false); + spec.loadFixture("conversations_read"); + new app.views.Conversations(); + }); + + it("should submit the form with ctrl+enter", function(){ + $("form#new_message").submit(this.submitCallback); + var e = $.Event("keydown", { keyCode: 13, ctrlKey: true }); + $("textarea#message_text").trigger(e); + expect(this.submitCallback).toHaveBeenCalled(); + }); + + it("shouldn't submit the form without the ctrl key", function(){ + $("form#new_message").submit(this.submitCallback); + var e = $.Event("keydown", { keyCode: 13, ctrlKey: false }); + $("textarea#message_text").trigger(e); + expect(this.submitCallback).not.toHaveBeenCalled(); + }); + }); });