From 408645cccc03201c2a1504e9e1211a0fc0469447 Mon Sep 17 00:00:00 2001 From: Steffen van Bergerem Date: Mon, 30 Jan 2017 12:14:25 +0100 Subject: [PATCH 1/8] Use new mention syntax in the publisher --- app/assets/javascripts/app/views/publisher/mention_view.js | 2 +- spec/javascripts/app/views/publisher_mention_view_spec.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/app/views/publisher/mention_view.js b/app/assets/javascripts/app/views/publisher/mention_view.js index 86b3b07aa..f732c0247 100644 --- a/app/assets/javascripts/app/views/publisher/mention_view.js +++ b/app/assets/javascripts/app/views/publisher/mention_view.js @@ -6,7 +6,7 @@ app.views.PublisherMention = app.views.SearchBase.extend({ mentionRegex: /@([^@\s]+)$/, templates: { - mentionItemSyntax: _.template("@{<%= name %> ; <%= handle %>}"), + mentionItemSyntax: _.template("@{<%= handle %>}"), mentionItemHighlight: _.template("<%= name %>") }, diff --git a/spec/javascripts/app/views/publisher_mention_view_spec.js b/spec/javascripts/app/views/publisher_mention_view_spec.js index d4e9417e3..c95a3247a 100644 --- a/spec/javascripts/app/views/publisher_mention_view_spec.js +++ b/spec/javascripts/app/views/publisher_mention_view_spec.js @@ -189,7 +189,7 @@ describe("app.views.PublisherMention", function() { it("sets the correct messageText", function() { this.view.updateMessageTexts(); - expect(this.view.inputBox.data("messageText")).toBe("@user1 Text before @{user1 ; user1@pod.tld}\ntext after"); + expect(this.view.inputBox.data("messageText")).toBe("@user1 Text before @{user1@pod.tld}\ntext after"); }); it("formats overlay text to HTML", function() { @@ -468,7 +468,7 @@ describe("app.views.PublisherMention", function() { this.view.typeaheadInput.typeahead("val", "user"); this.view.typeaheadInput.typeahead("open"); this.view.$(".tt-suggestion").first().click(); - expect(this.view.getTextForSubmit()).toBe("@{user1 ; user1@pod.tld}"); + expect(this.view.getTextForSubmit()).toBe("@{user1@pod.tld}"); }); it("returns normal text if nobody has been mentioned", function() { From b3c412d38f106891b66fd0d1fc09ea1cb6467280 Mon Sep 17 00:00:00 2001 From: Steffen van Bergerem Date: Mon, 30 Jan 2017 12:50:03 +0100 Subject: [PATCH 2/8] Display mention syntax in publisher instead of username --- .../app/views/publisher/mention_view.js | 42 ++++------------ .../app/views/publisher_mention_view_spec.js | 48 +++++++++++-------- 2 files changed, 39 insertions(+), 51 deletions(-) diff --git a/app/assets/javascripts/app/views/publisher/mention_view.js b/app/assets/javascripts/app/views/publisher/mention_view.js index f732c0247..0641e2fcc 100644 --- a/app/assets/javascripts/app/views/publisher/mention_view.js +++ b/app/assets/javascripts/app/views/publisher/mention_view.js @@ -2,13 +2,8 @@ app.views.PublisherMention = app.views.SearchBase.extend({ triggerChar: "@", - invisibleChar: "\u200B", // zero width space mentionRegex: /@([^@\s]+)$/, - - templates: { - mentionItemSyntax: _.template("@{<%= handle %>}"), - mentionItemHighlight: _.template("<%= name %>") - }, + mentionSyntaxTemplate: function(person) { return "@{" + person.handle + "}"; }, events: { "keydown #status_message_fake_text": "onInputBoxKeyDown", @@ -55,8 +50,8 @@ app.views.PublisherMention = app.views.SearchBase.extend({ cleanMentionedPeople: function() { var inputText = this.inputBox.val(); this.mentionedPeople = this.mentionedPeople.filter(function(person) { - return person.name && inputText.indexOf(person.name) > -1; - }); + return person.handle && inputText.indexOf(this.mentionSyntaxTemplate(person)) > -1; + }.bind(this)); this.ignoreDiasporaIds = this.mentionedPeople.map(function(person) { return person.handle; }); }, @@ -70,39 +65,22 @@ app.views.PublisherMention = app.views.SearchBase.extend({ this.addPersonToMentions(person); this.closeSuggestions(); - messageText = messageText.substring(0, triggerCharPosition) + - this.invisibleChar + person.name + messageText.substring(caretPosition); + var mentionText = this.mentionSyntaxTemplate(person); + + messageText = messageText.substring(0, triggerCharPosition) + mentionText + messageText.substring(caretPosition); this.inputBox.val(messageText); this.updateMessageTexts(); this.inputBox.focus(); - var newCaretPosition = triggerCharPosition + person.name.length + 1; + var newCaretPosition = triggerCharPosition + mentionText.length; this.inputBox[0].setSelectionRange(newCaretPosition, newCaretPosition); }, - /** - * Replaces every combination of this.invisibleChar + mention.name by the - * correct syntax for both hidden text and visible one. - * - * For instance, the text "Hello \u200Buser1" will be tranformed to - * "Hello @{user1 ; user1@pod.tld}" in the hidden element and - * "Hello user1" in the element visible to the user. - */ updateMessageTexts: function() { - var fakeMessageText = this.inputBox.val(), - mentionBoxText = _.escape(fakeMessageText), - messageText = fakeMessageText; - - this.mentionedPeople.forEach(function(person) { - var mentionName = this.invisibleChar + person.name; - messageText = messageText.replace(mentionName, this.templates.mentionItemSyntax(person)); - var textHighlight = this.templates.mentionItemHighlight({name: _.escape(person.name)}); - mentionBoxText = mentionBoxText.replace(mentionName, textHighlight); - }, this); - + var messageText = this.inputBox.val(); this.inputBox.data("messageText", messageText); - this.mentionsBox.find(".mentions").html(mentionBoxText); + this.mentionsBox.find(".mentions").html(_.escape(messageText)); }, updateTypeaheadInput: function() { @@ -128,7 +106,7 @@ app.views.PublisherMention = app.views.SearchBase.extend({ prefillMention: function(persons) { persons.forEach(function(person) { this.addPersonToMentions(person); - var text = this.invisibleChar + person.name; + var text = this.mentionSyntaxTemplate(person); if(this.inputBox.val().length !== 0) { text = this.inputBox.val() + " " + text; } diff --git a/spec/javascripts/app/views/publisher_mention_view_spec.js b/spec/javascripts/app/views/publisher_mention_view_spec.js index c95a3247a..54e72ad90 100644 --- a/spec/javascripts/app/views/publisher_mention_view_spec.js +++ b/spec/javascripts/app/views/publisher_mention_view_spec.js @@ -7,7 +7,6 @@ describe("app.views.PublisherMention", function() { it("initializes object properties", function() { this.view = new app.views.PublisherMention({ el: "#publisher" }); expect(this.view.mentionedPeople).toEqual([]); - expect(this.view.invisibleChar).toBe("\u200B"); expect(this.view.triggerChar).toBe("@"); }); @@ -29,6 +28,17 @@ describe("app.views.PublisherMention", function() { }); }); + describe("mentionSyntaxTemplate", function() { + beforeEach(function() { + this.view = new app.views.PublisherMention({el: "#publisher"}); + this.person = {handle: "alice@pod.tld", name: "Alice Awesome"}; + }); + + it("returns the correct mention syntax", function() { + expect(this.view.mentionSyntaxTemplate(this.person)).toBe("@{alice@pod.tld}"); + }); + }); + describe("bindTypeaheadEvents", function() { beforeEach(function() { this.view = new app.views.PublisherMention({ el: "#publisher" }); @@ -92,30 +102,30 @@ describe("app.views.PublisherMention", function() { }); it("removes person from mentioned people if not mentioned anymore", function() { - this.view.addPersonToMentions({name: "user1", handle: "user1@pod.tld"}); + this.view.addPersonToMentions({name: "User Name", handle: "user1@pod.tld"}); expect(this.view.mentionedPeople.length).toBe(1); this.view.cleanMentionedPeople(); expect(this.view.mentionedPeople.length).toBe(0); }); it("removes person from ignored people if not mentioned anymore", function() { - this.view.addPersonToMentions({name: "user1", handle: "user1@pod.tld"}); + this.view.addPersonToMentions({name: "User Name", handle: "user1@pod.tld"}); expect(this.view.ignoreDiasporaIds.length).toBe(1); this.view.cleanMentionedPeople(); expect(this.view.ignoreDiasporaIds.length).toBe(0); }); it("keeps mentioned persons", function() { - this.view.addPersonToMentions({name: "user1", handle: "user1@pod.tld"}); - this.view.inputBox.val("user1"); + this.view.addPersonToMentions({name: "User Name", handle: "user1@pod.tld"}); + this.view.inputBox.val("@{user1@pod.tld}"); expect(this.view.mentionedPeople.length).toBe(1); this.view.cleanMentionedPeople(); expect(this.view.mentionedPeople.length).toBe(1); }); it("keeps mentioned persons for ignored diaspora ids", function() { - this.view.addPersonToMentions({name: "user1", handle: "user1@pod.tld"}); - this.view.inputBox.val("user1"); + this.view.addPersonToMentions({name: "User Name", handle: "user1@pod.tld"}); + this.view.inputBox.val("@{user1@pod.tld}"); expect(this.view.ignoreDiasporaIds.length).toBe(1); this.view.cleanMentionedPeople(); expect(this.view.ignoreDiasporaIds.length).toBe(1); @@ -151,20 +161,20 @@ describe("app.views.PublisherMention", function() { it("correctly formats the text", function() { this.view.onSuggestionSelection({name: "user1337", handle: "user1@pod.tld"}); - expect(this.view.inputBox.val()).toBe("@user1337 Text before \u200Buser1337 text after"); + expect(this.view.inputBox.val()).toBe("@user1337 Text before @{user1@pod.tld} text after"); }); it("replaces the correct mention", function() { this.view.inputBox.val("@user1337 123 user2 @user2 456 @user3 789"); this.view.inputBox[0].setSelectionRange(26, 26); this.view.onSuggestionSelection({name: "user23", handle: "user2@pod.tld"}); - expect(this.view.inputBox.val()).toBe("@user1337 123 user2 \u200Buser23 456 @user3 789"); + expect(this.view.inputBox.val()).toBe("@user1337 123 user2 @{user2@pod.tld} 456 @user3 789"); this.view.inputBox[0].setSelectionRange(9, 9); this.view.onSuggestionSelection({name: "user1337", handle: "user1@pod.tld"}); - expect(this.view.inputBox.val()).toBe("\u200Buser1337 123 user2 \u200Buser23 456 @user3 789"); - this.view.inputBox[0].setSelectionRange(38, 38); + expect(this.view.inputBox.val()).toBe("@{user1@pod.tld} 123 user2 @{user2@pod.tld} 456 @user3 789"); + this.view.inputBox[0].setSelectionRange(54, 54); this.view.onSuggestionSelection({name: "user32", handle: "user3@pod.tld"}); - expect(this.view.inputBox.val()).toBe("\u200Buser1337 123 user2 \u200Buser23 456 \u200Buser32 789"); + expect(this.view.inputBox.val()).toBe("@{user1@pod.tld} 123 user2 @{user2@pod.tld} 456 @{user3@pod.tld} 789"); }); it("calls updateMessageTexts", function() { @@ -175,7 +185,7 @@ describe("app.views.PublisherMention", function() { it("places the caret at the right position", function() { this.view.onSuggestionSelection({"name": "user1WithLongName", "handle": "user1@pod.tld"}); - var expectedCaretPosition = ("@user1337 Text before \u200Buser1WithLongName").length; + var expectedCaretPosition = ("@user1337 Text before @{user1@pod.tld}").length; expect(this.view.inputBox[0].selectionStart).toBe(expectedCaretPosition); }); }); @@ -183,7 +193,7 @@ describe("app.views.PublisherMention", function() { describe("updateMessageTexts", function() { beforeEach(function() { this.view = new app.views.PublisherMention({ el: "#publisher" }); - this.view.inputBox.val("@user1 Text before \u200Buser1\ntext after"); + this.view.inputBox.val("@user1 Text before @{user1@pod.tld}\ntext after"); this.view.mentionedPeople.push({"name": "user1", "handle": "user1@pod.tld"}); }); @@ -195,14 +205,14 @@ describe("app.views.PublisherMention", function() { it("formats overlay text to HTML", function() { this.view.updateMessageTexts(); expect(this.view.mentionsBox.find(".mentions").html()) - .toBe("@user1 Text before user1\ntext after"); + .toBe("@user1 Text before @{user1@pod.tld}\ntext after"); }); it("properly escapes the user input", function() { - this.view.inputBox.val(" @user1 Text before \u200Buser1\ntext after"); + this.view.inputBox.val(" @user1 Text before @{user1@pod.tld}\ntext after"); this.view.updateMessageTexts(); expect(this.view.mentionsBox.find(".mentions").html()) - .toBe("<img src=\"/default.png\"> @user1 Text before user1\ntext after"); + .toBe("<img src=\"/default.png\"> @user1 Text before @{user1@pod.tld}\ntext after"); }); }); @@ -264,7 +274,7 @@ describe("app.views.PublisherMention", function() { this.view.prefillMention([{"name": "user1", "handle": "user1@pod.tld"}]); expect(this.view.addPersonToMentions).toHaveBeenCalledWith({"name": "user1", "handle": "user1@pod.tld"}); expect(this.view.updateMessageTexts).toHaveBeenCalled(); - expect(this.view.inputBox.val()).toBe("\u200Buser1"); + expect(this.view.inputBox.val()).toBe("@{user1@pod.tld}"); }); it("prefills multiple mentions", function() { @@ -276,7 +286,7 @@ describe("app.views.PublisherMention", function() { expect(this.view.addPersonToMentions).toHaveBeenCalledWith({"name": "user1", "handle": "user1@pod.tld"}); expect(this.view.addPersonToMentions).toHaveBeenCalledWith({"name": "user2", "handle": "user2@pod.tld"}); expect(this.view.updateMessageTexts).toHaveBeenCalled(); - expect(this.view.inputBox.val()).toBe("\u200Buser1 \u200Buser2"); + expect(this.view.inputBox.val()).toBe("@{user1@pod.tld} @{user2@pod.tld}"); }); }); From a04f32adcecfa004433bc54cdb37f919f8dae3c6 Mon Sep 17 00:00:00 2001 From: Steffen van Bergerem Date: Mon, 30 Jan 2017 13:00:15 +0100 Subject: [PATCH 3/8] Drop mentions box in the publisher --- .../app/views/publisher/mention_view.js | 3 --- app/assets/stylesheets/mentions.scss | 24 ------------------- app/assets/stylesheets/publisher.scss | 11 --------- app/views/publisher/_publisher.html.haml | 2 -- features/desktop/follows_tags.feature | 2 +- features/step_definitions/posts_steps.rb | 4 ++++ .../app/views/publisher_mention_view_spec.js | 13 ---------- 7 files changed, 5 insertions(+), 54 deletions(-) diff --git a/app/assets/javascripts/app/views/publisher/mention_view.js b/app/assets/javascripts/app/views/publisher/mention_view.js index 0641e2fcc..d678a6bf5 100644 --- a/app/assets/javascripts/app/views/publisher/mention_view.js +++ b/app/assets/javascripts/app/views/publisher/mention_view.js @@ -18,8 +18,6 @@ app.views.PublisherMention = app.views.SearchBase.extend({ // contains the 'fake text' displayed to the user // also has a data-messageText attribute with the original text this.inputBox = this.$("#status_message_fake_text"); - // contains the mentions displayed to the user - this.mentionsBox = this.$(".mentions-box"); this.typeaheadInput = this.$(".typeahead-mention-box"); this.bindTypeaheadEvents(); @@ -80,7 +78,6 @@ app.views.PublisherMention = app.views.SearchBase.extend({ updateMessageTexts: function() { var messageText = this.inputBox.val(); this.inputBox.data("messageText", messageText); - this.mentionsBox.find(".mentions").html(_.escape(messageText)); }, updateTypeaheadInput: function() { diff --git a/app/assets/stylesheets/mentions.scss b/app/assets/stylesheets/mentions.scss index a6920e7b3..c9af7be45 100644 --- a/app/assets/stylesheets/mentions.scss +++ b/app/assets/stylesheets/mentions.scss @@ -64,28 +64,4 @@ } } } - - .mentions-box { - position: absolute; - right: 0px; - bottom: 0px; - left: 0px; - top: 0px; - padding: $padding-base-vertical $padding-base-horizontal; - } - - .mentions { - color: transparent; - font-size: $font-size-base; - font-family: Arial, Helvetica, sans-serif; - overflow: hidden; - width: 100%; - white-space: pre-wrap; - word-wrap: break-word; - - > strong { - background: $background-blue; - font-weight: normal; - } - } } diff --git a/app/assets/stylesheets/publisher.scss b/app/assets/stylesheets/publisher.scss index 51c4a494f..a08f67955 100644 --- a/app/assets/stylesheets/publisher.scss +++ b/app/assets/stylesheets/publisher.scss @@ -14,10 +14,6 @@ display: none !important; } - .mentions-box { - margin-top: 0; - } - #publisher_textarea_wrapper { border: 1px solid $border-grey !important; } } @@ -248,8 +244,6 @@ .locator { display: none; } } - &.submitting .mentions-box { display: none; } - .twitter-typeahead { left: -1px; // Override inline rule of Typeahead @@ -257,11 +251,6 @@ position: absolute !important; // scss-lint:enable ImportantRule } - - .mentions-box { - // Leave space for markdown editor header - margin-top: 42px; - } } .publisher-buttonbar { diff --git a/app/views/publisher/_publisher.html.haml b/app/views/publisher/_publisher.html.haml index 1304283a4..6fc8669cc 100644 --- a/app/views/publisher/_publisher.html.haml +++ b/app/views/publisher/_publisher.html.haml @@ -5,8 +5,6 @@ %params .publisher-textarea-wrapper#publisher_textarea_wrapper .mentions-input-box - .mentions-box - .mentions - if current_user.getting_started? = status.text_area :fake_text, :rows => 2, :value => h(publisher_formatted_text), :tabindex => 1, :placeholder => "#{t('contacts.index.start_a_conversation')}...", diff --git a/features/desktop/follows_tags.feature b/features/desktop/follows_tags.feature index 78692e71c..fcdfbf3a5 100644 --- a/features/desktop/follows_tags.feature +++ b/features/desktop/follows_tags.feature @@ -16,7 +16,7 @@ Feature: posting Then I should see a ".tag-following-action .followed" Scenario: can post a message from the tag page - Then I should see "#boss" within "#publisher" + Then I should see "#boss " in the publisher When I click the publisher and post "#boss from the tag page" And I go to the tag page for "boss" Then I should see "#boss from the tag page" diff --git a/features/step_definitions/posts_steps.rb b/features/step_definitions/posts_steps.rb index b0b8e62b1..34df49e49 100644 --- a/features/step_definitions/posts_steps.rb +++ b/features/step_definitions/posts_steps.rb @@ -32,6 +32,10 @@ Then /^I should not be able to submit the publisher$/ do expect(publisher_submittable?).to be false end +Then /^I should see "([^"]*)" in the publisher$/ do |text| + expect(page).to have_field("status_message[fake_text]", with: text) +end + Given /^I have a limited post with text "([^\"]*)" in the aspect "([^"]*)"$/ do |text, aspect_name| @me.post :status_message, text: text, to: @me.aspects.where(name: aspect_name).first.id end diff --git a/spec/javascripts/app/views/publisher_mention_view_spec.js b/spec/javascripts/app/views/publisher_mention_view_spec.js index 54e72ad90..7ab98fe78 100644 --- a/spec/javascripts/app/views/publisher_mention_view_spec.js +++ b/spec/javascripts/app/views/publisher_mention_view_spec.js @@ -201,19 +201,6 @@ describe("app.views.PublisherMention", function() { this.view.updateMessageTexts(); expect(this.view.inputBox.data("messageText")).toBe("@user1 Text before @{user1@pod.tld}\ntext after"); }); - - it("formats overlay text to HTML", function() { - this.view.updateMessageTexts(); - expect(this.view.mentionsBox.find(".mentions").html()) - .toBe("@user1 Text before @{user1@pod.tld}\ntext after"); - }); - - it("properly escapes the user input", function() { - this.view.inputBox.val(" @user1 Text before @{user1@pod.tld}\ntext after"); - this.view.updateMessageTexts(); - expect(this.view.mentionsBox.find(".mentions").html()) - .toBe("<img src=\"/default.png\"> @user1 Text before @{user1@pod.tld}\ntext after"); - }); }); describe("updateTypeaheadInput", function() { From c4b6b9534c2e07109c9b9777e46a6f4f350964f5 Mon Sep 17 00:00:00 2001 From: Steffen van Bergerem Date: Mon, 30 Jan 2017 13:19:50 +0100 Subject: [PATCH 4/8] No more fake text in the publisher --- .../app/views/publisher/mention_view.js | 13 +++++----- .../javascripts/app/views/publisher_view.js | 25 ++++--------------- .../interim_stream_hackiness_helper.rb | 10 -------- app/views/publisher/_publisher.html.haml | 5 ++-- features/desktop/post_preview.feature | 16 ++++++------ features/desktop/post_with_a_poll.feature | 16 ++++++------ features/mobile/posts_from_main_page.feature | 4 +-- .../keyboard_navigation_steps.rb | 2 +- features/step_definitions/posts_steps.rb | 6 +---- features/support/publishing_cuke_helpers.rb | 23 ++++++----------- .../app/views/bookmarklet_view_spec.js | 7 +----- .../app/views/publisher_view_spec.js | 7 ++---- 12 files changed, 43 insertions(+), 91 deletions(-) diff --git a/app/assets/javascripts/app/views/publisher/mention_view.js b/app/assets/javascripts/app/views/publisher/mention_view.js index d678a6bf5..55efafbe2 100644 --- a/app/assets/javascripts/app/views/publisher/mention_view.js +++ b/app/assets/javascripts/app/views/publisher/mention_view.js @@ -6,18 +6,17 @@ app.views.PublisherMention = app.views.SearchBase.extend({ mentionSyntaxTemplate: function(person) { return "@{" + person.handle + "}"; }, events: { - "keydown #status_message_fake_text": "onInputBoxKeyDown", - "input #status_message_fake_text": "onInputBoxInput", - "click #status_message_fake_text": "onInputBoxClick", - "blur #status_message_fake_text": "onInputBoxBlur" + "keydown #status_message_text": "onInputBoxKeyDown", + "input #status_message_text": "onInputBoxInput", + "click #status_message_text": "onInputBoxClick", + "blur #status_message_text": "onInputBoxBlur" }, initialize: function() { this.mentionedPeople = []; - // contains the 'fake text' displayed to the user - // also has a data-messageText attribute with the original text - this.inputBox = this.$("#status_message_fake_text"); + // has a data-messageText attribute with the original text + this.inputBox = this.$("#status_message_text"); this.typeaheadInput = this.$(".typeahead-mention-box"); this.bindTypeaheadEvents(); diff --git a/app/assets/javascripts/app/views/publisher_view.js b/app/assets/javascripts/app/views/publisher_view.js index de9245027..7d789f998 100644 --- a/app/assets/javascripts/app/views/publisher_view.js +++ b/app/assets/javascripts/app/views/publisher_view.js @@ -18,11 +18,11 @@ app.views.Publisher = Backbone.View.extend({ el : "#publisher", events : { - "keydown #status_message_fake_text" : "keyDown", + "keydown #status_message_text": "keyDown", "focus textarea" : "open", "submit form" : "createStatusMessage", "click #submit" : "createStatusMessage", - "textchange #status_message_fake_text": "handleTextchange", + "textchange #status_message_text": "handleTextchange", "click #locator" : "showLocation", "click #poll_creator" : "togglePollCreator", "click #hide_location" : "destroyLocation", @@ -35,8 +35,7 @@ app.views.Publisher = Backbone.View.extend({ this.disabled = false; // init shortcut references to the various elements - this.inputEl = this.$("#status_message_fake_text"); - this.hiddenInputEl = this.$("#status_message_text"); + this.inputEl = this.$("#status_message_text"); this.wrapperEl = this.$("#publisher_textarea_wrapper"); this.submitEl = this.$("input[type=submit], button#submit"); this.photozoneEl = this.$("#photodropzone"); @@ -46,14 +45,6 @@ app.views.Publisher = Backbone.View.extend({ $(window).on("beforeunload", _.bind(this._beforeUnload, this)); $(window).unload(this.clear.bind(this)); - // sync textarea content - if( this.hiddenInputEl.val() === "" ) { - this.hiddenInputEl.val( this.inputEl.val() ); - } - if( this.inputEl.val() === "" ) { - this.inputEl.val( this.hiddenInputEl.val() ); - } - // hide close and preview buttons and manage services link // in case publisher is standalone // (e.g. bookmarklet, mentions popup) @@ -175,7 +166,6 @@ app.views.Publisher = Backbone.View.extend({ // inject content into the publisher textarea setText: function(txt) { this.inputEl.val(txt); - this.hiddenInputEl.val(txt); this.prefillText = txt; this.inputEl.trigger("input"); @@ -381,11 +371,10 @@ app.views.Publisher = Backbone.View.extend({ // remove mentions this.mention.reset(); - // clear text(s) + // clear text this.inputEl.val(""); - this.hiddenInputEl.val(""); this.inputEl.trigger("keyup") - .trigger("keydown"); + .trigger("keydown"); autosize.update(this.inputEl); // remove photos @@ -421,7 +410,6 @@ app.views.Publisher = Backbone.View.extend({ // force textchange plugin to update lastValue this.inputEl.data("lastValue", ""); - this.hiddenInputEl.data("lastValue", ""); return this; }, @@ -487,10 +475,8 @@ app.views.Publisher = Backbone.View.extend({ setInputEnabled: function(bool) { if (bool) { this.inputEl.removeAttr("disabled"); - this.hiddenInputEl.removeAttr("disabled"); } else { this.inputEl.prop("disabled", true); - this.hiddenInputEl.prop("disabled", true); } }, @@ -505,7 +491,6 @@ app.views.Publisher = Backbone.View.extend({ handleTextchange: function() { this.checkSubmitAvailability(); - this.hiddenInputEl.val(this.mention.getTextForSubmit()); }, _beforeUnload: function(e) { diff --git a/app/helpers/interim_stream_hackiness_helper.rb b/app/helpers/interim_stream_hackiness_helper.rb index b531871f2..4283a8126 100644 --- a/app/helpers/interim_stream_hackiness_helper.rb +++ b/app/helpers/interim_stream_hackiness_helper.rb @@ -21,16 +21,6 @@ module InterimStreamHackinessHelper end end - def publisher_hidden_text - if params[:prefill].present? - params[:prefill] - elsif defined?(@stream) - @stream.publisher.prefill - else - nil - end - end - def from_group(post) if defined?(@stream) && params[:controller] == 'multis' @stream.post_from_group(post) diff --git a/app/views/publisher/_publisher.html.haml b/app/views/publisher/_publisher.html.haml index 6fc8669cc..9ed2ae2ee 100644 --- a/app/views/publisher/_publisher.html.haml +++ b/app/views/publisher/_publisher.html.haml @@ -6,17 +6,16 @@ .publisher-textarea-wrapper#publisher_textarea_wrapper .mentions-input-box - if current_user.getting_started? - = status.text_area :fake_text, :rows => 2, :value => h(publisher_formatted_text), + = status.text_area :text, :rows => 2, :value => h(publisher_formatted_text), :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" - else - = status.text_area :fake_text, :rows => 2, :value => h(publisher_formatted_text), + = 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"} - = status.hidden_field :text, value: h(publisher_hidden_text), class: "clear_on_submit" .container-fluid.photodropzone-container#photodropzone_container %ul#photodropzone diff --git a/features/desktop/post_preview.feature b/features/desktop/post_preview.feature index 827b36d36..d2a69b687 100644 --- a/features/desktop/post_preview.feature +++ b/features/desktop/post_preview.feature @@ -44,7 +44,7 @@ Feature: preview posts in the stream Given I expand the publisher And I attach "spec/fixtures/button.png" to the publisher When I fill in the following: - | status_message_fake_text | Look at this dog | + | status_message_text | Look at this dog | And I preview the post Then I should see a "img" within ".md-preview .stream-element .photo_attachments" And I should see "Look at this dog" within ".md-preview .stream-element" @@ -63,7 +63,7 @@ Feature: preview posts in the stream Then I should see "Samuel Beckett" When I expand the publisher And I fill in the following: - | status_message_fake_text | This preview rocks | + | status_message_text | This preview rocks | And I preview the post Then I should see "This preview rocks" in the preview And I close the publisher @@ -71,11 +71,11 @@ Feature: preview posts in the stream Scenario: preview a post with the poll Given I expand the publisher When I fill in the following: - | status_message_fake_text | I am eating yogurt | + | status_message_text | I am eating yogurt | And I click on selector "#poll_creator" When I fill in the following: - | status_message_fake_text | I am eating yogurt | - | poll_question | What kind of yogurt do you like? | + | status_message_text | I am eating yogurt | + | poll_question | What kind of yogurt do you like? | And I fill in the following for the options: | normal | | not normal | @@ -87,12 +87,12 @@ Feature: preview posts in the stream Scenario: preview a post with location Given I expand the publisher When I fill in the following: - | status_message_fake_text | I am eating yogurt | + | status_message_text | I am eating yogurt | And I allow geolocation And I click on selector "#locator" When I fill in the following: - | status_message_fake_text | I am eating yogurt | - | location_address | Some cool place | + | status_message_text | I am eating yogurt | + | location_address | Some cool place | And I preview the post Then I should see a ".near-from" within ".md-preview .stream-element" And I should see "Some cool place" within ".md-preview .stream-element .near-from" diff --git a/features/desktop/post_with_a_poll.feature b/features/desktop/post_with_a_poll.feature index b5b3a0ff8..5a27fc7ee 100644 --- a/features/desktop/post_with_a_poll.feature +++ b/features/desktop/post_with_a_poll.feature @@ -40,8 +40,8 @@ Feature: posting with a poll Given I expand the publisher And I click on selector "#poll_creator" When I fill in the following: - | status_message_fake_text | I am eating yogurt | - | poll_question | What kind of yogurt do you like? | + | status_message_text | I am eating yogurt | + | poll_question | What kind of yogurt do you like? | And I fill in the following for the options: | normal | | not normal | @@ -53,8 +53,8 @@ Feature: posting with a poll Given I expand the publisher And I click on selector "#poll_creator" When I fill in the following: - | status_message_fake_text | I am eating yogurt | - | poll_question | What kind of yogurt do you like? | + | status_message_text | I am eating yogurt | + | poll_question | What kind of yogurt do you like? | And I fill in the following for the options: | normal | | not normal | @@ -70,8 +70,8 @@ Feature: posting with a poll Given I expand the publisher And I click on selector "#poll_creator" When I fill in the following: - | status_message_fake_text | I am eating yogurt | - | poll_question | What kind of yogurt do you like? | + | status_message_text | I am eating yogurt | + | poll_question | What kind of yogurt do you like? | And I fill in the following for the options: | normal | | not normal | @@ -83,8 +83,8 @@ Feature: posting with a poll Given I expand the publisher And I click on selector "#poll_creator" When I fill in the following: - | status_message_fake_text | I am eating yogurt | - | poll_question | What kind of yogurt do you like? | + | status_message_text | I am eating yogurt | + | poll_question | What kind of yogurt do you like? | And I fill in the following for the options: | normal | | | diff --git a/features/mobile/posts_from_main_page.feature b/features/mobile/posts_from_main_page.feature index 22fb6195a..9afee520d 100644 --- a/features/mobile/posts_from_main_page.feature +++ b/features/mobile/posts_from_main_page.feature @@ -20,7 +20,7 @@ Feature: posting from the mobile main page Scenario: post and delete some text Given I visit the mobile publisher page - And I append "I am eating yogurt" to the mobile publisher + And I append "I am eating yogurt" to the publisher And I select "Unicorns" from "aspect_ids_" And I press "Share" When I go to the stream page @@ -52,7 +52,7 @@ Feature: posting from the mobile main page Scenario: back out of uploading a picture when another has been attached Given I visit the mobile publisher page - And I append "I am eating yogurt" to the mobile publisher + And I append "I am eating yogurt" to the publisher And I attach the file "spec/fixtures/button.gif" to hidden "qqfile" within "#file-upload-publisher" And I attach the file "spec/fixtures/button.png" to hidden "qqfile" within "#file-upload-publisher" And I click to delete the first uploaded photo diff --git a/features/step_definitions/keyboard_navigation_steps.rb b/features/step_definitions/keyboard_navigation_steps.rb index e0109902d..32188aff3 100644 --- a/features/step_definitions/keyboard_navigation_steps.rb +++ b/features/step_definitions/keyboard_navigation_steps.rb @@ -5,7 +5,7 @@ When /^I press the "([^\"]*)" key somewhere$/ do |key| end When /^I press the "([^\"]*)" key in the publisher$/ do |key| - find("#status_message_fake_text").native.send_key(key) + find("#status_message_text").native.send_key(key) end Then /^post (\d+) should be highlighted$/ do |position| diff --git a/features/step_definitions/posts_steps.rb b/features/step_definitions/posts_steps.rb index 34df49e49..a13779a2c 100644 --- a/features/step_definitions/posts_steps.rb +++ b/features/step_definitions/posts_steps.rb @@ -33,7 +33,7 @@ Then /^I should not be able to submit the publisher$/ do end Then /^I should see "([^"]*)" in the publisher$/ do |text| - expect(page).to have_field("status_message[fake_text]", with: text) + expect(page).to have_field("status_message[text]", with: text) end Given /^I have a limited post with text "([^\"]*)" in the aspect "([^"]*)"$/ do |text, aspect_name| @@ -118,10 +118,6 @@ When /^I append "([^"]*)" to the publisher$/ do |text| append_to_publisher(text) end -When /^I append "([^"]*)" to the mobile publisher$/ do |text| - append_to_publisher(text, '#status_message_text') -end - When /^I attach "([^"]*)" to the publisher$/ do |path| upload_file_with_publisher(path) end diff --git a/features/support/publishing_cuke_helpers.rb b/features/support/publishing_cuke_helpers.rb index 046f8e332..ff5f91d43 100644 --- a/features/support/publishing_cuke_helpers.rb +++ b/features/support/publishing_cuke_helpers.rb @@ -1,21 +1,12 @@ module PublishingCukeHelpers def write_in_publisher(txt) - fill_in 'status_message_fake_text', with: txt + fill_in "status_message_text", with: txt end - def append_to_publisher(txt, input_selector='#status_message_fake_text') - status_message_text = find("#status_message_text", visible: false).value - find(input_selector).native.send_key(" #{txt}") - - # make sure the other text field got the new contents - if input_selector == "#status_message_fake_text" - begin - expect(page).to have_selector("#status_message_text[value='#{status_message_text} #{txt}']", visible: false) - rescue RSpec::Expectations::ExpectationNotMetError - puts "Value was instead: #{find('#status_message_text', visible: false).value.inspect}" - raise - end - end + def append_to_publisher(txt) + status_message_text = find("#status_message_text").value + find("#status_message_text").native.send_key(" #{txt}") + expect(page).to have_field("status_message[text]", with: "#{status_message_text} #{txt}") end def upload_file_with_publisher(path) @@ -33,7 +24,7 @@ module PublishingCukeHelpers end def submit_publisher - txt = find("#publisher #status_message_fake_text").value + txt = find("#publisher #status_message_text").value find("#publisher .btn-primary").click # wait for the content to appear expect(find("#main_stream")).to have_content(txt) @@ -45,7 +36,7 @@ module PublishingCukeHelpers end def click_publisher - find("#status_message_fake_text").click + find("#status_message_text").click expect(find("#publisher")).to have_css(".publisher-textarea-wrapper.active") end diff --git a/spec/javascripts/app/views/bookmarklet_view_spec.js b/spec/javascripts/app/views/bookmarklet_view_spec.js index d5de57466..9d12f998c 100644 --- a/spec/javascripts/app/views/bookmarklet_view_spec.js +++ b/spec/javascripts/app/views/bookmarklet_view_spec.js @@ -29,23 +29,18 @@ describe("app.views.Bookmarklet", function() { it("prefills the publisher", function() { init_bookmarklet(test_data); - expect($.trim(app.publisher.inputEl.val())).not.toEqual(""); - expect($.trim(app.publisher.hiddenInputEl.val())).not.toEqual(""); }); it("handles dirty input well", function() { init_bookmarklet(evil_test_data); - expect($.trim(app.publisher.inputEl.val())).not.toEqual(""); - expect($.trim(app.publisher.hiddenInputEl.val())).not.toEqual(""); }); it("allows changing a prefilled publisher", function() { init_bookmarklet(test_data); app.publisher.setText(app.publisher.inputEl.val()+"A"); - - expect(app.publisher.hiddenInputEl.val()).toMatch(/.+A$/); + expect(app.publisher.inputEl.val()).toMatch(/.+A$/); }); it("keeps the publisher disabled after successful post creation", function() { diff --git a/spec/javascripts/app/views/publisher_view_spec.js b/spec/javascripts/app/views/publisher_view_spec.js index c672b33fa..a0bd9c292 100644 --- a/spec/javascripts/app/views/publisher_view_spec.js +++ b/spec/javascripts/app/views/publisher_view_spec.js @@ -82,9 +82,9 @@ describe("app.views.Publisher", function() { }); it("resets the element's height", function() { - $(this.view.el).find("#status_message_fake_text").height(100); + $(this.view.el).find("#status_message_text").height(100); this.view.close($.Event()); - expect($(this.view.el).find("#status_message_fake_text").attr("style")).not.toContain("height"); + expect($(this.view.el).find("#status_message_text").attr("style")).not.toContain("height"); }); it("calls autosize.update", function() { @@ -235,9 +235,7 @@ describe("app.views.Publisher", function() { describe('#setText', function() { it("sets the content text", function() { this.view.setText("FOO bar"); - expect(this.view.inputEl.val()).toEqual("FOO bar"); - expect(this.view.hiddenInputEl.val()).toEqual("FOO bar"); }); }); @@ -248,7 +246,6 @@ describe("app.views.Publisher", function() { expect(this.view.disabled).toBeTruthy(); expect(this.view.inputEl.prop("disabled")).toBeTruthy(); - expect(this.view.hiddenInputEl.prop("disabled")).toBeTruthy(); }); it("disables submitting", function() { From 90b379b110a9abbfe5416deffb78c2c65d49e427 Mon Sep 17 00:00:00 2001 From: Steffen van Bergerem Date: Mon, 30 Jan 2017 13:31:16 +0100 Subject: [PATCH 5/8] Drop useless data attribute for message text in publisher --- .../app/views/publisher/mention_view.js | 15 ------ .../javascripts/app/views/publisher_view.js | 2 +- .../app/views/publisher_mention_view_spec.js | 52 ------------------- 3 files changed, 1 insertion(+), 68 deletions(-) diff --git a/app/assets/javascripts/app/views/publisher/mention_view.js b/app/assets/javascripts/app/views/publisher/mention_view.js index 55efafbe2..d1c98b829 100644 --- a/app/assets/javascripts/app/views/publisher/mention_view.js +++ b/app/assets/javascripts/app/views/publisher/mention_view.js @@ -14,8 +14,6 @@ app.views.PublisherMention = app.views.SearchBase.extend({ initialize: function() { this.mentionedPeople = []; - - // has a data-messageText attribute with the original text this.inputBox = this.$("#status_message_text"); this.typeaheadInput = this.$(".typeahead-mention-box"); this.bindTypeaheadEvents(); @@ -67,18 +65,11 @@ app.views.PublisherMention = app.views.SearchBase.extend({ messageText = messageText.substring(0, triggerCharPosition) + mentionText + messageText.substring(caretPosition); this.inputBox.val(messageText); - this.updateMessageTexts(); - this.inputBox.focus(); var newCaretPosition = triggerCharPosition + mentionText.length; this.inputBox[0].setSelectionRange(newCaretPosition, newCaretPosition); }, - updateMessageTexts: function() { - var messageText = this.inputBox.val(); - this.inputBox.data("messageText", messageText); - }, - updateTypeaheadInput: function() { var messageText = this.inputBox.val(); var caretPosition = this.inputBox[0].selectionStart; @@ -107,7 +98,6 @@ app.views.PublisherMention = app.views.SearchBase.extend({ text = this.inputBox.val() + " " + text; } this.inputBox.val(text); - this.updateMessageTexts(); }, this); }, @@ -133,7 +123,6 @@ app.views.PublisherMention = app.views.SearchBase.extend({ */ onInputBoxInput: function() { this.cleanMentionedPeople(); - this.updateMessageTexts(); this.updateTypeaheadInput(); }, @@ -189,9 +178,5 @@ app.views.PublisherMention = app.views.SearchBase.extend({ isVisible: function() { return this.$(".tt-menu").is(":visible"); - }, - - getTextForSubmit: function() { - return this.mentionedPeople.length ? this.inputBox.data("messageText") : this.inputBox.val(); } }); diff --git a/app/assets/javascripts/app/views/publisher_view.js b/app/assets/javascripts/app/views/publisher_view.js index 7d789f998..a06ac3387 100644 --- a/app/assets/javascripts/app/views/publisher_view.js +++ b/app/assets/javascripts/app/views/publisher_view.js @@ -324,7 +324,7 @@ app.views.Publisher = Backbone.View.extend({ this.handleTextchange(); var serializedForm = $("#new_status_message").serializeObject(); - var text = this.mention.getTextForSubmit(); + var text = serializedForm["status_message[text]"]; var photos = this.getUploadedPhotos(); var mentionedPeople = this.mention.mentionedPeople; var poll = this.getPollData(serializedForm); diff --git a/spec/javascripts/app/views/publisher_mention_view_spec.js b/spec/javascripts/app/views/publisher_mention_view_spec.js index 7ab98fe78..4cd9e5ae6 100644 --- a/spec/javascripts/app/views/publisher_mention_view_spec.js +++ b/spec/javascripts/app/views/publisher_mention_view_spec.js @@ -177,12 +177,6 @@ describe("app.views.PublisherMention", function() { expect(this.view.inputBox.val()).toBe("@{user1@pod.tld} 123 user2 @{user2@pod.tld} 456 @{user3@pod.tld} 789"); }); - it("calls updateMessageTexts", function() { - spyOn(this.view, "updateMessageTexts"); - this.view.onSuggestionSelection({name: "user1337", handle: "user1@pod.tld"}); - expect(this.view.updateMessageTexts).toHaveBeenCalled(); - }); - it("places the caret at the right position", function() { this.view.onSuggestionSelection({"name": "user1WithLongName", "handle": "user1@pod.tld"}); var expectedCaretPosition = ("@user1337 Text before @{user1@pod.tld}").length; @@ -190,19 +184,6 @@ describe("app.views.PublisherMention", function() { }); }); - describe("updateMessageTexts", function() { - beforeEach(function() { - this.view = new app.views.PublisherMention({ el: "#publisher" }); - this.view.inputBox.val("@user1 Text before @{user1@pod.tld}\ntext after"); - this.view.mentionedPeople.push({"name": "user1", "handle": "user1@pod.tld"}); - }); - - it("sets the correct messageText", function() { - this.view.updateMessageTexts(); - expect(this.view.inputBox.data("messageText")).toBe("@user1 Text before @{user1@pod.tld}\ntext after"); - }); - }); - describe("updateTypeaheadInput", function() { beforeEach(function() { this.view = new app.views.PublisherMention({ el: "#publisher" }); @@ -254,13 +235,11 @@ describe("app.views.PublisherMention", function() { beforeEach(function() { this.view = new app.views.PublisherMention({ el: "#publisher" }); spyOn(this.view, "addPersonToMentions"); - spyOn(this.view, "updateMessageTexts"); }); it("prefills one mention", function() { this.view.prefillMention([{"name": "user1", "handle": "user1@pod.tld"}]); expect(this.view.addPersonToMentions).toHaveBeenCalledWith({"name": "user1", "handle": "user1@pod.tld"}); - expect(this.view.updateMessageTexts).toHaveBeenCalled(); expect(this.view.inputBox.val()).toBe("@{user1@pod.tld}"); }); @@ -272,7 +251,6 @@ describe("app.views.PublisherMention", function() { expect(this.view.addPersonToMentions).toHaveBeenCalledWith({"name": "user1", "handle": "user1@pod.tld"}); expect(this.view.addPersonToMentions).toHaveBeenCalledWith({"name": "user2", "handle": "user2@pod.tld"}); - expect(this.view.updateMessageTexts).toHaveBeenCalled(); expect(this.view.inputBox.val()).toBe("@{user1@pod.tld} @{user2@pod.tld}"); }); }); @@ -380,12 +358,6 @@ describe("app.views.PublisherMention", function() { expect(this.view.cleanMentionedPeople).toHaveBeenCalled(); }); - it("calls 'updateMessageTexts'", function() { - spyOn(this.view, "updateMessageTexts"); - this.view.onInputBoxInput(); - expect(this.view.updateMessageTexts).toHaveBeenCalled(); - }); - it("calls 'updateTypeaheadInput'", function() { spyOn(this.view, "updateTypeaheadInput"); this.view.onInputBoxInput(); @@ -450,28 +422,4 @@ describe("app.views.PublisherMention", function() { expect(this.view.typeaheadInput.val()).toBe(""); }); }); - - describe("getTextForSubmit", function() { - beforeEach(function() { - this.view = new app.views.PublisherMention({ el: "#publisher" }); - this.view.bloodhound.add([ - {person: true, name: "user1", handle: "user1@pod.tld"} - ]); - }); - - it("returns text with mention if someone has been mentioned", function() { - this.view.inputBox.val("@user"); - this.view.inputBox[0].setSelectionRange(5, 5); - this.view.typeaheadInput.typeahead("val", "user"); - this.view.typeaheadInput.typeahead("open"); - this.view.$(".tt-suggestion").first().click(); - expect(this.view.getTextForSubmit()).toBe("@{user1@pod.tld}"); - }); - - it("returns normal text if nobody has been mentioned", function() { - this.view.inputBox.data("messageText", "Bad text"); - this.view.inputBox.val("Good text"); - expect(this.view.getTextForSubmit()).toBe("Good text"); - }); - }); }); From 9217df43cdc1374ed13ec5429896e23eb74a9a67 Mon Sep 17 00:00:00 2001 From: Steffen van Bergerem Date: Mon, 30 Jan 2017 13:52:39 +0100 Subject: [PATCH 6/8] Only update mentions in publisher before opening suggestions or preview --- .../app/views/publisher/mention_view.js | 8 +++- .../javascripts/app/views/publisher_view.js | 8 +--- .../app/views/publisher_mention_view_spec.js | 40 ++++++++++++++++--- .../app/views/publisher_view_spec.js | 14 ------- 4 files changed, 42 insertions(+), 28 deletions(-) diff --git a/app/assets/javascripts/app/views/publisher/mention_view.js b/app/assets/javascripts/app/views/publisher/mention_view.js index d1c98b829..36ab541cf 100644 --- a/app/assets/javascripts/app/views/publisher/mention_view.js +++ b/app/assets/javascripts/app/views/publisher/mention_view.js @@ -80,6 +80,8 @@ app.views.PublisherMention = app.views.SearchBase.extend({ return; } + this.cleanMentionedPeople(); + // result[1] is the string between the last '@' and the current caret position this.typeaheadInput.typeahead("val", result[1]); this.typeaheadInput.typeahead("open"); @@ -122,7 +124,6 @@ app.views.PublisherMention = app.views.SearchBase.extend({ * Listens for user input and opens results dropdown when input contains the trigger char */ onInputBoxInput: function() { - this.cleanMentionedPeople(); this.updateTypeaheadInput(); }, @@ -178,5 +179,10 @@ app.views.PublisherMention = app.views.SearchBase.extend({ isVisible: function() { return this.$(".tt-menu").is(":visible"); + }, + + getMentionedPeople: function() { + this.cleanMentionedPeople(); + return this.mentionedPeople; } }); diff --git a/app/assets/javascripts/app/views/publisher_view.js b/app/assets/javascripts/app/views/publisher_view.js index a06ac3387..c19ff863e 100644 --- a/app/assets/javascripts/app/views/publisher_view.js +++ b/app/assets/javascripts/app/views/publisher_view.js @@ -192,9 +192,6 @@ app.views.Publisher = Backbone.View.extend({ // empty poll answer and failing validation. this.viewPollCreator.removeLastAnswer(); - //add missing mentions at end of post: - this.handleTextchange(); - var serializedForm = $(evt.target).closest("form").serializeObject(); // disable input while posting, must be after the form is serialized this.setInputEnabled(false); @@ -320,13 +317,10 @@ app.views.Publisher = Backbone.View.extend({ }, createPostPreview: function() { - //add missing mentions at end of post: - this.handleTextchange(); - var serializedForm = $("#new_status_message").serializeObject(); var text = serializedForm["status_message[text]"]; var photos = this.getUploadedPhotos(); - var mentionedPeople = this.mention.mentionedPeople; + var mentionedPeople = this.mention.getMentionedPeople(); var poll = this.getPollData(serializedForm); var locationCoords = serializedForm["location[coords]"]; if(!locationCoords || locationCoords === "") { diff --git a/spec/javascripts/app/views/publisher_mention_view_spec.js b/spec/javascripts/app/views/publisher_mention_view_spec.js index 4cd9e5ae6..666a62d96 100644 --- a/spec/javascripts/app/views/publisher_mention_view_spec.js +++ b/spec/javascripts/app/views/publisher_mention_view_spec.js @@ -229,6 +229,22 @@ describe("app.views.PublisherMention", function() { expect(this.view.closeSuggestions).not.toHaveBeenCalled(); expect(this.view.typeaheadInput.val()).toBe("user"); }); + + it("doesn't call 'cleanMentionedPeople' if there is no '@' in front of the caret", function() { + spyOn(this.view, "cleanMentionedPeople"); + this.view.inputBox.val("user1337 Text before @user1 text after"); + this.view.inputBox[0].setSelectionRange(9, 9); + this.view.updateTypeaheadInput(); + expect(this.view.cleanMentionedPeople).not.toHaveBeenCalled(); + }); + + it("calls 'cleanMentionedPeople' if there is an '@' in front of the caret", function() { + spyOn(this.view, "cleanMentionedPeople"); + this.view.inputBox.val("@user1337 Text before @user1 text after"); + this.view.inputBox[0].setSelectionRange(9, 9); + this.view.updateTypeaheadInput(); + expect(this.view.cleanMentionedPeople).toHaveBeenCalled(); + }); }); describe("prefillMention", function() { @@ -352,12 +368,6 @@ describe("app.views.PublisherMention", function() { this.view = new app.views.PublisherMention({ el: "#publisher" }); }); - it("calls 'cleanMentionedPeople'", function() { - spyOn(this.view, "cleanMentionedPeople"); - this.view.onInputBoxInput(); - expect(this.view.cleanMentionedPeople).toHaveBeenCalled(); - }); - it("calls 'updateTypeaheadInput'", function() { spyOn(this.view, "updateTypeaheadInput"); this.view.onInputBoxInput(); @@ -422,4 +432,22 @@ describe("app.views.PublisherMention", function() { expect(this.view.typeaheadInput.val()).toBe(""); }); }); + + describe("getMentionedPeople", function() { + beforeEach(function() { + this.view = new app.views.PublisherMention({el: "#publisher"}); + }); + + it("calls 'cleanMentionedPeople'", function() { + spyOn(this.view, "cleanMentionedPeople"); + this.view.getMentionedPeople(); + expect(this.view.cleanMentionedPeople).toHaveBeenCalled(); + }); + + it("returns the cleaned mentionedPeople", function() { + this.view.inputBox.val("@{user1@pod.tld} user2@pod.tld"); + this.view.mentionedPeople = [{name: "user1", handle: "user1@pod.tld"}, {name: "user2", handle: "user2@pod.tld"}]; + expect(this.view.getMentionedPeople()).toEqual([{name: "user1", handle: "user1@pod.tld"}]); + }); + }); }); diff --git a/spec/javascripts/app/views/publisher_view_spec.js b/spec/javascripts/app/views/publisher_view_spec.js index a0bd9c292..0b3bc8993 100644 --- a/spec/javascripts/app/views/publisher_view_spec.js +++ b/spec/javascripts/app/views/publisher_view_spec.js @@ -203,12 +203,6 @@ describe("app.views.Publisher", function() { }); describe("createStatusMessage", function(){ - it("calls handleTextchange to complete missing mentions", function(){ - spyOn(this.view, "handleTextchange"); - this.view.createStatusMessage($.Event()); - expect(this.view.handleTextchange).toHaveBeenCalled(); - }); - it("adds the status message to the stream", function() { app.stream = { addNow: $.noop }; spyOn(app.stream, "addNow"); @@ -224,14 +218,6 @@ describe("app.views.Publisher", function() { }); }); - describe("createPostPreview", function(){ - it("calls handleTextchange to complete missing mentions", function(){ - spyOn(this.view, "handleTextchange"); - this.view.createPostPreview(); - expect(this.view.handleTextchange).toHaveBeenCalled(); - }); - }); - describe('#setText', function() { it("sets the content text", function() { this.view.setText("FOO bar"); From b23debf0b61c5881a53ac1f3c63c77d6c6a8bb4c Mon Sep 17 00:00:00 2001 From: Steffen van Bergerem Date: Mon, 30 Jan 2017 14:06:01 +0100 Subject: [PATCH 7/8] Refactor publisher backbone view --- .../javascripts/app/views/publisher_view.js | 21 +++++++------------ .../app/views/publisher_view_spec.js | 12 +++-------- 2 files changed, 10 insertions(+), 23 deletions(-) diff --git a/app/assets/javascripts/app/views/publisher_view.js b/app/assets/javascripts/app/views/publisher_view.js index c19ff863e..97bda7e12 100644 --- a/app/assets/javascripts/app/views/publisher_view.js +++ b/app/assets/javascripts/app/views/publisher_view.js @@ -22,7 +22,7 @@ app.views.Publisher = Backbone.View.extend({ "focus textarea" : "open", "submit form" : "createStatusMessage", "click #submit" : "createStatusMessage", - "textchange #status_message_text": "handleTextchange", + "textchange #status_message_text": "checkSubmitAvailability", "click #locator" : "showLocation", "click #poll_creator" : "togglePollCreator", "click #hide_location" : "destroyLocation", @@ -154,7 +154,7 @@ app.views.Publisher = Backbone.View.extend({ this.viewPollCreator.render(); if (this.prefillMention) { - this.handleTextchange(); + this.checkSubmitAvailability(); } }, @@ -170,7 +170,7 @@ app.views.Publisher = Backbone.View.extend({ this.inputEl.trigger("input"); autosize.update(this.inputEl); - this.handleTextchange(); + this.checkSubmitAvailability(); }, // show the "getting started" popups around the publisher @@ -242,7 +242,7 @@ app.views.Publisher = Backbone.View.extend({ self.setButtonsEnabled(true); self.setInputEnabled(true); self.wrapperEl.removeClass("submitting"); - self.handleTextchange(); + self.checkSubmitAvailability(); autosize.update(self.inputEl); } }); @@ -318,9 +318,7 @@ app.views.Publisher = Backbone.View.extend({ createPostPreview: function() { var serializedForm = $("#new_status_message").serializeObject(); - var text = serializedForm["status_message[text]"]; var photos = this.getUploadedPhotos(); - var mentionedPeople = this.mention.getMentionedPeople(); var poll = this.getPollData(serializedForm); var locationCoords = serializedForm["location[coords]"]; if(!locationCoords || locationCoords === "") { @@ -336,12 +334,12 @@ app.views.Publisher = Backbone.View.extend({ var previewMessage = { "id": 0, - "text": text, + "text": serializedForm["status_message[text]"], "public": serializedForm["aspect_ids[]"] === "public", "created_at": new Date().toISOString(), "interacted_at": new Date().toISOString(), "author": app.currentUser ? app.currentUser.attributes : {}, - "mentioned_people": mentionedPeople, + "mentioned_people": this.mention.getMentionedPeople(), "photos": photos, "title": serializedForm["status_message[text]"], "location": location, @@ -454,8 +452,7 @@ app.views.Publisher = Backbone.View.extend({ setEnabled: function(bool) { this.setInputEnabled(bool); this.disabled = !bool; - - this.handleTextchange(); + this.checkSubmitAvailability(); }, setButtonsEnabled: function(bool) { @@ -483,10 +480,6 @@ app.views.Publisher = Backbone.View.extend({ return (!onlyWhitespaces || isPhotoAttached) && isValidPoll && !this.disabled; }, - handleTextchange: function() { - this.checkSubmitAvailability(); - }, - _beforeUnload: function(e) { if(this._submittable() && this.inputEl.val() !== this.prefillText){ var confirmationMessage = Diaspora.I18n.t("confirm_unload"); diff --git a/spec/javascripts/app/views/publisher_view_spec.js b/spec/javascripts/app/views/publisher_view_spec.js index 0b3bc8993..e540669b6 100644 --- a/spec/javascripts/app/views/publisher_view_spec.js +++ b/spec/javascripts/app/views/publisher_view_spec.js @@ -43,17 +43,11 @@ describe("app.views.Publisher", function() { }); describe("#initSubviews", function() { - it("calls handleTextchange if the publisher is prefilled with mentions", function() { - spyOn(this.view, "handleTextchange"); + it("calls checkSubmitAvailability if the publisher is prefilled with mentions", function() { + spyOn(this.view, "checkSubmitAvailability"); this.view.prefillMention = "user@example.org"; this.view.initSubviews(); - expect(this.view.handleTextchange).toHaveBeenCalled(); - }); - - it("doesn't call handleTextchange if there are no prefilled mentions", function() { - spyOn(this.view, "handleTextchange"); - this.view.initSubviews(); - expect(this.view.handleTextchange).not.toHaveBeenCalled(); + expect(this.view.checkSubmitAvailability).toHaveBeenCalled(); }); }); From a6e6e6de9125755251e05e15a931cab6a350c117 Mon Sep 17 00:00:00 2001 From: Steffen van Bergerem Date: Mon, 30 Jan 2017 14:09:55 +0100 Subject: [PATCH 8/8] Refactor publisher mentions backbone view --- .../app/views/publisher/mention_view.js | 11 ++--------- .../app/views/publisher_mention_view_spec.js | 16 ++-------------- 2 files changed, 4 insertions(+), 23 deletions(-) diff --git a/app/assets/javascripts/app/views/publisher/mention_view.js b/app/assets/javascripts/app/views/publisher/mention_view.js index 36ab541cf..f30779c70 100644 --- a/app/assets/javascripts/app/views/publisher/mention_view.js +++ b/app/assets/javascripts/app/views/publisher/mention_view.js @@ -7,7 +7,7 @@ app.views.PublisherMention = app.views.SearchBase.extend({ events: { "keydown #status_message_text": "onInputBoxKeyDown", - "input #status_message_text": "onInputBoxInput", + "input #status_message_text": "updateTypeaheadInput", "click #status_message_text": "onInputBoxClick", "blur #status_message_text": "onInputBoxBlur" }, @@ -120,13 +120,6 @@ app.views.PublisherMention = app.views.SearchBase.extend({ this.typeaheadInput.trigger($.Event("keydown", {keyCode: e.keyCode, which: e.which})); }, - /** - * Listens for user input and opens results dropdown when input contains the trigger char - */ - onInputBoxInput: function() { - this.updateTypeaheadInput(); - }, - onInputBoxKeyDown: function(e) { // This also matches HOME/END on OSX which is CMD+LEFT, CMD+RIGHT if(e.which === Keycodes.LEFT || e.which === Keycodes.RIGHT || @@ -169,7 +162,7 @@ app.views.PublisherMention = app.views.SearchBase.extend({ reset: function() { this.inputBox.val(""); - this.onInputBoxInput(); + this.updateTypeaheadInput(); }, closeSuggestions: function() { diff --git a/spec/javascripts/app/views/publisher_mention_view_spec.js b/spec/javascripts/app/views/publisher_mention_view_spec.js index 666a62d96..5f53c110f 100644 --- a/spec/javascripts/app/views/publisher_mention_view_spec.js +++ b/spec/javascripts/app/views/publisher_mention_view_spec.js @@ -363,18 +363,6 @@ describe("app.views.PublisherMention", function() { }); }); - describe("onInputBoxInput", function() { - beforeEach(function() { - this.view = new app.views.PublisherMention({ el: "#publisher" }); - }); - - it("calls 'updateTypeaheadInput'", function() { - spyOn(this.view, "updateTypeaheadInput"); - this.view.onInputBoxInput(); - expect(this.view.updateTypeaheadInput).toHaveBeenCalled(); - }); - }); - describe("onInputBoxClick", function() { beforeEach(function() { this.view = new app.views.PublisherMention({ el: "#publisher" }); @@ -402,13 +390,13 @@ describe("app.views.PublisherMention", function() { describe("reset", function() { beforeEach(function() { this.view = new app.views.PublisherMention({ el: "#publisher" }); - spyOn(this.view, "onInputBoxInput"); + spyOn(this.view, "updateTypeaheadInput"); }); it("resets the mention box", function() { this.view.reset(); expect(this.view.inputBox.val()).toBe(""); - expect(this.view.onInputBoxInput).toHaveBeenCalled(); + expect(this.view.updateTypeaheadInput).toHaveBeenCalled(); }); });