Merge pull request #5178 from svbergerem/new-conversations
Display new conversation form on conversations/index
This commit is contained in:
commit
34bdcb889a
15 changed files with 233 additions and 189 deletions
|
|
@ -39,6 +39,7 @@ The default for including jQuery from a CDN has changed. If you want to continue
|
|||
* Port tag stream to Bootstrap [#5138](https://github.com/diaspora/diaspora/pull/5138)
|
||||
* Consolidate migrations, if you need a migration prior 2013, checkout the latest release in the 0.4.x series first [#5173](https://github.com/diaspora/diaspora/pull/5173)
|
||||
* Add tests for mobile sign up [#5185](https://github.com/diaspora/diaspora/pull/5185)
|
||||
* Display new conversation form on conversations/index [#5178](https://github.com/diaspora/diaspora/pull/5178)
|
||||
|
||||
## Bug fixes
|
||||
* orca cannot see 'Add Contact' button [#5158](https://github.com/diaspora/diaspora/pull/5158)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ app.Router = Backbone.Router.extend({
|
|||
routes: {
|
||||
"help": "help",
|
||||
"contacts": "contacts",
|
||||
"conversations": "conversations",
|
||||
|
||||
//new hotness
|
||||
"posts/:id": "singlePost",
|
||||
|
|
@ -42,6 +43,10 @@ app.Router = Backbone.Router.extend({
|
|||
app.contacts = new app.views.Contacts();
|
||||
},
|
||||
|
||||
conversations: function() {
|
||||
app.conversations = new app.views.Conversations();
|
||||
},
|
||||
|
||||
singlePost : function(id) {
|
||||
this.renderPage(function(){ return new app.pages.SinglePostViewer({ id: id })});
|
||||
},
|
||||
|
|
|
|||
47
app/assets/javascripts/app/views/conversations_view.js
Normal file
47
app/assets/javascripts/app/views/conversations_view.js
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
app.views.Conversations = Backbone.View.extend({
|
||||
|
||||
el: "#conversations_container",
|
||||
|
||||
events: {
|
||||
"mouseenter .stream_element.conversation" : "showParticipants",
|
||||
"mouseleave .stream_element.conversation" : "hideParticipants"
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
$("#people_stream.contacts .header .entypo").tooltip({ 'placement': 'bottom'});
|
||||
// TODO doesn't work anymore
|
||||
if ($('#first_unread').length > 0) {
|
||||
$("html").scrollTop($('#first_unread').offset().top-50);
|
||||
}
|
||||
this.autocompleteInput = $("#contact_autocomplete");
|
||||
this.prepareAutocomplete(gon.contacts);
|
||||
|
||||
$('.timeago').each(function(i,e) {
|
||||
var jqe = $(e);
|
||||
jqe.attr('title', new Date(jqe.attr('datetime')).toLocaleString());
|
||||
})
|
||||
.timeago()
|
||||
.tooltip();
|
||||
},
|
||||
|
||||
hideParticipants: function(e){
|
||||
$(e.currentTarget).find('.participants').slideUp('300');
|
||||
},
|
||||
|
||||
showParticipants: function(e){
|
||||
$(e.currentTarget).find('.participants').slideDown('300');
|
||||
},
|
||||
|
||||
prepareAutocomplete: function(data){
|
||||
this.autocompleteInput.autoSuggest(data, {
|
||||
selectedItemProp: "name",
|
||||
searchObjProps: "name",
|
||||
asHtmlID: "contact_ids",
|
||||
retrieveLimit: 10,
|
||||
minChars: 1,
|
||||
keyDelay: 0,
|
||||
startText: '',
|
||||
emptyText: Diaspora.I18n.t('no_results'),
|
||||
}).focus();
|
||||
}
|
||||
});
|
||||
|
|
@ -5,35 +5,6 @@
|
|||
//= require jquery.autoSuggest.custom
|
||||
|
||||
$(document).ready(function(){
|
||||
|
||||
if ($('#first_unread').length > 0) {
|
||||
$("html").scrollTop($('#first_unread').offset().top-45);
|
||||
}
|
||||
|
||||
$('time.timeago').each(function(i,e) {
|
||||
var jqe = $(e);
|
||||
jqe.attr('data-original-title', new Date(jqe.attr('datetime')).toLocaleString());
|
||||
jqe.attr('title', '');
|
||||
});
|
||||
|
||||
$('.timeago').tooltip();
|
||||
$('.timeago').timeago();
|
||||
|
||||
$('time.timeago').each(function(i,e) {
|
||||
var jqe = $(e);
|
||||
jqe.attr('title', '');
|
||||
});
|
||||
|
||||
$('.stream_element.conversation').hover(
|
||||
function(){
|
||||
$(this).find('.participants').slideDown('300');
|
||||
},
|
||||
|
||||
function(){
|
||||
$(this).find('.participants').slideUp('300');
|
||||
}
|
||||
);
|
||||
|
||||
$(document).on('click', '.conversation-wrapper', function(){
|
||||
var conversation_path = $(this).data('conversation-path');
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,7 @@
|
|||
.conversations_container {
|
||||
#conversations_container {
|
||||
.stream_element {
|
||||
border-bottom: 1px solid $border-grey;
|
||||
&:first-child {
|
||||
border-top: none;
|
||||
}
|
||||
.last_author {
|
||||
font-size: 12px;
|
||||
color: $text-dark-grey;
|
||||
}
|
||||
&:first-child { border-top: none; }
|
||||
a.author{
|
||||
font-weight: bold;
|
||||
unicode-bidi: bidi-override;
|
||||
|
|
@ -17,17 +11,111 @@
|
|||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
}
|
||||
.stream .stream_element {
|
||||
|
||||
p {
|
||||
margin: 0 0 1em 0;
|
||||
word-wrap: break-word;
|
||||
&:last-child { margin-bottom: 0; }
|
||||
}
|
||||
|
||||
.new_message { border-bottom: none; }
|
||||
.timestamp { font-size: 11px; }
|
||||
}
|
||||
|
||||
.stream_element.conversation {
|
||||
padding: 8px;
|
||||
.media {
|
||||
margin-bottom: 0px;
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
&:hover:not(.selected), &.selected {
|
||||
.subject,
|
||||
.last_author,
|
||||
.last_message {
|
||||
color: $white;
|
||||
}
|
||||
.timeago { color: $background-grey; }
|
||||
}
|
||||
|
||||
&:hover, &.unread:hover, &.selected:hover {
|
||||
background-color: lighten($blue,5%);
|
||||
cursor: pointer;
|
||||
}
|
||||
&.unread { background-color: darken($background-white, 5%); }
|
||||
&.selected { background-color: $blue; }
|
||||
|
||||
.avatar {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.last_author, .last_message {
|
||||
font-size: 12px;
|
||||
line-height: 15px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.last_author { color: $text-dark-grey; }
|
||||
|
||||
.message_count, .unread_message_count {
|
||||
margin-left: 3px;
|
||||
float: right;
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.participants_count {
|
||||
@include opacity(0.5);
|
||||
&:before { content: '+'; }
|
||||
float: left;
|
||||
background-color: #fff;
|
||||
margin-top: 35px;
|
||||
margin-left: -50px;
|
||||
text-align: center;
|
||||
width: 50px;
|
||||
height: 15px;
|
||||
line-height: 15px;
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.participants {
|
||||
display: none;
|
||||
float: left;
|
||||
clear: both;
|
||||
margin-top: 5px;
|
||||
padding-top: 5px;
|
||||
height: 25px;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
border-top: 1px dotted $border-grey;
|
||||
.avatar {
|
||||
margin: 0 5px 0 0;
|
||||
height: 25px;
|
||||
width: 25px;
|
||||
}
|
||||
}
|
||||
|
||||
.img { line-height: 15px; }
|
||||
|
||||
.subject {
|
||||
font-size: 14px;
|
||||
> * {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
.timeago {
|
||||
float: right;
|
||||
line-height: normal;
|
||||
font-weight: normal;
|
||||
color: $blue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#conversation_show {
|
||||
|
|
@ -35,7 +123,7 @@
|
|||
box-shadow: 0 2px 3px -3px #666;
|
||||
-webkit-box-shadow: 0 2px 3px -3px #666;
|
||||
-moz-box-shadow: 0 2px 3px -3px #666;
|
||||
|
||||
|
||||
background-color: $background-white;
|
||||
margin-bottom: 5px;
|
||||
border-bottom: 1px solid $border-grey;
|
||||
|
|
@ -62,129 +150,23 @@
|
|||
text-align: right;
|
||||
margin-top: 9px;
|
||||
}
|
||||
|
||||
|
||||
a img { margin-bottom: 4px; }
|
||||
|
||||
.conversation_controls {
|
||||
margin-bottom: 10px;
|
||||
|
||||
|
||||
a { margin-right: 10px; }
|
||||
}
|
||||
}
|
||||
|
||||
.conversation_participants a:hover { text-decoration: none; }
|
||||
|
||||
|
||||
.stream .stream_element {
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.stream_element.conversation {
|
||||
padding: 8px;
|
||||
.media {
|
||||
margin-bottom: 0px;
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
&:hover:not(.selected) {
|
||||
background-color: lighten($blue,5%);
|
||||
.subject,
|
||||
.last_author,
|
||||
.last_message {
|
||||
color: $white;
|
||||
}
|
||||
.timeago { color: $background-grey; }
|
||||
}
|
||||
&.selected:hover { background-color: lighten($blue,5%); }
|
||||
&:hover { cursor: pointer; }
|
||||
|
||||
.avatar {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.last_author, .last_message {
|
||||
font-size: 12px;
|
||||
line-height: 15px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.message_count, .unread_message_count {
|
||||
margin-left: 3px;
|
||||
float: right;
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.participants_count {
|
||||
@include opacity(0.5);
|
||||
&:before { content: '+'; }
|
||||
float: left;
|
||||
background-color: #fff;
|
||||
margin-top: 35px;
|
||||
margin-left: -50px;
|
||||
text-align: center;
|
||||
width: 50px;
|
||||
height: 15px;
|
||||
line-height: 15px;
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.participants {
|
||||
display: none;
|
||||
float: left;
|
||||
clear: both;
|
||||
margin-top: 5px;
|
||||
padding-top: 5px;
|
||||
height: 25px;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
border-top: 1px dotted $border-grey;
|
||||
.avatar {
|
||||
margin: 0 5px 0 0;
|
||||
height: 25px;
|
||||
width: 25px;
|
||||
}
|
||||
}
|
||||
|
||||
.img { line-height: 15px; }
|
||||
|
||||
.subject {
|
||||
font-size: 14px;
|
||||
> * {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
.timeago {
|
||||
float: right;
|
||||
line-height: normal;
|
||||
font-weight: normal;
|
||||
color: $blue;
|
||||
}
|
||||
}
|
||||
|
||||
.conversation.unread {
|
||||
background-color: darken($background-white, 5%);
|
||||
}
|
||||
|
||||
.conversation.selected {
|
||||
background-color: $blue;
|
||||
|
||||
.subject,
|
||||
.last_author,
|
||||
.last_message {
|
||||
color: $white;
|
||||
}
|
||||
.timeago { color: $background-grey; }
|
||||
}
|
||||
|
||||
#left_pane {
|
||||
border-right: solid 1px $border-grey;
|
||||
h3 {
|
||||
|
|
@ -204,6 +186,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
#conversation_new {
|
||||
label { font-weight: bold; }
|
||||
}
|
||||
|
||||
#no_conversations,
|
||||
#no_conversation_text {
|
||||
font-weight: bold;
|
||||
|
|
@ -225,7 +211,7 @@
|
|||
ul.as-selections { width: 100% !important; }
|
||||
input#contact_ids { box-shadow: none; }
|
||||
textarea { width: 98%; }
|
||||
|
||||
|
||||
.bottom_submit_section {
|
||||
text-align: right;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@ class ConversationsController < ApplicationController
|
|||
@ordered_participants = {}
|
||||
@conversations.each { |c| @ordered_participants[c.id] = (c.messages.map{|m| m.author}.reverse + c.participants).uniq }
|
||||
|
||||
gon.contacts = contacts_data
|
||||
|
||||
respond_with do |format|
|
||||
format.html
|
||||
format.json { render :json => @conversations, :status => 200 }
|
||||
|
|
@ -82,25 +84,33 @@ class ConversationsController < ApplicationController
|
|||
end
|
||||
|
||||
def new
|
||||
all_contacts_and_ids = Contact.connection.select_rows(
|
||||
Contact.connection.unprepared_statement {
|
||||
current_user.contacts.where(:sharing => true).joins(:person => :profile).
|
||||
select("contacts.id, profiles.first_name, profiles.last_name, people.diaspora_handle").to_sql
|
||||
}
|
||||
).map{|r| {:value => r[0], :name => ERB::Util.h(Person.name_from_attrs(r[1], r[2], r[3]).gsub(/(")/, "'"))} }
|
||||
if !params[:facebox] && session[:mobile_view] == false && request.format.html?
|
||||
redirect_to conversations_path
|
||||
return
|
||||
end
|
||||
|
||||
@contacts_json = contacts_data.to_json
|
||||
@contact_ids = ""
|
||||
|
||||
@contacts_json = all_contacts_and_ids.to_json
|
||||
if params[:contact_id]
|
||||
@contact_ids = current_user.contacts.find(params[:contact_id]).id
|
||||
elsif params[:aspect_id]
|
||||
@contact_ids = current_user.aspects.find(params[:aspect_id]).contacts.map{|c| c.id}.join(',')
|
||||
end
|
||||
if session[:mobile_view] == true && request.format.html?
|
||||
render :layout => true
|
||||
elsif
|
||||
render :layout => false
|
||||
render :layout => true
|
||||
else
|
||||
render :layout => false
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def contacts_data
|
||||
current_user.contacts.sharing.joins(person: :profile)
|
||||
.pluck(*%w(contacts.id profiles.first_name profiles.last_name people.diaspora_handle))
|
||||
.map {|contact_id, *name_attrs|
|
||||
{value: contact_id, name: ERB::Util.h(Person.name_from_attrs(*name_attrs)) }
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ module ContactsHelper
|
|||
conv_opts = { class: "conversation_button", rel: "facebox"}
|
||||
conv_opts[:title] = t('.many_people_are_you_sure', suggested_limit: suggested_limit) if contacts_size > suggested_limit
|
||||
|
||||
link_to new_conversation_path(aspect_id: aspect.id, name: aspect.name), conv_opts do
|
||||
link_to new_conversation_path(aspect_id: aspect.id, name: aspect.name, facebox: true), conv_opts do
|
||||
content_tag(:i, nil, :class => 'entypo mail contacts-header-icon', :title => t('contacts.index.start_a_conversation'))
|
||||
end
|
||||
end
|
||||
|
|
|
|||
18
app/views/conversations/_new.haml
Normal file
18
app/views/conversations/_new.haml
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
= form_for Conversation.new, html: {class: "form-horizontal form_do_not_clear"}, remote: true do |conversation|
|
||||
.control-group
|
||||
%label.control-label{:for => 'contact_ids'}
|
||||
= t('.to')
|
||||
.controls
|
||||
= text_field_tag "contact_autocomplete"
|
||||
.control-group
|
||||
%label.control-label{:for => 'conversation_subject'}
|
||||
= t('.subject')
|
||||
.controls
|
||||
= conversation.text_field :subject, :class => 'input-block-level'
|
||||
.control-group
|
||||
.controls
|
||||
= text_area_tag "conversation[text]", '', :rows => 5, :class => 'input-block-level'
|
||||
.control-group
|
||||
.controls
|
||||
.pull-right
|
||||
= conversation.submit t('.send'), 'data-disable-with' => t('.sending'), :class => 'btn btn-primary creation'
|
||||
|
|
@ -1,22 +1,17 @@
|
|||
-# Copyright (c) 2010-2011, Diaspora Inc. This file is
|
||||
-# licensed under the Affero General Public License version 3 or later. See
|
||||
-# the COPYRIGHT file.
|
||||
|
||||
|
||||
- content_for :head do
|
||||
= javascript_include_tag :inbox
|
||||
|
||||
- content_for :page_title do
|
||||
= t('.conversations_inbox')
|
||||
|
||||
.container-fluid.conversations_container
|
||||
.container-fluid#conversations_container
|
||||
.row-fluid
|
||||
.span4
|
||||
#left_pane
|
||||
#left_pane_header
|
||||
%h3
|
||||
.pull-right
|
||||
= link_to t('.new_conversation'), new_conversation_path, :class => 'btn btn-default', :rel => 'facebox'
|
||||
.pull-right{ :class => ("hidden" unless @conversation)}
|
||||
= link_to t('.new_conversation'), conversations_path, :class => 'btn btn-default'
|
||||
= t('.inbox')
|
||||
|
||||
#conversation_inbox
|
||||
|
|
@ -28,14 +23,16 @@
|
|||
= t('.no_messages')
|
||||
= will_paginate @conversations, :renderer => WillPaginate::ActionView::BootstrapLinkRenderer
|
||||
|
||||
|
||||
.span8
|
||||
.stream_container
|
||||
#conversation_show
|
||||
- if @conversation
|
||||
- if @conversation
|
||||
.stream_container
|
||||
#conversation_show
|
||||
= render 'conversations/show', :conversation => @conversation
|
||||
- else
|
||||
#no_conversation_text
|
||||
= t('.no_conversation_selected')
|
||||
#no_conversation_controls
|
||||
= link_to t('.create_a_new_conversation'), new_conversation_path, :rel => 'facebox'
|
||||
- else
|
||||
.stream_container.hidden
|
||||
#conversation_show
|
||||
#conversation_new.row-fluid
|
||||
%h3.text-center
|
||||
= t('conversations.index.new_conversation')
|
||||
.span10.offset
|
||||
= render 'conversations/new'
|
||||
|
|
|
|||
|
|
@ -1,3 +1,9 @@
|
|||
if($('.stream_container').hasClass('hidden')){
|
||||
$('#conversation_new').hide();
|
||||
$('.stream_container').removeClass('hidden');
|
||||
$('#left_pane_header .pull-right').removeClass('hidden');
|
||||
}
|
||||
|
||||
$('#conversation_show').html("<%= escape_javascript(render('conversations/show', :conversation => @conversation)) %>");
|
||||
|
||||
$(".stream_element", "#conversation_inbox").removeClass('selected');
|
||||
|
|
@ -10,7 +16,7 @@ $('time.timeago').each(function(i,e) {
|
|||
});
|
||||
|
||||
if ($('#first_unread') > 0) {
|
||||
$("html").scrollTop($('#first_unread').offset().top-45);
|
||||
$("html").scrollTop($('#first_unread').offset().top-50);
|
||||
}
|
||||
|
||||
$(".timeago").tooltip();
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@
|
|||
|
||||
= yield(:head)
|
||||
|
||||
= include_gon(:camel_case => true)
|
||||
%body
|
||||
#app
|
||||
%header#main_nav
|
||||
|
|
@ -67,7 +68,7 @@
|
|||
-# Menu
|
||||
= link_to(image_tag('icons/menu.png'), "#", id: "menu_badge", class: "badge")
|
||||
= link_to(image_tag('icons/asterisk_white_mobile.png'), stream_path, id: 'header_title')
|
||||
|
||||
|
||||
- if user_signed_in?
|
||||
#drawer
|
||||
%header
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
|
||||
.profile_button
|
||||
= link_to content_tag(:div, nil, :class => 'icons-message', :title => t('people.show.message'), :id => 'message_button'), new_conversation_path(:contact_id => @contact.id, :name => @contact.person.name), :rel => 'facebox'
|
||||
= link_to content_tag(:div, nil, :class => 'icons-message', :title => t('people.show.message'), :id => 'message_button'), new_conversation_path(:contact_id => @contact.id, :name => @contact.person.name, :facebox => true), :rel => 'facebox'
|
||||
.white_bar
|
||||
|
||||
.profile_button
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ en:
|
|||
and: "and"
|
||||
comma: ","
|
||||
edit: "Edit"
|
||||
no_results: "No Results Found"
|
||||
timeago:
|
||||
prefixAgo: ""
|
||||
prefixFromNow: ""
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ Feature: private conversations
|
|||
Background:
|
||||
Given a user named "Robert Grimm" with email "bob@bob.bob"
|
||||
And a user named "Alice Awesome" with email "alice@alice.alice"
|
||||
When I sign in as "bob@bob.bob"
|
||||
And a user with username "robert_grimm" is connected with "alice_awesome"
|
||||
When I sign in as "bob@bob.bob"
|
||||
|
||||
Scenario: send a message
|
||||
Given I send a message with subject "Greetings" and text "hello, alice!" to "Alice Awesome"
|
||||
|
|
|
|||
|
|
@ -6,12 +6,13 @@ end
|
|||
|
||||
Then /^I send a message with subject "([^"]*)" and text "([^"]*)" to "([^"]*)"$/ do |subject, text, person|
|
||||
step %(I am on the conversations page)
|
||||
step %(I follow "New conversation")
|
||||
step %(I fill in "contact_autocomplete" with "#{person}" in the modal window)
|
||||
step %(I press the first ".as-result-item" within ".as-results" in the modal window)
|
||||
step %(I fill in "conversation_subject" with "#{subject}" in the modal window)
|
||||
step %(I fill in "conversation_text" with "#{text}" in the modal window)
|
||||
step %(I press "Send" in the modal window)
|
||||
within("#conversation_new", match: :first) do
|
||||
step %(I fill in "contact_autocomplete" with "#{person}")
|
||||
step %(I press the first ".as-result-item" within ".as-results")
|
||||
step %(I fill in "conversation_subject" with "#{subject}")
|
||||
step %(I fill in "conversation_text" with "#{text}")
|
||||
step %(I press "Send")
|
||||
end
|
||||
end
|
||||
|
||||
When /^I reply with "([^"]*)"$/ do |text|
|
||||
|
|
|
|||
Loading…
Reference in a new issue