port bookmarklet to Backbone.js, use gon for params (fixes #4931)

This commit is contained in:
Florian Staudacher 2014-04-17 02:26:46 +02:00
parent 441cc062f8
commit 0d51bba959
10 changed files with 162 additions and 113 deletions

View file

@ -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();
}
});

View file

@ -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'));
}
});

View file

@ -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()) === ''),

View file

@ -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

View file

@ -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');
});

View file

@ -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."

View file

@ -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

View file

@ -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$/);
});
});

View file

@ -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();

View file

@ -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");
});
});
});
});