diff --git a/app/assets/javascripts/app/views/comment_mention_view.js b/app/assets/javascripts/app/views/comment_mention_view.js new file mode 100644 index 0000000000000000000000000000000000000000..52b1257743ce036ba96328e225add8608fbb7083 --- /dev/null +++ b/app/assets/javascripts/app/views/comment_mention_view.js @@ -0,0 +1,10 @@ +// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later +//= require ./publisher/mention_view + +app.views.CommentMention = app.views.PublisherMention.extend({ + initialize: function(opts) { + opts.url = Routes.mentionablePost(opts.postId); + app.views.PublisherMention.prototype.initialize.call(this, opts); + } +}); +// @license-end diff --git a/app/assets/javascripts/app/views/comment_stream_view.js b/app/assets/javascripts/app/views/comment_stream_view.js index 05ba192db154a00171dadac589a5772cbf1a166f..c6374a30185ca542a06ee2a0a3340437c821a306 100644 --- a/app/assets/javascripts/app/views/comment_stream_view.js +++ b/app/assets/javascripts/app/views/comment_stream_view.js @@ -27,6 +27,7 @@ app.views.CommentStream = app.views.Base.extend({ this.model.comments.each(this.appendComment, this); this.commentBox = this.$(".comment_box"); this.commentSubmitButton = this.$("input[name='commit']"); + new app.views.CommentMention({el: this.$el, postId: this.model.get("id")}); }, presenter: function(){ diff --git a/app/assets/javascripts/app/views/publisher/mention_view.js b/app/assets/javascripts/app/views/publisher/mention_view.js index f30779c707baf283665097ced627ca36c9fa5767..bf15dc85e345c7f5238226c3f6684f2e8725db28 100644 --- a/app/assets/javascripts/app/views/publisher/mention_view.js +++ b/app/assets/javascripts/app/views/publisher/mention_view.js @@ -6,15 +6,16 @@ app.views.PublisherMention = app.views.SearchBase.extend({ mentionSyntaxTemplate: function(person) { return "@{" + person.handle + "}"; }, events: { - "keydown #status_message_text": "onInputBoxKeyDown", - "input #status_message_text": "updateTypeaheadInput", - "click #status_message_text": "onInputBoxClick", - "blur #status_message_text": "onInputBoxBlur" + "keydown .mention-textarea": "onInputBoxKeyDown", + "input .mention-textarea": "updateTypeaheadInput", + "click .mention-textarea": "onInputBoxClick", + "blur .mention-textarea": "onInputBoxBlur" }, - initialize: function() { + initialize: function(opts) { this.mentionedPeople = []; - this.inputBox = this.$("#status_message_text"); + var url = (opts && opts.url) || "/contacts"; + this.inputBox = this.$(".mention-textarea"); this.typeaheadInput = this.$(".typeahead-mention-box"); this.bindTypeaheadEvents(); @@ -22,7 +23,7 @@ app.views.PublisherMention = app.views.SearchBase.extend({ typeaheadInput: this.typeaheadInput, customSearch: true, autoselect: true, - remoteRoute: {url: "/contacts"} + remoteRoute: {url: url} }); }, diff --git a/app/assets/stylesheets/comments.scss b/app/assets/stylesheets/comments.scss index 533c9cffb139e07111575072b20f6ac871f2d65c..54d5f19738c8d1e1d0e0c5899185cf2e44f196d7 100644 --- a/app/assets/stylesheets/comments.scss +++ b/app/assets/stylesheets/comments.scss @@ -46,7 +46,7 @@ .comment.new-comment-form-wrapper { padding-bottom: 0; } - .submit_button { + .submit-button { margin-top: 10px; input { float: right; @@ -60,7 +60,7 @@ } textarea.comment_box:focus, textarea.comment_box:valid, textarea.comment_box:active { border-color: $border-dark-grey; - & + .submit_button { display: block; } + ~ .submit-button { display: block; } min-height: 35px; box-shadow: none; } diff --git a/app/assets/stylesheets/mentions.scss b/app/assets/stylesheets/mentions.scss index c9af7be451ff5db4c498f696b0017b9c9c6aa073..97cd758ed811e968931fb91fb920fbafe296b6ef 100644 --- a/app/assets/stylesheets/mentions.scss +++ b/app/assets/stylesheets/mentions.scss @@ -65,3 +65,21 @@ } } } + +.typeahead-mention-box-wrap .twitter-typeahead { + left: -1px; + width: calc(100% + 2px); + + .tt-menu { + // Override inline rule of Typeahead + // If this is not overridden (`position: absolute` by default in Typeahead) then + // the box is cut when opened because of the `overflow: hidden` from parent classes of comment form styles. By + // having `position: relative` here we make it visible by inserting it in the flow. + // This has a side effect of "Comment" button move down when box is open, but it feels like the least evil. + // scss-lint:disable ImportantRule + position: relative !important; + // scss-lint:enable ImportantRule + + width: 100%; + } +} diff --git a/app/assets/stylesheets/publisher.scss b/app/assets/stylesheets/publisher.scss index 94510aed7b9036d92846a6346c5c3b8ae4ba9ab6..f95480c94e42be35af926710757dee5a15ace10d 100644 --- a/app/assets/stylesheets/publisher.scss +++ b/app/assets/stylesheets/publisher.scss @@ -19,12 +19,6 @@ .container-fluid{ padding: 0; } - .twitter-typeahead { - width: calc(100% + 2px); - - .tt-menu { width: 100%; } - } - form { margin: 0; #fileInfo { display: none !important; } @@ -245,7 +239,6 @@ } .twitter-typeahead { - left: -1px; // Override inline rule of Typeahead // scss-lint:disable ImportantRule position: absolute !important; diff --git a/app/assets/templates/comment-stream_tpl.jst.hbs b/app/assets/templates/comment-stream_tpl.jst.hbs index e7343507d976fcabb846a1790d3e370ee478d3eb..cf3bb465215213413651a25a4af7875395af9328 100644 --- a/app/assets/templates/comment-stream_tpl.jst.hbs +++ b/app/assets/templates/comment-stream_tpl.jst.hbs @@ -26,8 +26,14 @@ <div class="bd"> <form accept-charset="UTF-8" action="/posts/{{id}}/comments" class="new_comment" id="new_comment_on_{{id}}" method="post"> - <textarea class="comment_box form-control" id="comment_text_on_{{id}}" name="text" rows="1" required placeholder="{{t "stream.comment"}}" /> - <div class="submit_button"> + + <textarea class="comment_box form-control mention-textarea" + id="comment_text_on_{{id}}" name="text" rows="1" required placeholder="{{t "stream.comment"}}" /> + <div class="typeahead-mention-box-wrap"> + <input class="typeahead-mention-box hidden" type="text"> + </div> + + <div class="submit-button"> <input class="btn btn-primary" id="comment_submit_{{id}}" name="commit" type="submit" value="{{t "stream.comment"}}" /> </div> </form> diff --git a/app/views/publisher/_publisher.html.haml b/app/views/publisher/_publisher.html.haml index 9ed2ae2eeed9ea08a6866f9e9ee80959f8033f75..eda80f468c6680ad4abadea3c2c3b0cdf650f59e 100644 --- a/app/views/publisher/_publisher.html.haml +++ b/app/views/publisher/_publisher.html.haml @@ -10,12 +10,13 @@ :tabindex => 1, :placeholder => "#{t('contacts.index.start_a_conversation')}...", "data-title" => popover_with_close_html("1. " + t("shared.public_explain.share")), "data-content" => t("shared.public_explain.new_user_welcome_message"), - "class" => "form-control" + "class" => "form-control mention-textarea" - else = status.text_area :text, :rows => 2, :value => h(publisher_formatted_text), :tabindex => 1, :placeholder => "#{t('contacts.index.start_a_conversation')}...", - "class" => "form-control" - %input.typeahead-mention-box.hidden{type: "text"} + "class" => "form-control mention-textarea" + .typeahead-mention-box-wrap + %input.typeahead-mention-box.hidden{type: "text"} .container-fluid.photodropzone-container#photodropzone_container %ul#photodropzone diff --git a/features/desktop/mentions.feature b/features/desktop/mentions.feature index 000e1f963c0615009332a269753abf82cf6d7ba9..d68358b5872ed5a854c7526e54b846b3406c97ae 100644 --- a/features/desktop/mentions.feature +++ b/features/desktop/mentions.feature @@ -66,3 +66,22 @@ Feature: Mentions When I sign in as "alice@alice.alice" And I follow "Bob Jones" Then I should see "Bob Jones" + + Scenario: A user mentions another user in a comment using mention suggestions + Given following users exist: + | username | email | + | Bob Jones | bob@bob.bob | + | Alice Smith | alice@alice.alice | + And a user with email "bob@bob.bob" is connected with "alice@alice.alice" + And "alice@alice.alice" has a public post with text "check this out!" + When I sign in as "alice@alice.alice" + Then I should see "check this out!" + When I focus the comment field + And I enter "@Bob" in the comment field + Then I should see "Bob Jones" within ".tt-suggestion" + When I click on the first user in the mentions dropdown list + And I press the "A" key in the publisher + And I append "@Bob" to the publisher + Then I should not see the mentions dropdown list + When I press "Comment" + Then I should see "Bob Jones" within ".comments .comment:last-child" diff --git a/features/step_definitions/comment_steps.rb b/features/step_definitions/comment_steps.rb index 74589dddb3188d1a38bc11a3ab387dbbcdfc7073..753257d27c51c285873c88b954b0a8c06178c457 100644 --- a/features/step_definitions/comment_steps.rb +++ b/features/step_definitions/comment_steps.rb @@ -38,3 +38,7 @@ Given /^"([^"]*)" has commented a lot on "([^"]*)"$/ do |email, post_text| end end end + +When /^I enter "([^"]*)" in the comment field$/ do |comment_text| + find("textarea.comment_box.mention-textarea").native.send_keys(comment_text) +end diff --git a/spec/javascripts/app/views/comment_mention_view_spec.js b/spec/javascripts/app/views/comment_mention_view_spec.js new file mode 100644 index 0000000000000000000000000000000000000000..8de7c0f3f095ce0b9c4b8718905481c1bec20015 --- /dev/null +++ b/spec/javascripts/app/views/comment_mention_view_spec.js @@ -0,0 +1,10 @@ +describe("app.views.CommentMention", function() { + describe("initialize", function() { + it("passes correct URL to PublisherMention contructor", function() { + spyOn(app.views.PublisherMention.prototype, "initialize"); + new app.views.CommentMention({postId: 123}); + var call = app.views.PublisherMention.prototype.initialize.calls.mostRecent(); + expect(call.args[0].url).toEqual("/posts/123/mentionable"); + }); + }); +}); diff --git a/spec/javascripts/app/views/comment_stream_view_spec.js b/spec/javascripts/app/views/comment_stream_view_spec.js index ecac073332850d700b5e4a8e12e23a7874abfdc0..da6d562352e5ab704088fc1dcda88412e4e0ee0c 100644 --- a/spec/javascripts/app/views/comment_stream_view_spec.js +++ b/spec/javascripts/app/views/comment_stream_view_spec.js @@ -50,6 +50,13 @@ describe("app.views.CommentStream", function(){ expect(this.view.commentSubmitButton).toBeDefined(); expect(this.view.commentSubmitButton).toEqual(this.view.$("input[name='commit']")); }); + + it("initializes CommentMention view", function() { + spyOn(app.views.CommentMention.prototype, "initialize"); + this.view.postRenderTemplate(); + var call = app.views.CommentMention.prototype.initialize.calls.mostRecent(); + expect(call.args[0]).toEqual({el: this.view.$el, postId: this.view.model.id}); + }); }); describe("createComment", function() {