publishing from a person profile page wip

mentioning a person from their profile page, added js & jasmine, still need to add the mention style, and prevent deselecting the last one

a tiny sass add

publishing from the profile works, need js translation

added the translation

made the hover state consistant

need to fix the cucumber spec

specs are green need to add a button

added the buttion to mention people

moved the publisher to the facebox

fixed the cucumbers for the modal window
This commit is contained in:
zhitomirskiyi 2011-03-09 23:24:36 -08:00
parent 5457f48c2a
commit abbf949fe1
24 changed files with 275 additions and 37 deletions

View file

@ -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 = []

View file

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

View file

@ -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 = "<span class='aspect_badge single'>"
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 << "</span>"
end

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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
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 "<aspect>"
Then I should <see> "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 "<aspect>"
Then I should <see> "I am eating a yogurt"
Examples:
| aspect | see |
| PostTo | see |
| DidntPostTo | not see |

View file

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

View file

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

View file

@ -306,6 +306,26 @@ var Publisher = {
'<input id="services_" name="services[]" type="hidden" value="'+service+'">');
};
},
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(
'<input id="aspect_ids_" name="aspect_ids[]" type="hidden" value="'+aspectId+'">');
};
},
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();

View file

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

View file

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

View file

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

View file

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

View file

@ -3,7 +3,7 @@ describe("rails", function() {
beforeEach(function() {
$("#jasmine_content").html(
'<form accept-charset="UTF-8" id="form" action="/status_messages" data-remote="true" method="post">' +
'<textarea id="status_message_message" name="status_message[message]">Some status message</textarea>' +
'<textarea id="status_message_text" name="status_message[text]">Some status message</textarea>' +
'<input type="submit">' +
'<input id="standard_hidden" type="hidden" value="keep this value">' +
'<input id="clearable_hidden" type="hidden" class="clear_on_submit" value="clear this value">' +
@ -12,12 +12,12 @@ describe("rails", function() {
});
it("should retain form values if ajax fails", function() {
$('#form').trigger('ajax:failure');
expect($('#status_message_message').val()).not.toEqual("");
expect($('#status_message_text').val()).not.toEqual("");
});
it("should clear form on ajax:success", function() {
$('#form').trigger('ajax:success');
expect($('#status_message_message').val()).toEqual("");
expect($('#status_message_text').val()).toEqual("");
});
it('should not clear normal hidden fields', function(){

View file

@ -98,7 +98,7 @@ describe("View", function() {
$("#jasmine_content").html(
'<div id="publisher">' +
'<form action="/status_messages" class="new_status_message" id="new_status_message" method="post">' +
'<textarea id="status_message_message" name="status_message[message]"></textarea>' +
'<textarea id="status_message_text" name="status_message[text]"></textarea>' +
'</form>' +
'</div>'
);