From 854dcf04db4ad2ac74e02db807a70f702e6b8c89 Mon Sep 17 00:00:00 2001
From: Steffen van Bergerem <svbergerem@online.de>
Date: Fri, 29 Aug 2014 14:33:11 +0200
Subject: [PATCH] Display new conversation form on conversations/index

---
 Changelog.md                                  |   1 +
 app/assets/javascripts/app/router.js          |   5 +
 .../app/views/conversations_view.js           |  47 ++++
 app/assets/javascripts/inbox.js               |  29 ---
 app/assets/stylesheets/conversations.css.scss | 230 ++++++++----------
 app/controllers/conversations_controller.rb   |  30 ++-
 app/helpers/contacts_helper.rb                |   2 +-
 app/views/conversations/_new.haml             |  18 ++
 app/views/conversations/index.haml            |  31 ++-
 app/views/conversations/show.js.erb           |   8 +-
 app/views/layouts/application.mobile.haml     |   3 +-
 app/views/people/_profile_sidebar.html.haml   |   2 +-
 config/locales/javascript/javascript.en.yml   |   1 +
 features/desktop/conversations.feature        |   2 +-
 .../step_definitions/conversations_steps.rb   |  13 +-
 15 files changed, 233 insertions(+), 189 deletions(-)
 create mode 100644 app/assets/javascripts/app/views/conversations_view.js
 create mode 100644 app/views/conversations/_new.haml

diff --git a/Changelog.md b/Changelog.md
index b735f0bd9d..a84195d6b4 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -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)
diff --git a/app/assets/javascripts/app/router.js b/app/assets/javascripts/app/router.js
index 76b9895d56..6012183a90 100644
--- a/app/assets/javascripts/app/router.js
+++ b/app/assets/javascripts/app/router.js
@@ -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 })});
   },
diff --git a/app/assets/javascripts/app/views/conversations_view.js b/app/assets/javascripts/app/views/conversations_view.js
new file mode 100644
index 0000000000..c2701efa4b
--- /dev/null
+++ b/app/assets/javascripts/app/views/conversations_view.js
@@ -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();
+  }
+});
diff --git a/app/assets/javascripts/inbox.js b/app/assets/javascripts/inbox.js
index 5992ca4889..c7892eb34b 100644
--- a/app/assets/javascripts/inbox.js
+++ b/app/assets/javascripts/inbox.js
@@ -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');
 
diff --git a/app/assets/stylesheets/conversations.css.scss b/app/assets/stylesheets/conversations.css.scss
index 10e183f87d..313c72eabd 100644
--- a/app/assets/stylesheets/conversations.css.scss
+++ b/app/assets/stylesheets/conversations.css.scss
@@ -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;
   }
diff --git a/app/controllers/conversations_controller.rb b/app/controllers/conversations_controller.rb
index 1ebc4d81c6..5713a2af50 100644
--- a/app/controllers/conversations_controller.rb
+++ b/app/controllers/conversations_controller.rb
@@ -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
diff --git a/app/helpers/contacts_helper.rb b/app/helpers/contacts_helper.rb
index 0dd9d4bd21..379a073dfb 100644
--- a/app/helpers/contacts_helper.rb
+++ b/app/helpers/contacts_helper.rb
@@ -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
diff --git a/app/views/conversations/_new.haml b/app/views/conversations/_new.haml
new file mode 100644
index 0000000000..bc5a559f57
--- /dev/null
+++ b/app/views/conversations/_new.haml
@@ -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'
diff --git a/app/views/conversations/index.haml b/app/views/conversations/index.haml
index 5252844ecf..35e63b61ee 100644
--- a/app/views/conversations/index.haml
+++ b/app/views/conversations/index.haml
@@ -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'
diff --git a/app/views/conversations/show.js.erb b/app/views/conversations/show.js.erb
index 743b2197e6..660f21abb7 100644
--- a/app/views/conversations/show.js.erb
+++ b/app/views/conversations/show.js.erb
@@ -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();
diff --git a/app/views/layouts/application.mobile.haml b/app/views/layouts/application.mobile.haml
index 78158a9682..ac91997e72 100644
--- a/app/views/layouts/application.mobile.haml
+++ b/app/views/layouts/application.mobile.haml
@@ -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
diff --git a/app/views/people/_profile_sidebar.html.haml b/app/views/people/_profile_sidebar.html.haml
index ef54366465..46a43376a4 100644
--- a/app/views/people/_profile_sidebar.html.haml
+++ b/app/views/people/_profile_sidebar.html.haml
@@ -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
diff --git a/config/locales/javascript/javascript.en.yml b/config/locales/javascript/javascript.en.yml
index a977d733f0..6cd153fd8e 100644
--- a/config/locales/javascript/javascript.en.yml
+++ b/config/locales/javascript/javascript.en.yml
@@ -20,6 +20,7 @@ en:
     and: "and"
     comma: ","
     edit: "Edit"
+    no_results: "No Results Found"
     timeago:
       prefixAgo: ""
       prefixFromNow: ""
diff --git a/features/desktop/conversations.feature b/features/desktop/conversations.feature
index e3c1694685..2c42d4bc76 100644
--- a/features/desktop/conversations.feature
+++ b/features/desktop/conversations.feature
@@ -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"
diff --git a/features/step_definitions/conversations_steps.rb b/features/step_definitions/conversations_steps.rb
index e22bb1b1fb..d087a25418 100644
--- a/features/step_definitions/conversations_steps.rb
+++ b/features/step_definitions/conversations_steps.rb
@@ -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|
-- 
GitLab