diff --git a/Changelog.md b/Changelog.md index b735f0bd9d7569529ce6b35ad34e7e504207b50a..a84195d6b4662a9a73c5fa3a94ad2aba6dc5afd1 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 76b9895d5619ddbd99fee12786590c3707e8db2a..6012183a90ddf6417c5d4abd379b073b103af016 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 0000000000000000000000000000000000000000..c2701efa4b0a15f9ff9e226906c67594168d2d63 --- /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 5992ca4889b3659a16ddab7c408cdae3ee0f74a3..c7892eb34b44670faf6c6768fee2abec01509d4e 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 10e183f87db2d1f2f2af2a985641c9ea41bd9aec..313c72eabd440a0771487de5ae7b02d9b43164f7 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 1ebc4d81c6a270c1828fd7b6a25da875eff9fd56..5713a2af50a8089fe0492d6802fbcd947ba4453a 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 0dd9d4bd21dc7d0fa3080ae5d1c856e79c9ecafe..379a073dfb4486ac473d6da339824b7fbcd00d18 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 0000000000000000000000000000000000000000..bc5a559f57d45cb2749e9c4ede16a212cdc76f13 --- /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 5252844ecfbca288d4d49fef27630e0bc5b9c074..35e63b61ee3cdcf52af37f06570f5506e95f1316 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 743b2197e6eb791f4ffc5df9a22285218342c92b..660f21abb77cc31ae879592c91be2d0247669e98 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 78158a96828c54a88b79dbb3c5c2da567f389230..ac91997e728ab2a64c75bbb4318a8639f6f89793 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 ef54366465be9121c0444eba61dbb57157ae1642..46a43376a4d0c35fa4aef636f03e5f32c6f8d2a6 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 a977d733f0c1893a8fb022fe7dc69186e868d2b4..6cd153fd8e198c2dd24e7fc173511f2ab8300254 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 e3c169468552cc4b5aebc14536f6eca751cb84da..2c42d4bc76a7327f5a7dc86092a38890589f782e 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 e22bb1b1fb5adf820af1fcea2cd5b658f9d92770..d087a254182f4d7c84899e14d8ec3971858e7da4 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|