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..3e79ca9c9 100644 --- a/app/assets/javascripts/app/views/publisher_view.js +++ b/app/assets/javascripts/app/views/publisher_view.js @@ -103,7 +103,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 +117,34 @@ 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'); + }, + // 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 +160,22 @@ app.views.Publisher = Backbone.View.extend({ }, { url : "/status_messages", success : function() { - if(app.publisher) { - $(app.publisher.el).trigger('ajax:success'); + 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(); + }, + error: function() { + if( app.publisher ) app.publisher.trigger('publisher:error'); + self.setInputEnabled(true); } }); - - // clear state - this.clear(); }, // creates the location @@ -231,7 +249,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 +277,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 +339,9 @@ app.views.Publisher = Backbone.View.extend({ // disable submitting this.checkSubmitAvailability(); + // enable input + this.setInputEnabled(true); + // clear location this.destroyLocation(); @@ -378,6 +399,12 @@ app.views.Publisher = Backbone.View.extend({ 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()) === ''), 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/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..c1345f253 --- /dev/null +++ b/spec/javascripts/app/views/bookmarklet_view_spec.js @@ -0,0 +1,48 @@ + +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$/); + }); +}); diff --git a/spec/javascripts/app/views/publisher_view_spec.js b/spec/javascripts/app/views/publisher_view_spec.js index fb753f01f..dc488151e 100644 --- a/spec/javascripts/app/views/publisher_view_spec.js +++ b/spec/javascripts/app/views/publisher_view_spec.js @@ -124,6 +124,15 @@ 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("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"); - }); - }); - }); - - - - -});