diff --git a/app/controllers/people_controller.rb b/app/controllers/people_controller.rb
index ccffa26f3..9b72945e5 100644
--- a/app/controllers/people_controller.rb
+++ b/app/controllers/people_controller.rb
@@ -45,6 +45,7 @@ class PeopleController < ApplicationController
def show
@person = Person.where(:id => params[:id]).first
@post_type = :all
+ @aspect = :profile
@share_with = (params[:share_with] == 'true')
if @person
@@ -57,7 +58,9 @@ class PeopleController < ApplicationController
@aspects_with_person = []
if @contact
@aspects_with_person = @contact.aspects
+ @aspect_ids = @aspects_with_person.map(&:id)
@contacts_of_contact = @contact.contacts
+
else
@contact ||= Contact.new
@contacts_of_contact = []
diff --git a/app/controllers/status_messages_controller.rb b/app/controllers/status_messages_controller.rb
index 09b5b81ac..8c0e0e185 100644
--- a/app/controllers/status_messages_controller.rb
+++ b/app/controllers/status_messages_controller.rb
@@ -9,6 +9,22 @@ class StatusMessagesController < ApplicationController
respond_to :mobile
respond_to :json, :only => :show
+ def new
+ @person = Person.find(params[:person_id])
+ @aspect = :profile
+ @contact = current_user.contact_for(@person)
+ @aspects_with_person = []
+ if @contact
+ @aspects_with_person = @contact.aspects
+ @aspect_ids = @aspects_with_person.map(&:id)
+ @contacts_of_contact = @contact.contacts
+
+ render :layout => nil
+ else
+ redirect_to :back
+ end
+ end
+
def create
params[:status_message][:aspect_ids] = params[:aspect_ids]
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 8bd10648b..2fdc0125b 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -31,17 +31,22 @@ module ApplicationHelper
end
end
- def aspect_badges aspects
+ def aspect_badges aspects, opts = {}
str = ''
aspects.each do |aspect|
- str << aspect_badge(aspect)
+ str << aspect_badge(aspect, opts)
end
str.html_safe
end
- def aspect_badge aspect
+ def aspect_badge aspect, opts = {}
str = ""
- str << link_for_aspect(aspect, 'data-guid' => aspect.id, :class => 'hard_aspect_link').html_safe
+ link = opts.delete(:link)
+ if !link
+ str << link_to(aspect.name, "#", 'data-guid' => aspect.id, :class => 'hard_aspect_link').html_safe
+ else
+ str << link_for_aspect(aspect, 'data-guid' => aspect.id, :class => 'hard_aspect_link').html_safe
+ end
str << ""
end
diff --git a/app/views/aspects/show.html.haml b/app/views/aspects/show.html.haml
index 78fb386cb..81149f9bb 100644
--- a/app/views/aspects/show.html.haml
+++ b/app/views/aspects/show.html.haml
@@ -22,7 +22,7 @@
= render 'aspects/edit_aspect_pane', :contacts => @all_contacts, :aspect => @aspect
.span-15.last
- = render 'shared/publisher', :aspect => @aspect
+ = render 'shared/publisher', :aspect => @aspect, :aspect_ids => @aspect_ids
#main_stream.stream{:data => {:guids => @aspect.id}}
= render 'shared/stream', :posts => @posts
diff --git a/app/views/aspects/show.mobile.haml b/app/views/aspects/show.mobile.haml
index 5ac59fe3b..91ddc6dba 100644
--- a/app/views/aspects/show.mobile.haml
+++ b/app/views/aspects/show.mobile.haml
@@ -2,7 +2,7 @@
-# licensed under the Affero General Public License version 3 or later. See
-# the COPYRIGHT file.
-= render 'shared/publisher', :aspect => @aspect
+= render 'shared/publisher', :aspect => @aspect, :aspect_ids => @aspect_ids
= render 'shared/stream', :posts => @posts
diff --git a/app/views/people/_aspect_list.haml b/app/views/people/_aspect_list.haml
index a7df0a308..8c65d7361 100644
--- a/app/views/people/_aspect_list.haml
+++ b/app/views/people/_aspect_list.haml
@@ -19,7 +19,7 @@
- else
.badges{:class => ("hidden" if !contact.persisted?)}
- = aspect_badges(aspects_with_person)
+ = aspect_badges(aspects_with_person, :link => true)
%p
= link_to t('.edit_membership'),
{:controller => "contacts",
diff --git a/app/views/people/show.html.haml b/app/views/people/show.html.haml
index ed3ec10b9..9acbd7e6f 100644
--- a/app/views/people/show.html.haml
+++ b/app/views/people/show.html.haml
@@ -45,8 +45,9 @@
- else
- - if user_signed_in? && @contact.person
+ - if user_signed_in? && @contact.person && @contact.pending? == false
.right
+ = link_to t('.mention'), new_status_message_path(:person_id => @person.id), :class => 'button', :rel => 'facebox'
= link_to t('.message'), new_conversation_path(:contact_id => @contact.id, :name => @contact.person.name, :contact_id => @contact.id), :class => 'button', :rel => 'facebox'
/- if @post_type == :photos
@@ -70,6 +71,7 @@
= t('.you_have_no_tags')
%span.add_tags
= link_to t('.add_some'), edit_profile_path
+
%hr
- if @posts.count > 0
diff --git a/app/views/shared/_publisher.html.haml b/app/views/shared/_publisher.html.haml
index b2c93bb9b..bcb23eaf7 100644
--- a/app/views/shared/_publisher.html.haml
+++ b/app/views/shared/_publisher.html.haml
@@ -13,7 +13,7 @@
= image_tag 'icons/doc_edit.png'
%span= t('.whats_on_your_mind')
- = t('aspects', :count => @aspect_ids.length)
+ = t('aspects', :count => aspect_ids.length)
.content_creation
= form_for(StatusMessage.new, :remote => true, :html => {"data-type" => "json"}) do |status|
@@ -30,12 +30,18 @@
= status.text_area :fake_text, :rows => 2, :value => h(params[:prefill])
= status.hidden_field :text, :value => '', :class => 'clear_on_submit'
- - for aspect_id in @aspect_ids
+ - for aspect_id in aspect_ids
= hidden_field_tag 'aspect_ids[]', aspect_id.to_s
.options_and_submit
%div.mention_helper
- %i= t('.mention_helper_text')
+ - if aspect != :profile
+ %i= t('.mention_helper_text')
+ - else
+ .badges
+ %i= 'publishing to: '
+ = aspect_badges(aspects_with_person, :link => false)
+
.right
#fileInfo
@@ -58,5 +64,5 @@
= render 'shared/public_explain'
#publisher_photo_upload
- = render 'photos/new_photo', :aspect_ids => @aspect_ids.join(',')
+ = render 'photos/new_photo', :aspect_ids => aspect_ids.join(',')
diff --git a/app/views/shared/_publisher.mobile.haml b/app/views/shared/_publisher.mobile.haml
index 7f850d4ad..0694a5be1 100644
--- a/app/views/shared/_publisher.mobile.haml
+++ b/app/views/shared/_publisher.mobile.haml
@@ -4,7 +4,7 @@
:javascript
$(document).ready(function(){
- $("#status_message_message").bind("focus", function(){
+ $("#status_message_text").bind("focus", function(){
$("#publisher fieldset:first").removeClass('hidden');
});
});
diff --git a/app/views/shared/_stream_element.html.haml b/app/views/shared/_stream_element.html.haml
index 1f31ea14d..d65ac48e3 100644
--- a/app/views/shared/_stream_element.html.haml
+++ b/app/views/shared/_stream_element.html.haml
@@ -26,7 +26,7 @@
= t('the_world')
- elsif post.author.owner_id == current_user.id
%span.aspect_badges
- = aspect_badges(aspects_with_post(all_aspects, post))
+ = aspect_badges(aspects_with_post(all_aspects, post), :link => true)
%span.timeago
= link_to(how_long_ago(post), status_message_path(post))
diff --git a/app/views/status_messages/new.haml b/app/views/status_messages/new.haml
new file mode 100644
index 000000000..9e9d3c142
--- /dev/null
+++ b/app/views/status_messages/new.haml
@@ -0,0 +1,22 @@
+-# Copyright (c) 2010, Diaspora Inc. This file is
+-# licensed under the Affero General Public License version 3 or later. See
+-# the COPYRIGHT file.
+
+
+= javascript_include_tag "publisher.js"
+
+:javascript
+ $(document).ready(function()
+ {
+ var person = {name: '#{@person.name}', handle: '#{@person.diaspora_handle}' };
+ Publisher.autocompletion.onSelect($("#status_message_fake_text"),person,'#{@person.name}');
+ $("#publisher #status_message_submit.button").click(function(){$.facebox.close();});
+ });
+
+#new_status_message_pane
+ .span-15
+ #facebox_header
+ %h4
+ = t('conversations.index.new_message')
+
+ = render :partial => 'shared/publisher', :locals => { :aspect => @aspect, :aspect_ids => @aspect_ids, :aspects_with_person => @aspects_with_person, :person => @person}
diff --git a/config/locales/diaspora/en.yml b/config/locales/diaspora/en.yml
index 97431fe03..25b4404f8 100644
--- a/config/locales/diaspora/en.yml
+++ b/config/locales/diaspora/en.yml
@@ -346,6 +346,7 @@ en:
similar_contacts: "similar contacts"
start_sharing: "start sharing"
message: "Message"
+ mention: "Mention"
profile_sidebar:
remove_contact: "remove contact"
edit_my_profile: "Edit my profile"
diff --git a/config/locales/javascript/javascript.en.yml b/config/locales/javascript/javascript.en.yml
index 75e04f1c4..dc52cfc2b 100644
--- a/config/locales/javascript/javascript.en.yml
+++ b/config/locales/javascript/javascript.en.yml
@@ -29,4 +29,6 @@ en:
shared:
contact_list:
cannot_remove: "Cannot remove person from last aspect. (If you want to disconnect from this person you must remove contact.)"
+ publisher:
+ at_least_one_aspect: "You must publish to at least one aspect"
diff --git a/config/routes.rb b/config/routes.rb
index 6ca436187..7efea6eb3 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -5,7 +5,7 @@
Diaspora::Application.routes.draw do
- resources :status_messages, :only => [:create, :destroy, :show]
+ resources :status_messages, :only => [:new, :create, :destroy, :show]
resources :comments, :only => [:create]
resources :requests, :only => [:destroy, :create]
diff --git a/features/posts.feature b/features/posts.feature
index 45fc98c56..1714b4ca6 100644
--- a/features/posts.feature
+++ b/features/posts.feature
@@ -4,25 +4,28 @@ Feature: posting
As a rock star
I want to tell the world I am eating a yogurt
- Scenario: post to all aspects
- Given that I am a rock star
+ Background:
+ Given a user with username "bob"
+ And a user with username "alice"
+ When I sign in as "bob@bob.bob"
+ And a user with username "bob" is connected with "alice"
+ And I have an aspect called "PostTo"
+ And I have an aspect called "DidntPostTo"
+ And I have user with username "alice" in an aspect called "PostTo"
+ And I have user with username "alice" in an aspect called "DidntPostTo"
+
And I have no open aspects saved
- Given I am signed in
- And I have an aspect called "Family"
- And I am on the home page
- And I expand the publisher
+ And I am on the home page
+
+ Scenario: post to all aspects
+ Given I expand the publisher
When I fill in "status_message_fake_text" with "I am eating a yogurt"
And I press "Share"
And I follow "Home"
Then I should see "I am eating a yogurt" within ".stream_element"
Scenario: delete a post
- Given that I am a rock star
- And I have no open aspects saved
- And I am signed in
- And I have an aspect called "Family"
- And I am on the home page
- And I expand the publisher
+ Given I expand the publisher
When I fill in "status_message_fake_text" with "I am eating a yogurt"
And I press "Share"
And I follow "Home"
@@ -33,12 +36,6 @@ Feature: posting
Then I should not see "I am eating a yogurt"
Scenario Outline: post to one aspect
- Given that I am a rock star
- And I have no open aspects saved
- Given I am signed in
- And I have an aspect called "PostTo"
- And I have an aspect called "DidntPostTo"
- And I am on the home page
When I follow "PostTo"
And I wait for the ajax to finish
And I expand the publisher
@@ -52,3 +49,34 @@ Feature: posting
| aspect | see |
| PostTo | see |
| DidntPostTo | not see |
+
+ Scenario Outline: posting to all aspects from the profile page
+ Given I am on "alice@alice.alice"'s page
+ And I have turned off jQuery effects
+ And I click "Mention" button
+ And I expand the publisher in the modal window
+ And I append "#publisher #status_message_text" with "I am eating a yogurt" in the modal window
+ And I press "Share" in the modal window
+ And I follow ""
+ Then I should "I am eating a yogurt"
+
+ Examples:
+ | aspect | see |
+ | PostTo | see |
+ | DidntPostTo | see |
+
+ Scenario Outline: posting to one aspect from the profile page
+ Given I am on "alice@alice.alice"'s page
+ And I have turned off jQuery effects
+ And I click "Mention" button
+ And I expand the publisher in the modal window
+ And I append "#publisher #status_message_text" with "I am eating a yogurt" in the modal window
+ And I follow "DidntPostTo" within "#publisher" in the modal window
+ And I press "Share" in the modal window
+ And I follow ""
+ Then I should "I am eating a yogurt"
+
+ Examples:
+ | aspect | see |
+ | PostTo | see |
+ | DidntPostTo | not see |
diff --git a/features/step_definitions/custom_web_steps.rb b/features/step_definitions/custom_web_steps.rb
index f86a1d29f..21ac3264e 100644
--- a/features/step_definitions/custom_web_steps.rb
+++ b/features/step_definitions/custom_web_steps.rb
@@ -11,6 +11,13 @@ And /^I expand the publisher$/ do
')
end
+
+When /^(?:|I )append "([^"]*)" with "([^"]*)"$/ do |field, value|
+ script = "$('#{ field }').val(function(index, value) {
+ return value + ' ' + '#{value}'; });"
+ page.execute_script(script)
+end
+
And /^I hover over the post$/ do
page.execute_script('$(".stream_element").first().mouseover()')
end
@@ -19,6 +26,10 @@ When /^I click to delete the first post$/ do
page.execute_script('$(".stream_element").first().find(".delete").click()')
end
+And /^I click "([^"]*)" button$/ do |arg1|
+ page.execute_script('$(".button:contains('+arg1+')").click()')
+end
+
And /^I preemptively confirm the alert$/ do
page.evaluate_script("window.confirm = function() { return true; }")
end
diff --git a/features/step_definitions/user_steps.rb b/features/step_definitions/user_steps.rb
index 192dcafeb..353aaeb6d 100644
--- a/features/step_definitions/user_steps.rb
+++ b/features/step_definitions/user_steps.rb
@@ -16,6 +16,13 @@ Given /^a user with email "([^\"]*)"$/ do |email|
user.aspects.create(:name => "Unicorns")
end
+Given /^a user with username "([^\"]*)"$/ do |username|
+ user = Factory(:user, :email => username + "@" + username + '.' + username, :username => username,
+ :password => 'password', :password_confirmation => 'password', :getting_started => false)
+ user.aspects.create(:name => "Besties")
+ user.aspects.create(:name => "Unicorns")
+end
+
Given /^a user named "([^\"]*)" with email "([^\"]*)"$/ do |name, email|
first, last = name.split
username = "#{first}_#{last}" if first
@@ -45,6 +52,13 @@ Given /^I have an aspect called "([^\"]*)"$/ do |aspect_name|
@me.reload
end
+When /^I have user with username "([^"]*)" in an aspect called "([^"]*)"$/ do |username, aspect|
+ user = User.find_by_username(username)
+ contact = @me.reload.contact_for(user.person)
+ contact.aspects << @me.aspects.find_by_name(aspect)
+end
+
+
Given /^I have one contact request$/ do
other_user = Factory(:user)
other_aspect = other_user.aspects.create!(:name => "meh")
@@ -115,6 +129,12 @@ Given /^a user with email "([^"]*)" is connected with "([^"]*)"$/ do |arg1, arg2
connect_users(user1, user1.aspects.first, user2, user2.aspects.first)
end
+Given /^a user with username "([^"]*)" is connected with "([^"]*)"$/ do |arg1, arg2|
+ user1 = User.where(:username => arg1).first
+ user2 = User.where(:username => arg2).first
+ connect_users(user1, user1.aspects.first, user2, user2.aspects.first)
+end
+
Given /^a user with email "([^\"]*)" has posted a status message "([^\"]*)" in all aspects$/ do |arg1, arg2|
user = User.where(:email => arg1).first
status_message = user.build_post(:status_message, :text => arg2)
diff --git a/public/javascripts/publisher.js b/public/javascripts/publisher.js
index 3e2eaa495..b322e9f80 100644
--- a/public/javascripts/publisher.js
+++ b/public/javascripts/publisher.js
@@ -306,6 +306,26 @@ var Publisher = {
'');
};
},
+ toggleAspectIds: function(aspectId) {
+ var hidden_field = $('#publisher [name="aspect_ids[]"][value="'+aspectId+'"]')
+ if(hidden_field.length > 0){
+ hidden_field.remove();
+ } else {
+ $("#publisher .content_creation form").append(
+ '');
+ };
+ },
+ bindAspectToggles: function() {
+ $('#publisher .aspect_badge').bind("click", function(){
+ var unremovedAspects = $(this).parent().children('.aspect_badge').length - $(this).parent().children(".aspect_badge.removed").length;
+ if(!$(this).hasClass('removed') && ( unremovedAspects == 1 )){
+ alert(Diaspora.widgets.i18n.t('publisher.at_least_one_aspect'))
+ }else{
+ Publisher.toggleAspectIds($(this).children('a').attr('data-guid'));
+ $(this).toggleClass("removed");
+ };
+ });
+ },
initialize: function() {
Publisher.cachedForm = false;
Publisher.cachedInput = false;
@@ -314,6 +334,7 @@ var Publisher = {
Publisher.bindServiceIcons();
Publisher.bindPublicIcon();
+ Publisher.bindAspectToggles();
if ($("#status_message_fake_text").val() == "") {
Publisher.close();
diff --git a/public/stylesheets/sass/application.sass b/public/stylesheets/sass/application.sass
index 0abadf07b..451de9f87 100644
--- a/public/stylesheets/sass/application.sass
+++ b/public/stylesheets/sass/application.sass
@@ -4,6 +4,7 @@
$blue: #3F8FBA
+$red: #FF0000
$background: rgb(252,252,252)
body
@@ -2217,6 +2218,14 @@ h3,h4
&:active
:top 0px
+.aspect_badge.removed
+ :background
+ :color #FA2A00
+ :text
+ :decoration line-through
+ &:hover
+ :background
+ :color #FA2A00
.stream
.avatar
:float left
diff --git a/spec/controllers/people_controller_spec.rb b/spec/controllers/people_controller_spec.rb
index a0c5f775c..78792edc9 100644
--- a/spec/controllers/people_controller_spec.rb
+++ b/spec/controllers/people_controller_spec.rb
@@ -172,6 +172,15 @@ describe PeopleController do
get :show, :id => @person.id
assigns(:posts).should =~ posts_user_can_see
end
+
+ it 'generates a jasmine fixture' do
+ contact = @user.contact_for(@person)
+ aspect = @user.aspects.create(:name => 'people')
+ contact.aspects << aspect
+ contact.save
+ get :show, :id => @person
+ save_fixture(html_for("body"), "person_show")
+ end
end
context "when the person is not a contact of the current user" do
diff --git a/spec/controllers/status_messages_controller_spec.rb b/spec/controllers/status_messages_controller_spec.rb
index 46dd5037c..5c9875042 100644
--- a/spec/controllers/status_messages_controller_spec.rb
+++ b/spec/controllers/status_messages_controller_spec.rb
@@ -20,6 +20,14 @@ describe StatusMessagesController do
@user1.reload
end
+ describe '#new' do
+ it 'succeeds' do
+ get :new,
+ :person_id => @user2.person.id
+ response.should be_success
+ end
+ end
+
describe '#show' do
before do
@message = @user1.build_post :status_message, :text => "ohai", :to => @aspect1.id
diff --git a/spec/javascripts/publisher-spec.js b/spec/javascripts/publisher-spec.js
index c1ce93c9e..0dcbf40da 100644
--- a/spec/javascripts/publisher-spec.js
+++ b/spec/javascripts/publisher-spec.js
@@ -21,6 +21,81 @@ describe("Publisher", function() {
});
});
+ describe("bindAspectToggles", function() {
+ beforeEach( function(){
+ spec.loadFixture('person_show');
+ });
+
+ it('gets called on initialize', function(){
+ spyOn(Publisher, 'bindAspectToggles');
+ Publisher.initialize();
+ expect(Publisher.bindAspectToggles).toHaveBeenCalled();
+ });
+
+ it('toggles removed only on the clicked icon', function(){
+ expect($("#publisher .aspect_badge").first().hasClass("removed")).toBeFalsy();
+ expect($("#publihser .aspect_badge").last().hasClass("removed")).toBeFalsy();
+
+ Publisher.bindAspectToggles();
+ $("#publisher .aspect_badge").last().click();
+
+ expect($("#publisher .aspect_badge").first().hasClass("removed")).toBeFalsy();
+ expect($("#publisher .aspect_badge").last().hasClass("removed")).toBeTruthy();
+ });
+
+ it('binds to the services icons and toggles the hidden field', function(){
+ spyOn(Publisher, 'toggleAspectIds');
+ Publisher.bindAspectToggles();
+ var aspBadge = $("#publisher .aspect_badge a").last();
+ var aspNum = aspBadge.attr('data-guid');
+ aspBadge.click();
+
+ expect(Publisher.toggleAspectIds).toHaveBeenCalledWith(aspNum);
+ });
+
+ it('does not execute if it is the last non-removed aspect', function(){
+ var aspects = $("#publisher .aspect_badge").length;
+ spyOn(Publisher, 'toggleAspectIds');
+
+ Publisher.bindAspectToggles();
+ spyOn(window, 'alert');// click through the dialog if it happens
+ $("#publisher .aspect_badge a").each(function(){$(this).click()});
+
+ var lastAspectNum = $("#publisher .aspect_badge a").last().attr('data-guid');
+
+ expect($("#publisher .aspect_badge.removed").length).toBe(aspects-1);
+ expect(Publisher.toggleAspectIds.callCount).toBe(1);
+ });
+ });
+ describe('toggleAspectIds', function(){
+ beforeEach( function(){
+ spec.loadFixture('person_show');
+ });
+
+ it('adds a hidden field to the form if there is not one already', function(){
+ expect($('#publisher [name="aspect_ids[]"]').length).toBe(2);
+ Publisher.toggleAspectIds(42);
+ expect($('#publisher [name="aspect_ids[]"]').length).toBe(3);
+ expect($('#publisher [name="aspect_ids[]"]').last().attr('value')).toBe('42');
+ });
+
+ it('removes the hidden field if its already there', function() {
+ Publisher.toggleAspectIds(42);
+ expect($('#publisher [name="aspect_ids[]"]').length).toBe(3);
+
+ Publisher.toggleAspectIds(42);
+ expect($('#publisher [name="aspect_ids[]"]').length).toBe(2);
+ });
+
+ it('does not remove a hidden field with a different value', function() {
+ Publisher.toggleAspectIds(42);
+ expect($('#publisher [name="aspect_ids[]"]').length).toBe(3);
+
+ Publisher.toggleAspectIds(99);
+ expect($('#publisher [name="aspect_ids[]"]').length).toBe(4);
+ });
+ });
+
describe("bindPublicIcon", function() {
beforeEach( function(){
spec.loadFixture('aspects_index_services');
diff --git a/spec/javascripts/rails-spec.js b/spec/javascripts/rails-spec.js
index 6d1911f7a..ae6424a21 100644
--- a/spec/javascripts/rails-spec.js
+++ b/spec/javascripts/rails-spec.js
@@ -3,7 +3,7 @@ describe("rails", function() {
beforeEach(function() {
$("#jasmine_content").html(
'