Skip to content
Snippets Groups Projects
Commit 843c0d9c authored by Maxwell Salzberg's avatar Maxwell Salzberg
Browse files

Merge pull request #3068 from diaspora/posting

Merging the trumpeter
parents 9d266432 9550082a
No related branches found
No related tags found
No related merge requests found
Showing
with 449 additions and 18 deletions
......@@ -11,7 +11,7 @@
#
# It's strongly recommended to check this file into your version control system.
ActiveRecord::Schema.define(:version => 20120301143226) do
ActiveRecord::Schema.define(:version => 20120322223517) do
create_table "account_deletions", :force => true do |t|
t.string "diaspora_handle"
......@@ -334,6 +334,7 @@ ActiveRecord::Schema.define(:version => 20120301143226) do
t.integer "o_embed_cache_id"
t.integer "reshares_count", :default => 0
t.datetime "interacted_at"
t.string "frame_name"
end
add_index "posts", ["author_id", "root_guid"], :name => "index_posts_on_author_id_and_root_guid", :unique => true
......
......@@ -64,13 +64,10 @@ Feature: Notifications
And I focus the comment field
And I fill in "text" with "great post!"
And I press "Comment"
And I wait for the ajax to finish
And I go to the destroy user session page
When I sign in as "alice@alice.alice"
And I follow "Notifications" in the header
And I wait for the ajax to finish
Then the notification dropdown should be visible
And I wait for the ajax to finish
Then I should see "commented on your post"
And I should have 1 email delivery
......
......@@ -16,4 +16,10 @@ end
Then /^I should have (\d+) nsfw posts$/ do |num_posts|
all(".nsfw-shield").size.should == num_posts.to_i
end
When /^I click the show page link for "([^"]*)"$/ do |post_text|
within(find_post_by_text(post_text)) do
find("time").click
end
end
\ No newline at end of file
def fill_in_autocomplete(selector, value)
pending #make me work if yr board, investigate send_keys
page.execute_script %Q{$('#{selector}').val('#{value}').keyup()}
end
def aspects_dropdown
find(".dropdown-toggle")
end
def select_from_dropdown(option_text, dropdown)
dropdown.click
within ".dropdown-menu" do
link = find("a:contains('#{option_text}')")
link.should be_visible
link.click
end
#assert dropdown text is link
end
def go_to_framer
click_button "Next"
end
def finalize_frame
click_button "done"
end
def assert_post_renders_with(template_name)
find(".post")["data-template"].should == template_name.downcase
end
def find_image_by_filename(filename)
find("img[src='#{@image_sources[filename]}']")
end
def store_image_filename(file_name)
@image_sources ||= {}
@image_sources[file_name] = all(".photos img").last["src"]
@image_sources[file_name].should be_present
end
def upload_photo(file_name)
orig_photo_count = all(".photos img").size
within ".new_photo" do
attach_file "photo[user_file]", Rails.root.join("spec", "fixtures", file_name)
wait_until { all(".photos img").size == orig_photo_count + 1 }
end
store_image_filename(file_name)
end
When /^I trumpet$/ do
visit new_post_path
end
When /^I write "([^"]*)"$/ do |text|
fill_in 'text', :with => text
end
Then /I mention "([^"]*)"$/ do |text|
fill_in_autocomplete('textarea.text', '@a')
sleep(5)
find("li.active").click
end
When /^I select "([^"]*)" in my aspects dropdown$/ do |title|
within ".aspect_selector" do
select_from_dropdown(title, aspects_dropdown)
end
end
Then /^"([^"]*)" should be a (limited|public) post in my stream$/ do |post_text, scope|
find_post_by_text(post_text).find(".post_scope").text.should =~ /#{scope}/i
end
When /^I upload a fixture picture with filename "([^"]*)"$/ do |file_name|
upload_photo(file_name)
end
Then /^"([^"]*)" should have the "([^"]*)" picture$/ do |post_text, file_name|
within find_post_by_text(post_text) do
find_image_by_filename(file_name).should be_present
end
end
When /^I go through the default composer$/ do
go_to_framer
finalize_frame
end
When /^I start the framing process$/ do
go_to_framer
end
When /^I finalize my frame$/ do
finalize_frame
end
Then /^"([^"]*)" should have (\d+) pictures$/ do |post_text, number_of_pictures|
find_post_by_text(post_text).all(".photo_attachments img").size.should == number_of_pictures.to_i
end
Then /^I should see "([^"]*)" in the framer preview$/ do |post_text|
within(find(".post")) { page.should have_content(post_text) }
end
When /^I select the mood "([^"]*)"$/ do |template_name|
select template_name, :from => 'template'
end
Then /^the post's mood should (?:still |)be "([^"]*)"$/ do |template_name|
assert_post_renders_with(template_name)
end
When /^"([^"]*)" should be in the post's picture viewer$/ do |file_name|
within(".photo_viewer") do
find_image_by_filename(file_name).should be_present
end
end
\ No newline at end of file
@javascript
Feature: Creating a new post
Background:
Given a user with username "bob"
And I sign in as "bob@bob.bob"
And I trumpet
Scenario: Posting a public message with a photo
And I write "I love RMS"
When I select "Public" in my aspects dropdown
And I upload a fixture picture with filename "button.gif"
When I go through the default composer
When I go to "/stream"
Then I should see "I love RMS" as the first post in my stream
And "I love RMS" should be a public post in my stream
Then "I love RMS" should have the "button.gif" picture
Scenario: Posting to Aspects
And I write "This is super skrunkle"
When I select "All Aspects" in my aspects dropdown
And I go through the default composer
When I go to "/stream"
Then I should see "This is super skrunkle" as the first post in my stream
Then "This is super skrunkle" should be a limited post in my stream
Scenario: Mention a contact
Given a user named "Alice Smith" with email "alice@alice.alice"
And a user with email "bob@bob.bob" is connected with "alice@alice.alice"
And I mention "alice@alice.alice"
And I go through the default composer
And I go to "/stream"
Then I follow "Alice Smith"
Scenario: Uploading multiple photos
When I write "check out these pictures"
And I upload a fixture picture with filename "button.gif"
And I upload a fixture picture with filename "button.gif"
And I go through the default composer
And I go to "/stream"
Then "check out these pictures" should have 2 pictures
Scenario: Framing your frame
When I write "This is hella customized"
And I upload a fixture picture with filename "button.gif"
And I start the framing process
Then I should see "This is hella customized" in the framer preview
# Then the default mood for the post should be "Wallpaper"
# And I should see the image "button.gif" background
When I select the mood "Day"
Then the post's mood should be "Day"
And "button.gif" should be in the post's picture viewer
And I should see "This is hella customized" in the framer preview
When I finalize my frame
And I go to "/stream"
Then "This is hella customized" should be post 1
And I click the show page link for "This is hella customized"
And the post's mood should still be "Day"
......@@ -4,6 +4,7 @@ var app = {
helpers: {},
views: {},
pages: {},
forms: {},
user: function(userAttrs) {
if(userAttrs) { return this._user = new app.models.User(userAttrs) }
......
app.forms.Base = app.views.Base.extend({
formSelector : "form",
initialize : function() {
this.setupFormEvents()
},
setupFormEvents : function(){
this.events = {}
this.events['submit ' + this.formSelector] = 'setModelAttributes';
this.delegateEvents();
},
})
app.forms.Picture = app.forms.Base.extend({
templateName : "picture-form",
events : {
'ajax:complete .new_photo' : "photoUploaded",
"change input[name='photo[user_file]']" : "submitForm"
},
initialize : function() {
this.photos = new Backbone.Collection()
this.photos.bind("add", this.render, this)
},
postRenderTemplate : function(){
this.$("input[name=authenticity_token]").val($("meta[name=csrf-token]").attr("content"))
this.$("input[name=photo_ids]").val(this.photos.pluck("id"))
this.renderPhotos();
},
submitForm : function (){
this.$("form").submit();
},
photoUploaded : function(evt, xhr) {
resp = JSON.parse(xhr.responseText)
if(resp.success) {
this.photos.add(new Backbone.Model(resp.data))
} else {
alert("Upload failed! Please try again. " + resp.error);
}
},
renderPhotos : function(){
var photoContainer = this.$(".photos")
this.photos.each(function(photo){
var photoView = new app.views.Photo({model : photo}).render().el
photoContainer.append(photoView)
})
}
});
\ No newline at end of file
app.forms.Post = app.forms.Base.extend({
templateName : "post-form",
formSelector : ".new-post",
subviews : {
".aspect_selector" : "aspectsDropdown",
".service_selector" : "servicesSelector",
".new_picture" : "pictureForm"
},
formAttrs : {
"textarea#text_with_markup" : "text",
"input.aspect_ids" : "aspect_ids",
"input.service:checked" : "services"
},
initialize : function() {
this.aspectsDropdown = new app.views.AspectsDropdown();
this.servicesSelector = new app.views.ServicesSelector();
this.pictureForm = new app.forms.Picture();
this.setupFormEvents();
},
setModelAttributes : function(evt){
if(evt){ evt.preventDefault(); }
var form = this.$(this.formSelector);
this.model.set(_.inject(this.formAttrs, setValueFromField, {}))
//pass collections across
this.model.photos = this.pictureForm.photos
this.model.set({"photos": this.model.photos.toJSON() })
function setValueFromField(memo, attribute, selector){
var selectors = form.find(selector);
if(selectors.length > 1) {
memo[attribute] = _.map(selectors, function(selector){
return $(selector).val()
})
} else {
memo[attribute] = selectors.val();
}
return memo
}
},
postRenderTemplate : function() {
this.prepAndBindMentions()
},
prepAndBindMentions : function(){
Mentions.initialize(this.$("textarea.text"));
Mentions.fetchContacts();
this.$("textarea.text").bind("textchange", $.proxy(this.updateTextWithMarkup, this))
},
updateTextWithMarkup : function() {
this.$("form textarea.text").mentionsInput('val', function(markup){
$('#text_with_markup').val(markup);
});
}
});
\ No newline at end of file
......@@ -90,4 +90,19 @@ app.models.Post = Backbone.Model.extend({
self.trigger('interacted', this)
}});
}
}, {
frameMoods : [
"Day"
],
legacyTemplateNames : [
"status-with-photo-backdrop",
"note",
"rich-media",
"multi-photo",
"photo-backdrop",
"activity-streams-photo",
"status"
]
});
app.models.StatusMessage = app.models.Post.extend({ });
app.models.StatusMessage = app.models.Post.extend({
url : function(){
return this.isNew() ? '/status_messages' : '/posts/' + this.get("id");
},
defaults : {
'post_type' : 'StatusMessage',
'author' : app.currentUser ? app.currentUser.attributes : {}
},
toJSON : function(){
return {
status_message : _.clone(this.attributes),
aspect_ids : this.get("aspect_ids") && this.get("aspect_ids").split(","),
photos : this.photos && this.photos.pluck("id"),
services : mungeServices(this.get("services"))
}
function mungeServices (values) {
if(!values) { return; }
return values.length > 1 ? values : [values]
}
}
});
app.pages.Framer = app.views.Base.extend({
templateName : "framer",
id : "post-content",
events : {
"click button.done" : "saveFrame"
},
subviews : {
".post-view" : "postView",
".template-picker" : "templatePicker"
},
initialize : function(){
this.model = app.frame
this.model.authorIsCurrentUser = function(){ return true }
this.model.bind("change", this.render, this)
this.templatePicker = new app.views.TemplatePicker({ model: this.model })
},
postView : function(){
return app.views.Post.showFactory(this.model)
},
saveFrame : function(){
this.model.save()
}
})
app.pages.PostNew = app.views.Base.extend({
templateName : "post-new",
subviews : { "#new-post" : "postForm"},
events : {
"click button.next" : "navigateNext"
},
initialize : function(){
this.model = new app.models.StatusMessage()
this.postForm = new app.forms.Post({model : this.model})
},
navigateNext : function(){
this.postForm.setModelAttributes()
app.frame = this.model;
app.router.navigate("framer", true)
}
});
......@@ -25,12 +25,7 @@ app.pages.PostViewer = app.views.Base.extend({
this.authorView = new app.views.PostViewerAuthor({ model : this.model });
this.interactionsView = new app.views.PostViewerInteractions({ model : this.model });
this.navView = new app.views.PostViewerNav({ model : this.model });
this.postView = new app.views.Post({
model : this.model,
className : this.model.get("templateName") + " post loaded",
templateName : "post-viewer/content/" + this.model.get("templateName"),
attributes : {"data-template" : this.model.get("templateName")}
});
this.postView = app.views.Post.showFactory(this.model)
this.render();
},
......
......@@ -16,26 +16,37 @@ app.Router = Backbone.Router.extend({
"followed_tags": "stream",
"tags/:name": "stream",
"posts/new" : "newPost",
"posts/:id": "singlePost",
"p/:id": "singlePost"
"p/:id": "singlePost",
"framer": "framer"
},
stream : function() {
app.stream = new app.models.Stream();
app.page = new app.views.Stream({model : app.stream}).render();
app.page = new app.views.Stream({model : app.stream});
app.publisher = app.publisher || new app.views.Publisher({collection : app.stream.posts});
var streamFacesView = new app.views.StreamFaces({collection : app.stream.posts}).render();
var streamFacesView = new app.views.StreamFaces({collection : app.stream.posts});
$("#main_stream").html(app.page.el);
$('#selected_aspect_contacts .content').html(streamFacesView.el);
$("#main_stream").html(app.page.render().el);
$('#selected_aspect_contacts .content').html(streamFacesView.render().el);
},
photos : function() {
app.photos = new app.models.Photos();
app.page = new app.views.Photos({model : app.photos}).render();
app.page = new app.views.Photos({model : app.photos});
$("#main_stream").html(app.page.render().el);
},
newPost : function(){
var page = new app.pages.PostNew();
$("#container").html(page.render().el)
},
$("#main_stream").html(app.page.el);
framer : function(){
var page = new app.pages.Framer();
$("#container").html(page.render().el)
},
singlePost : function(id) {
......
<div class="btn-group aspects_dropdown check-group">
<a class="btn btn-info dropdown-toggle" data-toggle="dropdown" href="#">
<span class="text"></span> <span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li><i class='icon-ok'/><a href="#" class="public" data-aspect-id="public" data-visibility="public">Public</a></li>
<li><i class='icon-ok'/><a href="#" class="all-aspects" data-aspect-id="all_aspects" data-visibility="all-aspects">All Aspects</a></li>
<li class="divider"></li>
{{#each current_user.aspects}}
<li><i class='icon-ok'/><a href="#" data-aspect-id="{{id}}" data-visibility="custom">{{name}}</a></li>
{{/each}}
</ul>
</div>
<input type="hidden" class="aspect_ids"/>
<section class="text">{{{text}}}</section>
<section class="photo_viewer"></section>
<div class="controls">
<div class='template-picker'></div>
<button class="done btn-primary">done</button>
</div>
<div class="post-view"></div>
\ No newline at end of file
{{#each photos}}
<img src="{{sizes.large}}"/>
{{/each}}
\ No newline at end of file
<form accept-charset="UTF-8" action="/photos" class="new_photo" data-remote="true" enctype="multipart/form-data" method="post">
<input name="authenticity_token" type="hidden"/>
<div style="margin:0;padding:0;display:inline">
<input name="utf8" type="hidden" value="✓"/>
</div>
<input name="photo[user_file]" type="file"/>
<div class="photos"></div>
</form>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment