diff --git a/app/assets/javascripts/app/router.js b/app/assets/javascripts/app/router.js index f6367cf62..0cc50563a 100644 --- a/app/assets/javascripts/app/router.js +++ b/app/assets/javascripts/app/router.js @@ -21,7 +21,9 @@ app.Router = Backbone.Router.extend({ "people/:id/photos": "photos", "people/:id": "stream", - "u/:name": "stream" + "u/:name": "stream", + + "bookmarklet": "bookmarklet" }, help: function() { @@ -110,5 +112,12 @@ app.Router = Backbone.Router.extend({ if(this.followedTagsView && Backbone.history.fragment != "followed_tags") this.followedTagsView.hideFollowedTags(); }, + + bookmarklet: function() { + var contents = (window.gon) ? gon.preloads.bookmarklet : {} + app.bookmarklet = new app.views.Bookmarklet( + _.extend({}, {el: $('#bookmarklet')}, contents) + ).render(); + } }); diff --git a/app/assets/javascripts/app/views/bookmarklet_view.js b/app/assets/javascripts/app/views/bookmarklet_view.js new file mode 100644 index 000000000..29e63daca --- /dev/null +++ b/app/assets/javascripts/app/views/bookmarklet_view.js @@ -0,0 +1,44 @@ +app.views.Bookmarklet = Backbone.View.extend({ + separator: ' - ', + + initialize: function(opts) { + // init a standalone publisher + app.publisher = new app.views.Publisher({standalone: true}); + + app.publisher.on('publisher:add', this._postSubmit, this); + app.publisher.on('publisher:sync', this._postSuccess, this); + app.publisher.on('publisher:error', this._postError, this); + + this.param_contents = opts; + }, + + render: function() { + app.publisher.open(); + app.publisher.setText(this._publisherContent()); + + return this; + }, + + _publisherContent: function() { + var p = this.param_contents; + if( p.content ) return p.content; + + var contents = p.title + this.separator + p.url; + if( p.notes ) contents += this.separator + p.notes; + return contents; + }, + + _postSubmit: function(evt) { + this.$('h4').text(Diaspora.I18n.t('bookmarklet.post_submit')); + }, + + _postSuccess: function(evt) { + this.$('h4').text(Diaspora.I18n.t('bookmarklet.post_success')); + app.publisher.close(); + _.delay(window.close, 2000); + }, + + _postError: function(evt) { + this.$('h4').text(Diaspora.I18n.t('bookmarklet.post_error')); + } +}); diff --git a/app/assets/javascripts/app/views/publisher_view.js b/app/assets/javascripts/app/views/publisher_view.js index be4037d82..29fe3e741 100644 --- a/app/assets/javascripts/app/views/publisher_view.js +++ b/app/assets/javascripts/app/views/publisher_view.js @@ -30,6 +30,7 @@ app.views.Publisher = Backbone.View.extend({ initialize : function(opts){ this.standalone = opts ? opts.standalone : false; + this.disabled = false; // init shortcut references to the various elements this.el_input = this.$('#status_message_fake_text'); @@ -103,7 +104,7 @@ app.views.Publisher = Backbone.View.extend({ publisher: this }); this.view_uploader.on('change', this.checkSubmitAvailability, this); - + this.view_poll_creator = new app.views.PublisherPollCreator({ el: this.$('#publisher-poll-creator') }); @@ -117,21 +118,35 @@ app.views.Publisher = Backbone.View.extend({ this.view_aspect_selector_blueprint.updateAspectsSelector(ids); }, + // inject content into the publisher textarea + setText: function(txt) { + this.el_input.val(txt); + this.el_hiddenInput.val(txt); + + this.el_input.trigger('input'); + this.handleTextchange(); + }, + // show the "getting started" popups around the publisher triggerGettingStarted: function() { this.view_getting_started.show(); }, createStatusMessage : function(evt) { + var self = this; + if(evt){ evt.preventDefault(); } //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); // lulz this code should be killed. var statusMessage = new app.models.Post(); + if( app.publisher ) app.publisher.trigger('publisher:add'); statusMessage.save({ "status_message" : { @@ -147,17 +162,24 @@ app.views.Publisher = Backbone.View.extend({ }, { url : "/status_messages", success : function() { - if(app.publisher) { - $(app.publisher.el).trigger('ajax:success'); - } - if(app.stream) { - app.stream.addNow(statusMessage.toJSON()); + if( app.publisher ) { + app.publisher.$el.trigger('ajax:success'); + app.publisher.trigger('publisher:sync'); } + + if(app.stream) app.stream.addNow(statusMessage.toJSON()); + + // clear state + self.clear(); + + // standalone means single-shot posting (until further notice) + if( self.standalone ) self.setEnabled(false); + }, + error: function() { + if( app.publisher ) app.publisher.trigger('publisher:error'); + self.setInputEnabled(true); } }); - - // clear state - this.clear(); }, // creates the location @@ -231,7 +253,7 @@ app.views.Publisher = Backbone.View.extend({ var poll = undefined; var poll_question = serializedForm["poll_question"]; - var poll_answers_arry = _.flatten([serializedForm["poll_answers[]"]]); + var poll_answers_arry = _.flatten([serializedForm["poll_answers[]"]]); var poll_answers = _.map(poll_answers_arry, function(answer){ if(answer) return { 'answer' : answer }; }); @@ -259,7 +281,7 @@ app.views.Publisher = Backbone.View.extend({ "title" : serializedForm["status_message[text]"], "address" : $("#location_address").val(), "interactions" : {"likes":[],"reshares":[],"comments_count":0,"likes_count":0,"reshares_count":0}, - 'poll': poll, + 'poll': poll, }; if(app.stream) { this.removePostPreview(); @@ -321,6 +343,9 @@ app.views.Publisher = Backbone.View.extend({ // disable submitting this.checkSubmitAvailability(); + // enable input + this.setInputEnabled(true); + // clear location this.destroyLocation(); @@ -347,6 +372,8 @@ app.views.Publisher = Backbone.View.extend({ }, open : function() { + if( this.disabled ) return; + // visually 'open' the publisher this.$el.removeClass('closed'); this.el_wrapper.addClass('active'); @@ -372,18 +399,31 @@ app.views.Publisher = Backbone.View.extend({ } }, + setEnabled: function(bool) { + this.setInputEnabled(bool); + this.disabled = !bool; + + this.handleTextchange(); + }, + setButtonsEnabled: function(bool) { bool = !bool; this.el_submit.prop({disabled: bool}); this.el_preview.prop({disabled: bool}); }, + setInputEnabled: function(bool) { + bool = !bool; + this.el_input.prop({disabled: bool}); + this.el_hiddenInput.prop({disabled: bool}); + }, + // determine submit availability _submittable: function() { var onlyWhitespaces = ($.trim(this.el_input.val()) === ''), isPhotoAttached = (this.el_photozone.children().length > 0); - return (!onlyWhitespaces || isPhotoAttached); + return (!onlyWhitespaces || isPhotoAttached) && !this.disabled; }, handleTextchange: function() { diff --git a/app/controllers/status_messages_controller.rb b/app/controllers/status_messages_controller.rb index c20b2976f..06790768b 100644 --- a/app/controllers/status_messages_controller.rb +++ b/app/controllers/status_messages_controller.rb @@ -42,6 +42,13 @@ class StatusMessagesController < ApplicationController def bookmarklet @aspects = current_user.aspects @aspect_ids = @aspects.map{|x| x.id} + + gon.preloads[:bookmarklet] = { + content: params[:content], + title: params[:title], + url: params[:url], + notes: params[:notes] + } end def create @@ -52,7 +59,7 @@ class StatusMessagesController < ApplicationController @status_message = current_user.build_post(:status_message, params[:status_message]) @status_message.build_location(:address => params[:location_address], :coordinates => params[:location_coords]) if params[:location_address].present? if params[:poll_question].present? - @status_message.build_poll(:question => params[:poll_question]) + @status_message.build_poll(:question => params[:poll_question]) [*params[:poll_answers]].each do |poll_answer| @status_message.poll.poll_answers.build(:answer => poll_answer) end diff --git a/app/views/status_messages/bookmarklet.html.haml b/app/views/status_messages/bookmarklet.html.haml index f45806fa0..835138c19 100644 --- a/app/views/status_messages/bookmarklet.html.haml +++ b/app/views/status_messages/bookmarklet.html.haml @@ -9,32 +9,3 @@ %h4 =t('bookmarklet.post_something') = render :partial => 'publisher/publisher', :locals => { :aspect => :profile, :selected_aspects => @aspects, :aspect_ids => @aspect_ids } - -:javascript - app.publisher = new app.views.Publisher({ - standalone: true - }); - - var contents = "#{escape_javascript params[:content]}"; - if(!contents){ - contents = "#{escape_javascript params[:title]} - #{escape_javascript params[:url]}"; - var notes = "#{escape_javascript params[:notes]}"; - if (notes.length > 0){ - contents += " - " + notes; - } - } - - $("#publisher").bind('ajax:success', function(){ - $('h4').text("#{t('bookmarklet.post_success')}"); - app.publisher.close(); - window.setTimeout(window.close, 2000, true); - }); - - // this has to happen after the publisher has finished loading, otherwise - // the textarea is cleared again by the initialization of the mentions plugin - $(function(){ - $("#publisher #status_message_fake_text").val(contents); - $("#publisher #status_message_text").val(contents); - $('#publisher button#submit').removeAttr('disabled'); - $('#publisher #publisher_textarea_wrapper').addClass('active'); - }); diff --git a/config/locales/javascript/javascript.en.yml b/config/locales/javascript/javascript.en.yml index 437a5848e..5a619206e 100644 --- a/config/locales/javascript/javascript.en.yml +++ b/config/locales/javascript/javascript.en.yml @@ -46,6 +46,10 @@ en: limited: "Limited - your post will only be seen by people you are sharing with" public: "Public - your post will be visible to everyone and found by search engines" near_from: "Posted from: <%= location %>" + bookmarklet: + post_submit: "Submitting post..." + post_success: "Posted! Closing popup window..." + post_error: "An error occurred, try again later." infinite_scroll: no_more: "No more posts." no_more_contacts: "No more contacts." diff --git a/features/desktop/post_preview.feature b/features/desktop/post_preview.feature index 97d97d877..3585ceaf9 100644 --- a/features/desktop/post_preview.feature +++ b/features/desktop/post_preview.feature @@ -16,20 +16,17 @@ Feature: preview posts in the stream Scenario: preview and post a text-only message Given I expand the publisher - When I fill in the following: - | status_message_fake_text | I am eating yogurt | + When I write the status message "I am eating yogurt" And I press "Preview" Then "I am eating yogurt" should be post 1 And the first post should be a preview - When I fill in the following: - | status_message_fake_text | This preview rocks | + When I write the status message "This preview rocks" And I press "Preview" Then "This preview rocks" should be post 1 And I should not see "I am eating a yogurt" - When I fill in the following: - | status_message_fake_text | I like rocks | + When I write the status message "I like rocks" And I press "Share" Then "I like rocks" should be post 1 And I should not see "This preview rocks" diff --git a/features/desktop/posts_from_main_page.feature b/features/desktop/posts_from_main_page.feature index e68434f05..0da96f25f 100644 --- a/features/desktop/posts_from_main_page.feature +++ b/features/desktop/posts_from_main_page.feature @@ -17,7 +17,7 @@ Feature: posting from the main page And I have user with username "alice" in an aspect called "PostingTo" And I have user with username "alice" in an aspect called "NotPostingThingsHere" And I am on the home page - + Scenario: expanding the publisher Given ".markdownIndications" is hidden And ".options_and_submit" is hidden @@ -28,23 +28,20 @@ Feature: posting from the main page Scenario: post a text-only message to all aspects Given I expand the publisher - When I fill in the following: - | status_message_fake_text | I am eating yogurt | - And I press "Share" + When I write the status message "I am eating yogurt" + And I submit the publisher And I go to the aspects page Then "I am eating yogurt" should be post 1 Scenario: re-posting a text-only message Given I expand the publisher - When I fill in the following: - | status_message_fake_text | The World needs more Cats. | - And I press "Share" + When I write the status message "The World needs more Cats." + And I submit the publisher Given I expand the publisher - When I fill in the following: - | status_message_fake_text | The World needs more Cats. | - And I press "Share" + When I write the status message "The World needs more Cats." + And I submit the publisher And I go to the aspects page Then "The World needs more Cats." should be post 1 @@ -58,10 +55,9 @@ Feature: posting from the main page Scenario: post a text-only message to just one aspect When I select only "PostingTo" aspect And I expand the publisher - And I fill in the following: - | status_message_fake_text | I am eating a yogurt | + When I write the status message "I am eating a yogurt" - And I press "Share" + And I submit the publisher When I am on the aspects page And I select only "PostingTo" aspect @@ -74,9 +70,8 @@ Feature: posting from the main page Scenario: post a photo with text Given I expand the publisher When I attach the file "spec/fixtures/button.png" to hidden "file" within "#file-upload" - When I fill in the following: - | status_message_fake_text | Look at this dog | - And I press "Share" + When I write the status message "Look at this dog" + And I submit the publisher And I go to the aspects page Then I should see a "img" within ".stream_element div.photo_attachments" And I should see "Look at this dog" within ".stream_element" @@ -112,8 +107,7 @@ Feature: posting from the main page Scenario: back out of uploading a picture to a post with text Given I expand the publisher And I have turned off jQuery effects - When I fill in the following: - | status_message_fake_text | I am eating a yogurt | + When I write the status message "I am eating a yogurt" And I attach the file "spec/fixtures/button.png" to hidden "file" within "#file-upload" And I click to delete the first uploaded photo Then I should not see an uploaded image within the photo drop zone @@ -122,8 +116,7 @@ Feature: posting from the main page Scenario: back out of uploading a picture when another has been attached Given I expand the publisher And I have turned off jQuery effects - When I fill in the following: - | status_message_fake_text | I am eating a yogurt | + When I write the status message "I am eating a yogurt" And I attach the file "spec/fixtures/button.png" to hidden "file" within "#file-upload" And I attach the file "spec/fixtures/button.png" to hidden "file" within "#file-upload" And I click to delete the first uploaded photo @@ -133,9 +126,8 @@ Feature: posting from the main page @wip Scenario: hide a contact's post Given I expand the publisher - When I fill in the following: - | status_message_fake_text | Here is a post for you to hide | - And I press "Share" + When I write the status message "Here is a post for you to hide" + And I submit the publisher And I log out And I sign in as "alice@alice.alice" @@ -151,9 +143,8 @@ Feature: posting from the main page Scenario: delete one of my posts Given I expand the publisher - When I fill in the following: - | status_message_fake_text | I am eating a yogurt | - And I press "Share" + When I write the status message "I am eating a yogurt" + And I submit the publisher And I go to the aspects page And I hover over the ".stream_element" And I click to delete the first post @@ -165,7 +156,7 @@ Feature: posting from the main page And I press the aspect dropdown And I toggle the aspect "PostingTo" And I append "I am eating a yogurt" to the publisher - And I press "Share" + And I submit the publisher And I am on the aspects page And I select only "PostingTo" aspect @@ -179,13 +170,13 @@ Feature: posting from the main page And I press the aspect dropdown And I toggle the aspect "PostingTo" And I append "I am eating a yogurt" to the publisher - And I press "Share" + And I submit the publisher And I expand the publisher And I press the aspect dropdown And I toggle the aspect "Besties" And I append "And cornflakes also" to the publisher - And I press "Share" + And I submit the publisher And I am on the aspects page And I select only "PostingTo" aspect @@ -201,9 +192,8 @@ Feature: posting from the main page # (NOTE) make this a jasmine spec Scenario: reject deletion one of my posts When I expand the publisher - When I fill in the following: - | status_message_fake_text | I am eating a yogurt | - And I press "Share" + When I write the status message "I am eating a yogurt" + And I submit the publisher And I hover over the ".stream_element" And I prepare the deletion of the first post diff --git a/features/step_definitions/aspects_steps.rb b/features/step_definitions/aspects_steps.rb index f19e1e5bb..3636a8da3 100644 --- a/features/step_definitions/aspects_steps.rb +++ b/features/step_definitions/aspects_steps.rb @@ -1,3 +1,21 @@ +module AspectCukeHelpers + def click_aspect_dropdown + find('.dropdown .button').click + end + + def toggle_aspect(a_name) + a_id = @me.aspects.where(name: a_name).pluck(:id).first + aspect_css = ".dropdown li[data-aspect_id='#{a_id}']" + page.should have_selector(aspect_css) + find(aspect_css).click + end + + def aspect_dropdown_visible? + find('.aspect_membership.dropdown.active').should be_visible + end +end +World(AspectCukeHelpers) + When /^I click on "([^"]*)" aspect edit icon$/ do |aspect_name| within(".all_aspects") do li = find('li', text: aspect_name) @@ -23,20 +41,6 @@ When /^I select "([^"]*)" aspect as well$/ do |aspect_name| step %Q(I should see "#{aspect_name}" aspect selected) end -Then /^I should see "([^"]*)" aspect selected$/ do |aspect_name| - aspect = @me.aspects.where(:name => aspect_name).first - within("#aspects_list") do - page.should have_css "li[data-aspect_id='#{aspect.id}'] .selected" - end -end - -Then /^I should see "([^"]*)" aspect unselected$/ do |aspect_name| - aspect = @me.aspects.where(:name => aspect_name).first - within("#aspects_list") do - page.should have_no_css "li[data-aspect_id='#{aspect.id}'] .selected" - end -end - When /^I check the first contact list button$/ do find(".contact_list .button", match: :first).tap do |button| button.click @@ -51,3 +55,29 @@ When /^I uncheck the first contact list button$/ do sleep 1 # The expectation above should wait for the request to finsh, but that doesn't work for some reason end end + +When /^I press the aspect dropdown$/ do + click_aspect_dropdown +end + +And /^I toggle the aspect "([^"]*)"$/ do |name| + toggle_aspect(name) +end + +Then /^I should see "([^"]*)" aspect selected$/ do |aspect_name| + aspect = @me.aspects.where(:name => aspect_name).first + within("#aspects_list") do + page.should have_css "li[data-aspect_id='#{aspect.id}'] .selected" + end +end + +Then /^I should see "([^"]*)" aspect unselected$/ do |aspect_name| + aspect = @me.aspects.where(:name => aspect_name).first + within("#aspects_list") do + page.should have_no_css "li[data-aspect_id='#{aspect.id}'] .selected" + end +end + +Then /^the aspect dropdown should be visible$/ do + aspect_dropdown_visible? +end diff --git a/features/step_definitions/custom_web_steps.rb b/features/step_definitions/custom_web_steps.rb index 3d4069427..ac06e50cb 100644 --- a/features/step_definitions/custom_web_steps.rb +++ b/features/step_definitions/custom_web_steps.rb @@ -64,19 +64,6 @@ And /^I expand the publisher$/ do click_publisher end -When /^I press the aspect dropdown$/ do - find('.dropdown .button').click -end - -Then /^the aspect dropdown should be visible$/ do - find(:css, '.aspect_membership.dropdown.active').should be_visible -end - -And /^I toggle the aspect "([^"]*)"$/ do |aspect_name| - aspect = @me.aspects.where(:name => aspect_name).first - find(".dropdown li[data-aspect_id='#{aspect.id}']").click -end - Then /^the publisher should be expanded$/ do find("#publisher")["class"].should_not include("closed") end @@ -85,18 +72,6 @@ Then /^the text area wrapper mobile should be with attachments$/ do find("#publisher_textarea_wrapper")["class"].should include("with_attachments") end -When /^I append "([^"]*)" to the publisher$/ do |stuff| - elem = find('#status_message_fake_text') - elem.native.send_keys(' ' + stuff) -end - -When /^I append "([^"]*)" to the publisher mobile$/ do |stuff| - elem = find('#status_message_text') - elem.native.send_keys(' ' + stuff) - - find('#status_message_text').value.should include(stuff) -end - And /^I want to mention (?:him|her) from the profile$/ do find('#mention_button').click within('#facebox') do diff --git a/features/step_definitions/mention_steps.rb b/features/step_definitions/mention_steps.rb index 237cd2857..e270ea875 100644 --- a/features/step_definitions/mention_steps.rb +++ b/features/step_definitions/mention_steps.rb @@ -7,7 +7,7 @@ end And /^I mention Alice in the publisher$/ do alice = User.find_by_email 'alice@alice.alice' - fill_in 'status_message_fake_text', :with => "@{Alice Smith ; #{alice.person.diaspora_handle}}" + write_in_publisher("@{Alice Smith ; #{alice.person.diaspora_handle}}") end And /^I click on the first user in the mentions dropdown list$/ do diff --git a/features/step_definitions/posts_steps.rb b/features/step_definitions/posts_steps.rb index 6c374296b..8b8c1933b 100644 --- a/features/step_definitions/posts_steps.rb +++ b/features/step_definitions/posts_steps.rb @@ -38,6 +38,10 @@ And /^the post with text "([^"]*)" is reshared by "([^"]*)"$/ do |text, email| user.post(:reshare, :root_guid => root.guid, :public => true, :to => user.aspects) end +And /^I submit the publisher$/ do + submit_publisher +end + When /^I click on the first block button/ do find(".stream_element", match: :first).hover find(".block_user").click @@ -63,8 +67,20 @@ When /^I post an extremely long status message$/ do click_and_post("I am a very interesting message " * 64) end +When /^I write the status message "([^"]*)"$/ do |text| + write_in_publisher(text) +end + When /^I insert an extremely long status message$/ do - fill_in 'status_message_fake_text', :with => "I am a very interesting message " * 64 + write_in_publisher("I am a very interesting message " * 64) +end + +When /^I append "([^"]*)" to the publisher$/ do |text| + append_to_publisher(text) +end + +When /^I append "([^"]*)" to the publisher mobile$/ do |text| + append_to_publisher(text, '#status_message_text') end When /^I open the show page of the "([^"]*)" post$/ do |post_text| diff --git a/features/step_definitions/stream_steps.rb b/features/step_definitions/stream_steps.rb index 4f36c979a..557e224ab 100644 --- a/features/step_definitions/stream_steps.rb +++ b/features/step_definitions/stream_steps.rb @@ -3,7 +3,7 @@ Then /^I like the post "([^"]*)"$/ do |post_text| end Then /^"([^"]*)" should be post (\d+)$/ do |post_text, position| - stream_element_numbers_content(position).text.should == post_text + stream_element_numbers_content(position).should have_content(post_text) end When /^I toggle nsfw posts$/ do diff --git a/features/support/publishing_cuke_helpers.rb b/features/support/publishing_cuke_helpers.rb index 90c0482e8..eef1eeaea 100644 --- a/features/support/publishing_cuke_helpers.rb +++ b/features/support/publishing_cuke_helpers.rb @@ -1,8 +1,25 @@ module PublishingCukeHelpers + def write_in_publisher(txt) + fill_in 'status_message_fake_text', with: txt + end + + def append_to_publisher(txt, input_selector='#status_message_fake_text') + elem = find(input_selector) + elem.native.send_keys(' ' + txt) + + # make sure the other text field got the new contents + find('#status_message_text', visible: false).value.should include(txt) + end + def make_post(text) - fill_in 'status_message_fake_text', :with => text - find(".creation").click - page.should have_content text unless page.has_css? '.nsfw-shield' + write_in_publisher(text) + submit_publisher + end + + def submit_publisher + txt = find('#publisher #status_message_fake_text').value + find('#publisher .creation').click + page.should have_content(txt) unless page.has_css?('.nsfw-shield') end def click_and_post(text) diff --git a/spec/controllers/status_messages_controller_spec.rb b/spec/controllers/status_messages_controller_spec.rb index f354e02b8..7d6a4b46e 100644 --- a/spec/controllers/status_messages_controller_spec.rb +++ b/spec/controllers/status_messages_controller_spec.rb @@ -15,12 +15,6 @@ describe StatusMessagesController do end describe '#bookmarklet' do - def pass_test_args(text='cute kitty') - get :bookmarklet, {:url => 'https://www.youtube.com/watch?v=0Bmhjf0rKe8', - :title => 'Surprised Kitty', - :notes => text} - end - it 'succeeds' do get :bookmarklet response.should be_success @@ -32,23 +26,13 @@ describe StatusMessagesController do doc = Nokogiri(response.body) doc.xpath('//head').count.should equal 1 doc.xpath('//body').count.should equal 1 - - save_fixture(html_for('body'), 'empty_bookmarklet') end it 'accepts get params' do - pass_test_args + get :bookmarklet, { url: 'https://www.youtube.com/watch?v=0Bmhjf0rKe8', + title: 'Surprised Kitty', + notes: 'cute kitty' } response.should be_success - - save_fixture(html_for('body'), 'prefilled_bookmarklet') - end - - it 'correctly deals with dirty input' do - test_text = "**love** This is such a\n\n great \"cute kitty\" '''blabla'''" - pass_test_args(test_text) - response.should be_success - - save_fixture(html_for('body'), 'prefilled_bookmarklet_dirty') end end @@ -210,7 +194,7 @@ describe StatusMessagesController do inlined_jobs do post :create, @hash end - + @photo1.reload.pending.should be_false @photo2.reload.pending.should be_false end diff --git a/spec/javascripts/app/views/bookmarklet_view_spec.js b/spec/javascripts/app/views/bookmarklet_view_spec.js new file mode 100644 index 000000000..deafaca79 --- /dev/null +++ b/spec/javascripts/app/views/bookmarklet_view_spec.js @@ -0,0 +1,62 @@ + +describe('app.views.Bookmarklet', function() { + var test_data = { + url: 'https://www.youtube.com/watch?v=0Bmhjf0rKe8', + title: 'Surprised Kitty', + notes: 'cute kitty' + }; + var evil_test_data = _.extend({}, { + notes: "**love** This is such a\n\n great \"cute kitty\" '''blabla''' %28%29\\" + }, test_data); + + var init_bookmarklet = function(data) { + app.bookmarklet = new app.views.Bookmarklet( + _.extend({el: $('#bookmarklet')}, data) + ).render(); + }; + + beforeEach(function() { + spec.loadFixture('bookmarklet'); + }); + + it('initializes a standalone publisher', function() { + new app.views.Bookmarklet(); + expect(app.publisher).not.toBeNull(); + expect(app.publisher.standalone).toBeTruthy(); + }); + + it('prefills the publisher', function() { + init_bookmarklet(test_data); + + expect($.trim(app.publisher.el_input.val())).not.toEqual(''); + expect($.trim(app.publisher.el_hiddenInput.val())).not.toEqual(''); + }); + + it('handles dirty input well', function() { + init_bookmarklet(evil_test_data); + + expect($.trim(app.publisher.el_input.val())).not.toEqual(''); + expect($.trim(app.publisher.el_hiddenInput.val())).not.toEqual(''); + }); + + it('allows changing a prefilled publisher', function() { + init_bookmarklet(test_data); + app.publisher.setText(app.publisher.el_input.val()+'A'); + + expect(app.publisher.el_hiddenInput.val()).toMatch(/.+A$/); + }); + + it('keeps the publisher disabled after successful post creation', function() { + jasmine.Ajax.useMock(); + + init_bookmarklet(test_data); + spec.content().find('form').submit(); + + mostRecentAjaxRequest().response({ + status: 200, // success! + responseText: "{}" + }); + + expect(app.publisher.disabled).toBeTruthy(); + }); +}); diff --git a/spec/javascripts/app/views/publisher_view_spec.js b/spec/javascripts/app/views/publisher_view_spec.js index fb753f01f..257724324 100644 --- a/spec/javascripts/app/views/publisher_view_spec.js +++ b/spec/javascripts/app/views/publisher_view_spec.js @@ -39,6 +39,12 @@ describe("app.views.Publisher", function() { this.view.open($.Event()); expect($(this.view.el)).not.toHaveClass("closed"); }); + + it("won't open when disabled", function() { + this.view.disabled = true; + this.view.open($.Event()); + expect($(this.view.el)).toHaveClass("closed"); + }); }); describe("#close", function() { @@ -124,6 +130,36 @@ describe("app.views.Publisher", function() { }) }); + describe('#setText', function() { + it('sets the content text', function() { + this.view.setText('FOO bar'); + + expect(this.view.el_input.val()).toEqual('FOO bar'); + expect(this.view.el_hiddenInput.val()).toEqual('FOO bar'); + }); + }); + + describe('#setEnabled', function() { + it('disables the publisher', function() { + expect(this.view.disabled).toBeFalsy(); + this.view.setEnabled(false); + + expect(this.view.disabled).toBeTruthy(); + expect(this.view.el_input.prop('disabled')).toBeTruthy(); + expect(this.view.el_hiddenInput.prop('disabled')).toBeTruthy(); + }); + + it("disables submitting", function() { + this.view.setText('TESTING'); + expect(this.view.el_submit.prop('disabled')).toBeFalsy(); + expect(this.view.el_preview.prop('disabled')).toBeFalsy(); + + this.view.setEnabled(false); + expect(this.view.el_submit.prop('disabled')).toBeTruthy(); + expect(this.view.el_preview.prop('disabled')).toBeTruthy(); + }); + }); + describe("publishing a post with keyboard", function(){ it("should submit the form when ctrl+enter is pressed", function(){ this.view.render(); diff --git a/spec/javascripts/bookmarklet-spec.js b/spec/javascripts/bookmarklet-spec.js deleted file mode 100644 index e9eb63363..000000000 --- a/spec/javascripts/bookmarklet-spec.js +++ /dev/null @@ -1,54 +0,0 @@ -/* Copyright (c) 2010-2012, Diaspora Inc. This file is - * licensed under the Affero General Public License version 3 or later. See - * the COPYRIGHT file. - */ - -describe("bookmarklet", function() { - - describe("base functionality", function(){ - beforeEach( function(){ - spec.loadFixture('empty_bookmarklet'); - }); - - it('verifies the publisher is loaded', function(){ - expect(typeof app.publisher === "object").toBeTruthy(); - }); - - it('verifies we are using the bookmarklet', function(){ - expect(app.publisher.standalone).toBeTruthy(); - expect(app.publisher.$('#hide_publisher').is(':visible')).toBeFalsy(); - }); - }); - - describe("prefilled bookmarklet", function(){ - it('fills in some text into the publisher', function(){ - spec.loadFixture('prefilled_bookmarklet'); - _.defer(function() { - expect($("#publisher #status_message_fake_text").val() == "").toBeFalsy(); - expect($("#publisher #status_message_text").val() == "").toBeFalsy(); - }); - }); - - it('handles dirty input well', function(){ - spec.loadFixture('prefilled_bookmarklet_dirty'); - _.defer(function() { - expect($("#publisher #status_message_fake_text").val() == "").toBeFalsy(); - expect($("#publisher #status_message_text").val() == "").toBeFalsy(); - }); - }); - }); - - describe("modified prefilled bookmarklet", function(){ - it('allows changing of post content', function(){ - spec.loadFixture('prefilled_bookmarklet'); - $('div.mentions > div').html('Foo Bar'); - _.defer(function() { - expect($("#publisher #status_message_text").val()).toEqual("Foo Bar"); - }); - }); - }); - - - - -});