Fully port conversations to Backbone and drop inbox.js
This commit is contained in:
parent
caf46fdcb9
commit
e424896822
26 changed files with 513 additions and 268 deletions
|
|
@ -9,7 +9,7 @@ app.Router = Backbone.Router.extend({
|
||||||
"commented(/)": "stream",
|
"commented(/)": "stream",
|
||||||
"community_spotlight(/)": "spotlight",
|
"community_spotlight(/)": "spotlight",
|
||||||
"contacts(/)": "contacts",
|
"contacts(/)": "contacts",
|
||||||
"conversations(/)": "conversations",
|
"conversations(/)(:id)(/)": "conversations",
|
||||||
"followed_tags(/)": "followed_tags",
|
"followed_tags(/)": "followed_tags",
|
||||||
"getting_started(/)": "gettingStarted",
|
"getting_started(/)": "gettingStarted",
|
||||||
"help(/)": "help",
|
"help(/)": "help",
|
||||||
|
|
@ -93,8 +93,11 @@ app.Router = Backbone.Router.extend({
|
||||||
app.page = new app.pages.Contacts({stream: stream});
|
app.page = new app.pages.Contacts({stream: stream});
|
||||||
},
|
},
|
||||||
|
|
||||||
conversations: function() {
|
conversations: function(id) {
|
||||||
app.conversations = new app.views.Conversations();
|
app.conversations = app.conversations || new app.views.ConversationsInbox();
|
||||||
|
if (parseInt("" + id, 10)) {
|
||||||
|
app.conversations.renderConversation(id);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,24 @@
|
||||||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||||
|
|
||||||
app.views.ConversationsForm = Backbone.View.extend({
|
app.views.ConversationsForm = Backbone.View.extend({
|
||||||
|
el: ".conversations-form-container",
|
||||||
|
|
||||||
events: {
|
events: {
|
||||||
"keydown textarea#conversation_text" : "keyDown",
|
"keydown .conversation-message-text": "keyDown",
|
||||||
|
"submit #conversation-new": "onSubmitNewConversation"
|
||||||
},
|
},
|
||||||
|
|
||||||
initialize: function(opts) {
|
initialize: function(opts) {
|
||||||
this.contacts = _.has(opts, "contacts") ? opts.contacts : null;
|
this.contacts = _.has(opts, "contacts") ? opts.contacts : null;
|
||||||
if(!this.contacts || this.contacts.length === 0) {
|
|
||||||
this.displayNoContactsMessage();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.prefill = [];
|
this.prefill = [];
|
||||||
if (_.has(opts, "prefillName") && _.has(opts, "prefillValue")) {
|
if (_.has(opts, "prefillName") && _.has(opts, "prefillValue")) {
|
||||||
this.prefill = [{name : opts.prefillName,
|
this.prefill = [{name: opts.prefillName, value: opts.prefillValue}];
|
||||||
value : opts.prefillValue}];
|
|
||||||
}
|
}
|
||||||
this.autocompleteInput = $("#contact_autocomplete");
|
|
||||||
this.prepareAutocomplete(this.contacts);
|
this.prepareAutocomplete(this.contacts);
|
||||||
},
|
},
|
||||||
|
|
||||||
prepareAutocomplete: function(data){
|
prepareAutocomplete: function(data){
|
||||||
this.autocompleteInput.autoSuggest(data, {
|
this.$("#contact-autocomplete").autoSuggest(data, {
|
||||||
selectedItemProp: "name",
|
selectedItemProp: "name",
|
||||||
searchObjProps: "name",
|
searchObjProps: "name",
|
||||||
asHtmlID: "contact_ids",
|
asHtmlID: "contact_ids",
|
||||||
|
|
@ -32,20 +28,26 @@ app.views.ConversationsForm = Backbone.View.extend({
|
||||||
startText: '',
|
startText: '',
|
||||||
emptyText: Diaspora.I18n.t("no_results"),
|
emptyText: Diaspora.I18n.t("no_results"),
|
||||||
preFill: this.prefill
|
preFill: this.prefill
|
||||||
}).focus();
|
});
|
||||||
$("#contact_ids").attr("aria-labelledby", "toLabel");
|
$("#contact_ids").attr("aria-labelledby", "toLabel").focus();
|
||||||
},
|
|
||||||
|
|
||||||
displayNoContactsMessage: function() {
|
|
||||||
$("form#new_conversation").replaceWith(
|
|
||||||
"<div class=\"well text-center\">" + Diaspora.I18n.t("conversation.new.no_contacts") + "</div>"
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
keyDown : function(evt) {
|
keyDown : function(evt) {
|
||||||
if(evt.which === Keycodes.ENTER && evt.ctrlKey) {
|
if(evt.which === Keycodes.ENTER && evt.ctrlKey) {
|
||||||
$(evt.target).parents("form").submit();
|
$(evt.target).parents("form").submit();
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getConversationParticipants: function() {
|
||||||
|
return this.$("#as-values-contact_ids").val().split(",");
|
||||||
|
},
|
||||||
|
|
||||||
|
onSubmitNewConversation: function(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
if (this.getConversationParticipants().length === 0) {
|
||||||
|
evt.stopPropagation();
|
||||||
|
app.flashMessages.error(Diaspora.I18n.t("conversation.create.no_recipient"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// @license-end
|
// @license-end
|
||||||
|
|
|
||||||
82
app/assets/javascripts/app/views/conversations_inbox_view.js
Normal file
82
app/assets/javascripts/app/views/conversations_inbox_view.js
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||||
|
|
||||||
|
app.views.ConversationsInbox = Backbone.View.extend({
|
||||||
|
el: "#conversations-container",
|
||||||
|
|
||||||
|
events: {
|
||||||
|
"click .conversation-wrapper": "displayConversation",
|
||||||
|
"click .new-conversation-btn": "displayNewConversation"
|
||||||
|
},
|
||||||
|
|
||||||
|
initialize: function() {
|
||||||
|
new app.views.ConversationsForm({contacts: gon.contacts});
|
||||||
|
this.setupConversation();
|
||||||
|
},
|
||||||
|
|
||||||
|
renderConversation: function(conversationId) {
|
||||||
|
var self = this;
|
||||||
|
$.ajax({
|
||||||
|
url: Routes.conversationRaw(conversationId),
|
||||||
|
dataType: "html",
|
||||||
|
success: function(data) {
|
||||||
|
self.$el.find("#conversation-new").addClass("hidden");
|
||||||
|
self.$el.find("#conversation-show").removeClass("hidden").html(data);
|
||||||
|
self.selectConversation(conversationId);
|
||||||
|
self.setupConversation();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
selectConversation: function(conversationId) {
|
||||||
|
this.$el.find("#conversation-inbox .stream-element").removeClass("selected");
|
||||||
|
if (conversationId) {
|
||||||
|
this.$el.find("#conversation-inbox .stream-element[data-guid='" + conversationId + "']").addClass("selected");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
displayNewConversation: function(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
evt.stopPropagation();
|
||||||
|
this.$el.find("#conversation-new").removeClass("hidden");
|
||||||
|
this.$el.find("#conversation-show").addClass("hidden");
|
||||||
|
this.selectConversation();
|
||||||
|
app.router.navigate(Routes.conversations());
|
||||||
|
},
|
||||||
|
|
||||||
|
setupConversation: function() {
|
||||||
|
app.helpers.timeago($(this.el));
|
||||||
|
$(".control-icons a").tooltip({placement: "bottom"});
|
||||||
|
|
||||||
|
var conv = $(".conversation-wrapper .stream-element.selected"),
|
||||||
|
cBadge = $("#conversations-link .badge");
|
||||||
|
|
||||||
|
if (conv.hasClass("unread")) {
|
||||||
|
var unreadCount = parseInt(conv.find(".unread-message-count").text(), 10);
|
||||||
|
|
||||||
|
if (cBadge.text() !== "") {
|
||||||
|
cBadge.text().replace(/\d+/, function(num) {
|
||||||
|
num = parseInt(num, 10) - unreadCount;
|
||||||
|
if (num > 0) {
|
||||||
|
cBadge.text(num);
|
||||||
|
} else {
|
||||||
|
cBadge.text(0).addClass("hidden");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
conv.removeClass("unread");
|
||||||
|
conv.find(".unread-message-count").remove();
|
||||||
|
|
||||||
|
var pos = $("#first_unread").offset().top - 50;
|
||||||
|
$("html").animate({scrollTop: pos});
|
||||||
|
} else {
|
||||||
|
$("html").animate({scrollTop: 0});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
displayConversation: function(evt) {
|
||||||
|
var $target = $(evt.target).closest(".conversation-wrapper");
|
||||||
|
app.router.navigate($target.data("conversation-path"), {trigger: true});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// @license-end
|
||||||
|
|
||||||
|
|
@ -1,59 +0,0 @@
|
||||||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
|
||||||
|
|
||||||
app.views.Conversations = Backbone.View.extend({
|
|
||||||
|
|
||||||
el: "#conversations_container",
|
|
||||||
|
|
||||||
events: {
|
|
||||||
"keydown textarea#message_text" : "keyDown",
|
|
||||||
"conversation:loaded" : "setupConversation"
|
|
||||||
},
|
|
||||||
|
|
||||||
initialize: function() {
|
|
||||||
if($("#conversation_new:visible").length > 0) {
|
|
||||||
new app.views.ConversationsForm({
|
|
||||||
el: $("#conversation_new"),
|
|
||||||
contacts: gon.contacts
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.setupConversation();
|
|
||||||
},
|
|
||||||
|
|
||||||
setupConversation: function() {
|
|
||||||
app.helpers.timeago($(this.el));
|
|
||||||
$(".control-icons a").tooltip({placement: "bottom"});
|
|
||||||
|
|
||||||
var conv = $(".conversation-wrapper .stream-element.selected"),
|
|
||||||
cBadge = $("#conversations-link .badge");
|
|
||||||
|
|
||||||
if(conv.hasClass("unread") ){
|
|
||||||
var unreadCount = parseInt(conv.find(".unread-message-count").text(), 10);
|
|
||||||
|
|
||||||
if(cBadge.text() !== "") {
|
|
||||||
cBadge.text().replace(/\d+/, function(num){
|
|
||||||
num = parseInt(num, 10) - unreadCount;
|
|
||||||
if(num > 0) {
|
|
||||||
cBadge.text(num);
|
|
||||||
} else {
|
|
||||||
cBadge.text(0).addClass("hidden");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
conv.removeClass("unread");
|
|
||||||
conv.find(".unread-message-count").remove();
|
|
||||||
|
|
||||||
var pos = $("#first_unread").offset().top - 50;
|
|
||||||
$("html").animate({scrollTop:pos});
|
|
||||||
} else {
|
|
||||||
$("html").animate({scrollTop:0});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
keyDown : function(evt) {
|
|
||||||
if(evt.which === Keycodes.ENTER && evt.ctrlKey) {
|
|
||||||
$(evt.target).parents("form").submit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// @license-end
|
|
||||||
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
|
||||||
$(document).ready(function(){
|
|
||||||
$(document).on('click', '.conversation-wrapper', function(){
|
|
||||||
var conversation_path = $(this).data('conversation-path');
|
|
||||||
$.getScript(conversation_path, function() {
|
|
||||||
Diaspora.page.directionDetector.updateBinds();
|
|
||||||
});
|
|
||||||
history.pushState(null, "", conversation_path);
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
$(window).bind("popstate", function(){
|
|
||||||
if (/conversations\/\d+/.test(location.href)) {
|
|
||||||
$.getScript(location.href, function() {
|
|
||||||
Diaspora.page.directionDetector.updateBinds();
|
|
||||||
});
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
// @license-end
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
//= require templates
|
//= require templates
|
||||||
//= require main
|
//= require main
|
||||||
//= require fileuploader-custom
|
//= require fileuploader-custom
|
||||||
//= require inbox
|
|
||||||
//= require mobile/mobile
|
//= require mobile/mobile
|
||||||
//= require jquery.autoSuggest.custom
|
//= require jquery.autoSuggest.custom
|
||||||
//= require contact-list
|
//= require contact-list
|
||||||
|
|
|
||||||
|
|
@ -594,7 +594,8 @@ form#new_user.new_user input.btn {
|
||||||
text-shadow: 1px 1px 20px rgb(126, 240, 77);
|
text-shadow: 1px 1px 20px rgb(126, 240, 77);
|
||||||
}
|
}
|
||||||
|
|
||||||
#conversation_inbox, .notifications {
|
.conversation-inbox,
|
||||||
|
.notifications {
|
||||||
div.pagination {
|
div.pagination {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ class ConversationsController < ApplicationController
|
||||||
gon.contacts = contacts_data
|
gon.contacts = contacts_data
|
||||||
|
|
||||||
respond_with do |format|
|
respond_with do |format|
|
||||||
format.html
|
format.html { render "index", locals: {no_contacts: current_user.contacts.mutual.empty?} }
|
||||||
format.json { render json: @visibilities.map(&:conversation), status: 200 }
|
format.json { render json: @visibilities.map(&:conversation), status: 200 }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -53,7 +53,7 @@ class ConversationsController < ApplicationController
|
||||||
@response[:success] = false
|
@response[:success] = false
|
||||||
@response[:message] = I18n.t('conversations.create.fail')
|
@response[:message] = I18n.t('conversations.create.fail')
|
||||||
if person_ids.blank?
|
if person_ids.blank?
|
||||||
@response[:message] = I18n.t('conversations.create.no_contact')
|
@response[:message] = I18n.t("javascripts.conversation.create.no_recipient")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
|
|
@ -64,7 +64,7 @@ class ConversationsController < ApplicationController
|
||||||
def show
|
def show
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html do
|
format.html do
|
||||||
redirect_to conversations_path(:conversation_id => params[:id])
|
redirect_to conversations_path(conversation_id: params[:id])
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -72,7 +72,6 @@ class ConversationsController < ApplicationController
|
||||||
@first_unread_message_id = @conversation.first_unread_message(current_user).try(:id)
|
@first_unread_message_id = @conversation.first_unread_message(current_user).try(:id)
|
||||||
@conversation.set_read(current_user)
|
@conversation.set_read(current_user)
|
||||||
|
|
||||||
format.js
|
|
||||||
format.json { render :json => @conversation, :status => 200 }
|
format.json { render :json => @conversation, :status => 200 }
|
||||||
else
|
else
|
||||||
redirect_to conversations_path
|
redirect_to conversations_path
|
||||||
|
|
@ -80,6 +79,17 @@ class ConversationsController < ApplicationController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def raw
|
||||||
|
@conversation = current_user.conversations.where(id: params[:conversation_id]).first
|
||||||
|
if @conversation
|
||||||
|
@first_unread_message_id = @conversation.first_unread_message(current_user).try(:id)
|
||||||
|
@conversation.set_read(current_user)
|
||||||
|
render partial: "conversations/show", locals: {conversation: @conversation}
|
||||||
|
else
|
||||||
|
render nothing: true, status: 404
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def new
|
def new
|
||||||
if !params[:modal] && !session[:mobile_view] && request.format.html?
|
if !params[:modal] && !session[:mobile_view] && request.format.html?
|
||||||
redirect_to conversations_path
|
redirect_to conversations_path
|
||||||
|
|
|
||||||
|
|
@ -6,17 +6,18 @@
|
||||||
.media-left
|
.media-left
|
||||||
= owner_image_tag(:thumb_small)
|
= owner_image_tag(:thumb_small)
|
||||||
.media-body
|
.media-body
|
||||||
= form_for [conversation, Message.new], html: {class: "control-group"} do |message|
|
= form_for [conversation, Message.new], html: {id: "response-message", class: "control-group"} do |message|
|
||||||
.form-group
|
.form-group
|
||||||
%label#messageLabel.sr-only{for: "message_text"}
|
%label.sr-only#message-label{for: "response-message-text"}= t("conversations.new.message")
|
||||||
= t("conversations.new.message")
|
|
||||||
= message.text_area :text,
|
= message.text_area :text,
|
||||||
rows: 5,
|
rows: 5,
|
||||||
tabindex: 1,
|
tabindex: 1,
|
||||||
class: "form-control form-group",
|
id: "response-message-text",
|
||||||
aria: {labelledby: "messageLabel"}
|
class: "form-control form-group conversation-message-text",
|
||||||
|
aria: {labelledby: "message-label"}
|
||||||
|
|
||||||
= message.submit t("conversations.show.reply"),
|
= message.submit t("conversations.show.reply"),
|
||||||
"data-disable-with" => t("conversations.show.replying"),
|
"data-disable-with" => t("conversations.show.replying"),
|
||||||
class: "btn btn-primary pull-right", tabindex: 2
|
:class => "btn btn-primary pull-right",
|
||||||
|
:tabindex => 2
|
||||||
.clearfix
|
.clearfix
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,25 @@
|
||||||
.container-fluid
|
.container-fluid
|
||||||
= form_for Conversation.new, html: {class: "form-horizontal form_do_not_clear"}, remote: true do |conversation|
|
= form_for Conversation.new, html: {id: "new-conversation",
|
||||||
|
class: "new-conversation form-horizontal form-do-not-clear"}, remote: true do |conversation|
|
||||||
.form-group
|
.form-group
|
||||||
%label#toLabel{for: "contact_ids"}
|
%label#toLabel{for: "contact_ids"}
|
||||||
= t(".to")
|
= t(".to")
|
||||||
= text_field_tag "contact_autocomplete", nil, class: "form-control"
|
= text_field_tag "contact_autocomplete", nil, id: "contact-autocomplete", class: "form-control"
|
||||||
.form-group
|
.form-group
|
||||||
%label#subjectLabel{for: "conversation_subject"}
|
%label#subject-label{for: "conversation-subject"}
|
||||||
= t(".subject")
|
= t(".subject")
|
||||||
= conversation.text_field :subject,
|
= conversation.text_field :subject,
|
||||||
|
id: "conversation-subject",
|
||||||
class: "input-block-level form-control",
|
class: "input-block-level form-control",
|
||||||
aria: {labelledby: "subjectLabel"}
|
aria: {labelledby: "subject-label"},
|
||||||
|
value: "",
|
||||||
|
placeholder: t("conversations.new.subject_default")
|
||||||
.form-group
|
.form-group
|
||||||
%label#messageLabel.sr-only{for: "conversation_text"}
|
%label.sr-only#message-label{for: "new-message-text"} = t(".message")
|
||||||
= t(".message")
|
= text_area_tag "conversation[text]", "",
|
||||||
= text_area_tag "conversation[text]",
|
rows: 5,
|
||||||
"",
|
id: "new-message-text",
|
||||||
rows: 5,
|
class: "conversation-message-text input-block-level form-control",
|
||||||
class: "input-block-level form-control",
|
aria: {labelledby: "message-label"}
|
||||||
aria: {labelledby: "messageLabel"}
|
|
||||||
.form-group
|
.form-group
|
||||||
= conversation.submit t('.send'), 'data-disable-with' => t('.sending'), class: 'btn btn-primary pull-right'
|
= conversation.submit t(".send"), "data-disable-with" => t(".sending"), :class => "btn btn-primary pull-right"
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
var response = <%= raw @response.to_json %>;
|
var response = <%= raw @response.to_json %>;
|
||||||
<% if session[:mobile_view] %>
|
<% if session[:mobile_view] %>
|
||||||
|
if(response.success) {
|
||||||
window.location.href = "<%= conversations_path(conversation_id: @conversation.id) %>";
|
window.location.href = "<%= conversations_path(conversation_id: @conversation.id) %>";
|
||||||
|
}
|
||||||
<% else %>
|
<% else %>
|
||||||
if(response.success){
|
if(response.success){
|
||||||
app.flashMessages.success(response.message);
|
app.flashMessages.success(response.message);
|
||||||
$("#new_conversation").removeClass('form_do_not_clear').clearForm();
|
$("#new-conversation").removeClass('form-do-not-clear').clearForm();
|
||||||
window.location.href = "<%= conversations_path(conversation_id: @conversation.id) %>";
|
window.location.href = "<%= conversations_path(conversation_id: @conversation.id) %>";
|
||||||
} else {
|
} else {
|
||||||
app.flashMessages.error(response.message);
|
app.flashMessages.error(response.message);
|
||||||
|
|
|
||||||
|
|
@ -1,41 +1,35 @@
|
||||||
- content_for :head do
|
|
||||||
= javascript_include_tag :inbox
|
|
||||||
|
|
||||||
- content_for :page_title do
|
- content_for :page_title do
|
||||||
= t('.conversations_inbox')
|
= t(".conversations_inbox")
|
||||||
|
|
||||||
.container-fluid#conversations_container
|
.container-fluid#conversations-container
|
||||||
.row
|
.row
|
||||||
.col-md-4
|
.col-md-4
|
||||||
.sidebar#left_pane
|
.sidebar#left_pane
|
||||||
.sidebar-header.clearfix#left_pane_header
|
.sidebar-header.clearfix#left_pane_header
|
||||||
.pull-right
|
.pull-right
|
||||||
= link_to t(".new_conversation"), conversations_path, class: "btn btn-default"
|
= link_to t(".new_conversation"), conversations_path, class: "new-conversation-btn btn btn-default"
|
||||||
%h3
|
%h3
|
||||||
= t(".inbox")
|
= t(".inbox")
|
||||||
|
|
||||||
.conversation-inbox#conversation_inbox
|
.conversation-inbox#conversation-inbox
|
||||||
.stream.conversations
|
.conversations-form-container.stream.conversations
|
||||||
- if @visibilities.count > 0
|
- if @visibilities.count > 0
|
||||||
= render partial: "conversations/conversation", collection: @visibilities, as: :visibility
|
= render partial: "conversations/conversation", collection: @visibilities, as: :visibility
|
||||||
- else
|
- else
|
||||||
.no-conversations
|
.no-conversations
|
||||||
= t('.no_messages')
|
= t(".no_messages")
|
||||||
.pagination-container
|
.pagination-container
|
||||||
= will_paginate @visibilities, previous_label: "«", next_label: "»", inner_window: 1,
|
= will_paginate @visibilities, previous_label: "«", next_label: "»", inner_window: 1,
|
||||||
renderer: WillPaginate::ActionView::BootstrapLinkRenderer
|
renderer: WillPaginate::ActionView::BootstrapLinkRenderer
|
||||||
|
|
||||||
|
|
||||||
.col-md-8
|
.col-md-8
|
||||||
- if @conversation
|
.conversations-form-container.stream_container
|
||||||
.stream_container
|
#conversation-show{class: @conversation ? "" : "hidden"}
|
||||||
#conversation_show
|
- if @conversation
|
||||||
= render 'conversations/show', conversation: @conversation
|
= render 'conversations/show', conversation: @conversation
|
||||||
- else
|
#conversation-new{class: @conversation ? "framed-content clearfix hidden" : "framed-content clearfix"}
|
||||||
.stream_container.hidden
|
|
||||||
#conversation_show
|
|
||||||
.framed-content.clearfix#conversation_new
|
|
||||||
.new-conversation
|
.new-conversation
|
||||||
%h3.text-center
|
%h3.text-center= t("conversations.index.new_conversation")
|
||||||
= t("conversations.index.new_conversation")
|
- if no_contacts
|
||||||
= render "conversations/new"
|
.well.text-center= t("javascripts.conversation.new.no_contacts")
|
||||||
|
- else
|
||||||
|
= render "conversations/new"
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
.stream
|
.stream
|
||||||
%p{ class: "conversation_#{name}" }= msg
|
%p{ class: "conversation_#{name}" }= msg
|
||||||
|
|
||||||
#conversation_inbox
|
.conversation-inbox#conversation-inbox
|
||||||
.stream.conversations
|
.stream.conversations
|
||||||
- if @visibilities.count > 0
|
- if @visibilities.count > 0
|
||||||
= render partial: "conversations/conversation", collection: @visibilities, as: :visibility
|
= render partial: "conversations/conversation", collection: @visibilities, as: :visibility
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
:javascript
|
:javascript
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
var data = $.parseJSON( "#{escape_javascript(@contacts_json)}" ),
|
var data = $.parseJSON( "#{escape_javascript(@contacts_json)}" ),
|
||||||
autocompleteInput = $("#contact_autocomplete");
|
autocompleteInput = $("#contact-autocomplete");
|
||||||
|
|
||||||
autocompleteInput.autoSuggest(data, {
|
autocompleteInput.autoSuggest(data, {
|
||||||
selectedItemProp: "name",
|
selectedItemProp: "name",
|
||||||
|
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
if($('.stream_container').hasClass('hidden')){
|
|
||||||
$('#conversation_new').hide();
|
|
||||||
$('.stream_container').removeClass('hidden');
|
|
||||||
}
|
|
||||||
|
|
||||||
$('#conversation_show').html("<%= escape_javascript(render('conversations/show', :conversation => @conversation)) %>");
|
|
||||||
|
|
||||||
$(".stream-element", "#conversation_inbox").removeClass('selected');
|
|
||||||
$(".stream-element[data-guid='<%= @conversation.id %>']", "#conversation_inbox").addClass('selected');
|
|
||||||
$('#conversation_show').trigger("conversation:loaded");
|
|
||||||
|
|
@ -27,7 +27,7 @@
|
||||||
id: 'mentionModal'
|
id: 'mentionModal'
|
||||||
|
|
||||||
-if @contact
|
-if @contact
|
||||||
#new_conversation_pane
|
.conversations-form-container#new_conversation_pane
|
||||||
= render 'shared/modal',
|
= render 'shared/modal',
|
||||||
path: new_conversation_path(:contact_id => @contact.id, name: @contact.person.name, modal: true),
|
path: new_conversation_path(:contact_id => @contact.id, name: @contact.person.name, modal: true),
|
||||||
title: t('conversations.index.new_conversation'),
|
title: t('conversations.index.new_conversation'),
|
||||||
|
|
|
||||||
|
|
@ -274,6 +274,7 @@ en:
|
||||||
new_conversation: "New conversation"
|
new_conversation: "New conversation"
|
||||||
no_messages: "No messages"
|
no_messages: "No messages"
|
||||||
inbox: "Inbox"
|
inbox: "Inbox"
|
||||||
|
no_contacts: "You need to add some contacts before you can start a conversation"
|
||||||
show:
|
show:
|
||||||
reply: "Reply"
|
reply: "Reply"
|
||||||
replying: "Replying..."
|
replying: "Replying..."
|
||||||
|
|
@ -290,7 +291,6 @@ en:
|
||||||
create:
|
create:
|
||||||
sent: "Message sent"
|
sent: "Message sent"
|
||||||
fail: "Invalid message"
|
fail: "Invalid message"
|
||||||
no_contact: "Hey, you need to add the contact first!"
|
|
||||||
new_conversation:
|
new_conversation:
|
||||||
fail: "Invalid message"
|
fail: "Invalid message"
|
||||||
destroy:
|
destroy:
|
||||||
|
|
|
||||||
|
|
@ -240,6 +240,8 @@ en:
|
||||||
posts: "Posts"
|
posts: "Posts"
|
||||||
|
|
||||||
conversation:
|
conversation:
|
||||||
|
create:
|
||||||
|
no_recipient: "Hey, you need to add a recipient first!"
|
||||||
new:
|
new:
|
||||||
no_contacts: "You need to add some contacts before you can start a conversation."
|
no_contacts: "You need to add some contacts before you can start a conversation."
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,7 @@ Diaspora::Application.routes.draw do
|
||||||
resources :conversations, except: %i(edit update destroy) do
|
resources :conversations, except: %i(edit update destroy) do
|
||||||
resources :messages, only: %i(create)
|
resources :messages, only: %i(create)
|
||||||
delete 'visibility' => 'conversation_visibilities#destroy'
|
delete 'visibility' => 'conversation_visibilities#destroy'
|
||||||
|
get "raw"
|
||||||
end
|
end
|
||||||
|
|
||||||
resources :notifications, :only => [:index, :update] do
|
resources :notifications, :only => [:index, :update] do
|
||||||
|
|
|
||||||
|
|
@ -18,10 +18,10 @@ Feature: private conversations
|
||||||
Scenario: send a message
|
Scenario: send a message
|
||||||
When I sign in as "bob@bob.bob"
|
When I sign in as "bob@bob.bob"
|
||||||
And I send a message with subject "Greetings" and text "hello, alice!" to "Alice Awesome"
|
And I send a message with subject "Greetings" and text "hello, alice!" to "Alice Awesome"
|
||||||
Then I should see "Greetings" within "#conversation_inbox"
|
Then I should see "Greetings" within "#conversation-inbox"
|
||||||
And I should see "Greetings" within "#conversation_show"
|
And I should see "Greetings" within "#conversation-show"
|
||||||
And I should see "less than a minute ago" within "#conversation_inbox"
|
And I should see "less than a minute ago" within "#conversation-inbox"
|
||||||
And I should see "less than a minute ago" within "#conversation_show"
|
And I should see "less than a minute ago" within "#conversation-show"
|
||||||
And I should see "Alice Awesome" as a participant
|
And I should see "Alice Awesome" as a participant
|
||||||
And "Alice Awesome" should be part of active conversation
|
And "Alice Awesome" should be part of active conversation
|
||||||
And I should see "hello, alice!" within ".stream_container"
|
And I should see "hello, alice!" within ".stream_container"
|
||||||
|
|
@ -34,8 +34,8 @@ Feature: private conversations
|
||||||
Scenario: send a message using keyboard shortcuts
|
Scenario: send a message using keyboard shortcuts
|
||||||
When I sign in as "bob@bob.bob"
|
When I sign in as "bob@bob.bob"
|
||||||
And I send a message with subject "Greetings" and text "hello, alice!" to "Alice Awesome" using keyboard shortcuts
|
And I send a message with subject "Greetings" and text "hello, alice!" to "Alice Awesome" using keyboard shortcuts
|
||||||
Then I should see "Greetings" within "#conversation_inbox"
|
Then I should see "Greetings" within "#conversation-inbox"
|
||||||
And I should see "Greetings" within "#conversation_show"
|
And I should see "Greetings" within "#conversation-show"
|
||||||
And "Alice Awesome" should be part of active conversation
|
And "Alice Awesome" should be part of active conversation
|
||||||
And I should see "hello, alice!" within ".stream_container"
|
And I should see "hello, alice!" within ".stream_container"
|
||||||
When I reply with "hey, how you doing?" using keyboard shortcuts
|
When I reply with "hey, how you doing?" using keyboard shortcuts
|
||||||
|
|
@ -47,9 +47,9 @@ Feature: private conversations
|
||||||
Scenario: delete a conversation
|
Scenario: delete a conversation
|
||||||
When I sign in as "bob@bob.bob"
|
When I sign in as "bob@bob.bob"
|
||||||
And I send a message with subject "Greetings" and text "hello, alice!" to "Alice Awesome"
|
And I send a message with subject "Greetings" and text "hello, alice!" to "Alice Awesome"
|
||||||
Then I should see "Greetings" within "#conversation_inbox"
|
Then I should see "Greetings" within "#conversation-inbox"
|
||||||
When I click on selector ".hide_conversation"
|
When I click on selector ".hide_conversation"
|
||||||
Then I should not see "Greetings" within "#conversation_inbox"
|
Then I should not see "Greetings" within "#conversation-inbox"
|
||||||
When I sign in as "alice@alice.alice"
|
When I sign in as "alice@alice.alice"
|
||||||
Then I should have 1 unread private message
|
Then I should have 1 unread private message
|
||||||
And I should have 1 email delivery
|
And I should have 1 email delivery
|
||||||
|
|
|
||||||
|
|
@ -14,38 +14,38 @@ end
|
||||||
|
|
||||||
Then /^I send a message with subject "([^"]*)" and text "([^"]*)" to "([^"]*)"$/ do |subject, text, person|
|
Then /^I send a message with subject "([^"]*)" and text "([^"]*)" to "([^"]*)"$/ do |subject, text, person|
|
||||||
step %(I am on the conversations page)
|
step %(I am on the conversations page)
|
||||||
within("#conversation_new", match: :first) do
|
within("#new-conversation", match: :first) do
|
||||||
step %(I fill in "contact_autocomplete" with "#{person}")
|
step %(I fill in "contact_autocomplete" with "#{person}")
|
||||||
step %(I press the first ".as-result-item" within ".as-results")
|
step %(I press the first ".as-result-item" within ".as-results")
|
||||||
step %(I fill in "conversation_subject" with "#{subject}")
|
step %(I fill in "conversation-subject" with "#{subject}")
|
||||||
step %(I fill in "conversation_text" with "#{text}")
|
step %(I fill in "new-message-text" with "#{text}")
|
||||||
step %(I press "Send")
|
step %(I press "Send")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Then /^I send a message with subject "([^"]*)" and text "([^"]*)" to "([^"]*)" using keyboard shortcuts$/ do |subject, text, person|
|
Then /^I send a message with subject "([^"]*)" and text "([^"]*)" to "([^"]*)" using keyboard shortcuts$/ do |subject, text, person|
|
||||||
step %(I am on the conversations page)
|
step %(I am on the conversations page)
|
||||||
within("#conversation_new", match: :first) do
|
within("#new-conversation", match: :first) do
|
||||||
step %(I fill in "contact_autocomplete" with "#{person}")
|
step %(I fill in "contact_autocomplete" with "#{person}")
|
||||||
step %(I press the first ".as-result-item" within ".as-results")
|
step %(I press the first ".as-result-item" within ".as-results")
|
||||||
step %(I fill in "conversation_subject" with "#{subject}")
|
step %(I fill in "conversation-subject" with "#{subject}")
|
||||||
step %(I fill in "conversation_text" with "#{text}")
|
step %(I fill in "new-message-text" with "#{text}")
|
||||||
find("#conversation_text").native.send_key %i(Ctrl Return)
|
find("#new-message-text").native.send_key %i(Ctrl Return)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
When /^I reply with "([^"]*)"$/ do |text|
|
When /^I reply with "([^"]*)"$/ do |text|
|
||||||
step %(I am on the conversations page)
|
step %(I am on the conversations page)
|
||||||
step %(I press the first ".conversation" within ".conversations")
|
step %(I press the first ".conversation" within ".conversations")
|
||||||
step %(I fill in "message_text" with "#{text}")
|
step %(I fill in "response-message-text" with "#{text}")
|
||||||
step %(I press "Reply")
|
step %(I press "Reply")
|
||||||
end
|
end
|
||||||
|
|
||||||
When /^I reply with "([^"]*)" using keyboard shortcuts$/ do |text|
|
When /^I reply with "([^"]*)" using keyboard shortcuts$/ do |text|
|
||||||
step %(I am on the conversations page)
|
step %(I am on the conversations page)
|
||||||
step %(I press the first ".conversation" within ".conversations")
|
step %(I press the first ".conversation" within ".conversations")
|
||||||
step %(I fill in "message_text" with "#{text}")
|
step %(I fill in "response-message-text" with "#{text}")
|
||||||
find("#message_text").native.send_key %i(Ctrl Return)
|
find("#response-message-text").native.send_key %i(Ctrl Return)
|
||||||
end
|
end
|
||||||
|
|
||||||
Then /^I send a mobile message with subject "([^"]*)" and text "([^"]*)" to "([^"]*)"$/ do |subject, text, person|
|
Then /^I send a mobile message with subject "([^"]*)" and text "([^"]*)" to "([^"]*)"$/ do |subject, text, person|
|
||||||
|
|
@ -53,8 +53,8 @@ Then /^I send a mobile message with subject "([^"]*)" and text "([^"]*)" to "([^
|
||||||
step %(I follow "New conversation")
|
step %(I follow "New conversation")
|
||||||
step %(I fill in "contact_autocomplete" with "#{person}")
|
step %(I fill in "contact_autocomplete" with "#{person}")
|
||||||
step %(I press the first ".as-result-item" within ".as-results")
|
step %(I press the first ".as-result-item" within ".as-results")
|
||||||
step %(I fill in "conversation_subject" with "#{subject}")
|
step %(I fill in "conversation-subject" with "#{subject}")
|
||||||
step %(I fill in "conversation_text" with "#{text}")
|
step %(I fill in "new-message-text" with "#{text}")
|
||||||
step %(I press "Send")
|
step %(I press "Send")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -259,7 +259,7 @@ describe ConversationsController, :type => :controller do
|
||||||
it 'should set response with success to false and message to fail due to no contact' do
|
it 'should set response with success to false and message to fail due to no contact' do
|
||||||
post :create, @hash
|
post :create, @hash
|
||||||
expect(assigns[:response][:success]).to eq(false)
|
expect(assigns[:response][:success]).to eq(false)
|
||||||
expect(assigns[:response][:message]).to eq(I18n.t('conversations.create.no_contact'))
|
expect(assigns[:response][:message]).to eq(I18n.t("javascripts.conversation.create.no_recipient"))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -300,12 +300,6 @@ describe ConversationsController, :type => :controller do
|
||||||
@conversation = Conversation.create(hash)
|
@conversation = Conversation.create(hash)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'succeeds with js' do
|
|
||||||
xhr :get, :show, :id => @conversation.id, :format => :js
|
|
||||||
expect(response).to be_success
|
|
||||||
expect(assigns[:conversation]).to eq(@conversation)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'succeeds with json' do
|
it 'succeeds with json' do
|
||||||
get :show, :id => @conversation.id, :format => :json
|
get :show, :id => @conversation.id, :format => :json
|
||||||
expect(response).to be_success
|
expect(response).to be_success
|
||||||
|
|
@ -318,4 +312,26 @@ describe ConversationsController, :type => :controller do
|
||||||
expect(response).to redirect_to(conversations_path(:conversation_id => @conversation.id))
|
expect(response).to redirect_to(conversations_path(:conversation_id => @conversation.id))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#raw" do
|
||||||
|
before do
|
||||||
|
hash = {
|
||||||
|
author: alice.person,
|
||||||
|
participant_ids: [alice.contacts.first.person.id, alice.person.id],
|
||||||
|
subject: "not spam",
|
||||||
|
messages_attributes: [{author: alice.person, text: "cool stuff"}]
|
||||||
|
}
|
||||||
|
@conversation = Conversation.create(hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns html of conversation" do
|
||||||
|
get :raw, conversation_id: @conversation.id
|
||||||
|
expect(response).to render_template(partial: "show", locals: {conversation: @conversation})
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns 404 when requesting non-existant conversation" do
|
||||||
|
get :raw, conversation_id: -1
|
||||||
|
expect(response).to have_http_status(404)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,30 @@ describe('app.Router', function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("conversations", function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
this.router = new app.Router();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("doesn't do anything if no conversation id is passed", function() {
|
||||||
|
spyOn(app.views.ConversationsInbox.prototype, "renderConversation");
|
||||||
|
this.router.conversations();
|
||||||
|
expect(app.views.ConversationsInbox.prototype.renderConversation).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("doesn't do anything if id is not a readable number", function() {
|
||||||
|
spyOn(app.views.ConversationsInbox.prototype, "renderConversation");
|
||||||
|
this.router.conversations("yolo");
|
||||||
|
expect(app.views.ConversationsInbox.prototype.renderConversation).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders the conversation if id is a readable number", function() {
|
||||||
|
spyOn(app.views.ConversationsInbox.prototype, "renderConversation");
|
||||||
|
this.router.conversations("12");
|
||||||
|
expect(app.views.ConversationsInbox.prototype.renderConversation).toHaveBeenCalledWith("12");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("stream", function() {
|
describe("stream", function() {
|
||||||
it("calls _initializeStreamView", function() {
|
it("calls _initializeStreamView", function() {
|
||||||
spyOn(app.router, "_initializeStreamView");
|
spyOn(app.router, "_initializeStreamView");
|
||||||
|
|
|
||||||
110
spec/javascripts/app/views/conversations_form_view_spec.js
Normal file
110
spec/javascripts/app/views/conversations_form_view_spec.js
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
describe("app.views.ConversationsForm", function() {
|
||||||
|
describe("keyDown", function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
this.submitCallback = jasmine.createSpy().and.returnValue(false);
|
||||||
|
spec.loadFixture("conversations_read");
|
||||||
|
new app.views.ConversationsForm();
|
||||||
|
});
|
||||||
|
|
||||||
|
context("on new message form", function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
$("#conversation-new").removeClass("hidden");
|
||||||
|
$("#conversation-show").addClass("hidden");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should submit the form with ctrl+enter", function() {
|
||||||
|
$("#new-conversation").submit(this.submitCallback);
|
||||||
|
var e = $.Event("keydown", {which: Keycodes.ENTER, ctrlKey: true});
|
||||||
|
$("#new-message-text").trigger(e);
|
||||||
|
expect(this.submitCallback).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shouldn't submit the form without the ctrl key", function() {
|
||||||
|
$("#new-conversation").submit(this.submitCallback);
|
||||||
|
var e = $.Event("keydown", {which: Keycodes.ENTER, ctrlKey: false});
|
||||||
|
$("#new-message-text").trigger(e);
|
||||||
|
expect(this.submitCallback).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
context("on response message form", function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
$("#conversation-new").addClass("hidden");
|
||||||
|
$("#conversation-show").removeClass("hidden");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should submit the form with ctrl+enter", function() {
|
||||||
|
$("#response-message").submit(this.submitCallback);
|
||||||
|
var e = $.Event("keydown", {which: Keycodes.ENTER, ctrlKey: true});
|
||||||
|
$("#response-message-text").trigger(e);
|
||||||
|
expect(this.submitCallback).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shouldn't submit the form without the ctrl key", function() {
|
||||||
|
$("#response-message").submit(this.submitCallback);
|
||||||
|
var e = $.Event("keydown", {which: Keycodes.ENTER, ctrlKey: false});
|
||||||
|
$("#response-message-text").trigger(e);
|
||||||
|
expect(this.submitCallback).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("onSubmitNewConversation", function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
spec.loadFixture("conversations_read");
|
||||||
|
$("#conversation-new").removeClass("hidden");
|
||||||
|
$("#conversation-show").addClass("hidden");
|
||||||
|
spyOn(app.views.ConversationsForm.prototype, "onSubmitNewConversation").and.callThrough();
|
||||||
|
this.target = new app.views.ConversationsForm();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("onSubmitNewConversation is called when submitting the conversation form", function() {
|
||||||
|
spyOn(app.views.ConversationsForm.prototype, "getConversationParticipants").and.returnValue([]);
|
||||||
|
$("#conversation-new").trigger("submit");
|
||||||
|
|
||||||
|
expect(app.views.ConversationsForm.prototype.onSubmitNewConversation).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not submit a conversation with no recipient", function() {
|
||||||
|
spyOn(app.views.ConversationsForm.prototype, "getConversationParticipants").and.returnValue([]);
|
||||||
|
var event = jasmine.createSpyObj("event", ["preventDefault", "stopPropagation"]);
|
||||||
|
|
||||||
|
this.target.onSubmitNewConversation(event);
|
||||||
|
|
||||||
|
expect(event.preventDefault).toHaveBeenCalled();
|
||||||
|
expect(event.stopPropagation).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("submits a conversation with recipients", function() {
|
||||||
|
spyOn(app.views.ConversationsForm.prototype, "getConversationParticipants").and.returnValue([1]);
|
||||||
|
var event = jasmine.createSpyObj("event", ["preventDefault", "stopPropagation"]);
|
||||||
|
|
||||||
|
this.target.onSubmitNewConversation(event);
|
||||||
|
|
||||||
|
expect(event.preventDefault).toHaveBeenCalled();
|
||||||
|
expect(event.stopPropagation).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("flashes an error message when submitting a conversation with no recipient", function() {
|
||||||
|
spyOn(app.views.FlashMessages.prototype, "error");
|
||||||
|
spyOn(app.views.ConversationsForm.prototype, "getConversationParticipants").and.returnValue([]);
|
||||||
|
var event = jasmine.createSpyObj("event", ["preventDefault", "stopPropagation"]);
|
||||||
|
|
||||||
|
this.target.onSubmitNewConversation(event);
|
||||||
|
|
||||||
|
expect(app.views.FlashMessages.prototype.error)
|
||||||
|
.toHaveBeenCalledWith(Diaspora.I18n.t("conversation.create.no_recipient"));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not flash an error message when submitting a conversation with recipients", function() {
|
||||||
|
spyOn(app.views.FlashMessages.prototype, "error");
|
||||||
|
spyOn(app.views.ConversationsForm.prototype, "getConversationParticipants").and.returnValue([1]);
|
||||||
|
var event = jasmine.createSpyObj("event", ["preventDefault", "stopPropagation"]);
|
||||||
|
|
||||||
|
this.target.onSubmitNewConversation(event);
|
||||||
|
|
||||||
|
expect(app.views.FlashMessages.prototype.error).not
|
||||||
|
.toHaveBeenCalledWith(Diaspora.I18n.t("conversation.create.no_recipient"));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
164
spec/javascripts/app/views/conversations_inbox_view_spec.js
Normal file
164
spec/javascripts/app/views/conversations_inbox_view_spec.js
Normal file
|
|
@ -0,0 +1,164 @@
|
||||||
|
describe("app.views.ConversationsInbox", function() {
|
||||||
|
describe("initialize", function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
spec.loadFixture("conversations_read");
|
||||||
|
$("#conversation-new").removeClass("hidden");
|
||||||
|
$("#conversation-show").addClass("hidden");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("initializes the conversations form", function() {
|
||||||
|
spyOn(app.views.ConversationsForm.prototype, "initialize");
|
||||||
|
new app.views.ConversationsInbox();
|
||||||
|
expect(app.views.ConversationsForm.prototype.initialize).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("call setupConversation", function() {
|
||||||
|
spyOn(app.views.ConversationsInbox.prototype, "setupConversation");
|
||||||
|
new app.views.ConversationsInbox();
|
||||||
|
expect(app.views.ConversationsInbox.prototype.setupConversation).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("renderConversation", function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
spec.loadFixture("conversations_read");
|
||||||
|
$("#conversation-new").removeClass("hidden");
|
||||||
|
$("#conversation-show").addClass("hidden");
|
||||||
|
var conversations = $("#conversation-inbox .stream-element");
|
||||||
|
conversations.removeClass("selected");
|
||||||
|
this.conversationId = conversations.first().data("guid");
|
||||||
|
this.target = new app.views.ConversationsInbox();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders conversation of given id", function() {
|
||||||
|
spyOn($, "ajax").and.callThrough();
|
||||||
|
spyOn(app.views.ConversationsInbox.prototype, "selectConversation");
|
||||||
|
spyOn(app.views.ConversationsInbox.prototype, "setupConversation");
|
||||||
|
this.target.renderConversation(this.conversationId);
|
||||||
|
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||||
|
status: 200,
|
||||||
|
responseText: "<div id='fake-conversation-content'></div>"
|
||||||
|
});
|
||||||
|
|
||||||
|
expect($.ajax).toHaveBeenCalled();
|
||||||
|
expect(jasmine.Ajax.requests.mostRecent().url).toBe("/conversations/" + this.conversationId + "/raw");
|
||||||
|
expect(app.views.ConversationsInbox.prototype.selectConversation).toHaveBeenCalledWith(this.conversationId);
|
||||||
|
expect(app.views.ConversationsInbox.prototype.setupConversation).toHaveBeenCalled();
|
||||||
|
expect($("#conversation-new")).toHaveClass("hidden");
|
||||||
|
expect($("#conversation-show")).not.toHaveClass("hidden");
|
||||||
|
expect($("#conversation-show #fake-conversation-content").length).toBe(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("selectConversation", function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
spec.loadFixture("conversations_read");
|
||||||
|
this.conversationId = $("#conversation-inbox .stream-element").first().data("guid");
|
||||||
|
this.target = new app.views.ConversationsInbox();
|
||||||
|
$("#conversation-inbox .stream-element").addClass("selected");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("unselects every conversation if called with no parameters", function() {
|
||||||
|
expect($("#conversation-inbox .stream-element.selected").length).not.toBe(0);
|
||||||
|
this.target.selectConversation();
|
||||||
|
expect($("#conversation-inbox .stream-element.selected").length).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("selects the given conversation", function() {
|
||||||
|
expect($("#conversation-inbox .stream-element.selected").length).not.toBe(1);
|
||||||
|
this.target.selectConversation(this.conversationId);
|
||||||
|
expect($("#conversation-inbox .stream-element.selected").length).toBe(1);
|
||||||
|
expect($("#conversation-inbox .stream-element.selected").data("guid")).toBe(this.conversationId);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("displayNewConversation", function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
spec.loadFixture("conversations_read");
|
||||||
|
$("#conversation-new").addClass("hidden");
|
||||||
|
$("#conversation-show").removeClass("hidden");
|
||||||
|
spyOn(app.views.ConversationsInbox.prototype, "selectConversation");
|
||||||
|
new app.views.ConversationsInbox();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("displays the new conversation panel", function() {
|
||||||
|
$(".new-conversation-btn").click();
|
||||||
|
|
||||||
|
expect(app.views.ConversationsInbox.prototype.selectConversation).toHaveBeenCalledWith();
|
||||||
|
expect($("#conversation-new")).not.toHaveClass("hidden");
|
||||||
|
expect($("#conversation-show")).toHaveClass("hidden");
|
||||||
|
expect(window.location.pathname).toBe("/conversations");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("setupConversation", function() {
|
||||||
|
context("for unread conversations", function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
spec.loadFixture("conversations_unread");
|
||||||
|
// select second conversation that is still unread
|
||||||
|
$(".conversation-wrapper > .conversation.selected").removeClass("selected");
|
||||||
|
$(".conversation-wrapper > .conversation.unread").addClass("selected");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("removes the unread class from the conversation", function() {
|
||||||
|
expect($(".conversation-wrapper > .conversation.selected")).toHaveClass("unread");
|
||||||
|
new app.views.ConversationsInbox();
|
||||||
|
expect($(".conversation-wrapper > .conversation.selected")).not.toHaveClass("unread");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("removes the unread message counter from the conversation", function() {
|
||||||
|
expect($(".conversation-wrapper > .conversation.selected .unread-message-count").length).toEqual(1);
|
||||||
|
new app.views.ConversationsInbox();
|
||||||
|
expect($(".conversation-wrapper > .conversation.selected .unread-message-count").length).toEqual(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("decreases the unread message count in the header", function() {
|
||||||
|
var badge = "<div id=\"conversations-link\"><div class=\"badge\">3</div></div>";
|
||||||
|
$("header").append(badge);
|
||||||
|
expect($("#conversations-link .badge").text().trim()).toEqual("3");
|
||||||
|
expect($(".conversation-wrapper > .conversation .unread-message-count").text().trim()).toEqual("1");
|
||||||
|
new app.views.ConversationsInbox();
|
||||||
|
expect($("#conversations-link .badge").text().trim()).toEqual("2");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("removes the badge in the header if there are no unread messages left", function() {
|
||||||
|
var badge = "<div id=\"conversations-link\"><div class=\"badge\">1</div></div>";
|
||||||
|
$("header").append(badge);
|
||||||
|
expect($("#conversations-link .badge").text().trim()).toEqual("1");
|
||||||
|
expect($(".conversation-wrapper > .conversation.selected .unread-message-count").text().trim()).toEqual("1");
|
||||||
|
new app.views.ConversationsInbox();
|
||||||
|
expect($("#conversations-link .badge").text().trim()).toEqual("0");
|
||||||
|
expect($("#conversations-link .badge")).toHaveClass("hidden");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
context("for read conversations", function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
spec.loadFixture("conversations_read");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not change the badge in the header", function() {
|
||||||
|
var badge = "<div id=\"conversations-link\"><div class=\"badge\">3</div></div>";
|
||||||
|
$("header").append(badge);
|
||||||
|
expect($("#conversations-link .badge").text().trim()).toEqual("3");
|
||||||
|
new app.views.ConversationsInbox();
|
||||||
|
expect($("#conversations-link .badge").text().trim()).toEqual("3");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("displayConversation", function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
spyOn(app.router, "navigate");
|
||||||
|
spec.loadFixture("conversations_read");
|
||||||
|
new app.views.ConversationsInbox();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("calls app.router.navigate with correct parameters", function() {
|
||||||
|
var conversationEl = $(".conversation-wrapper").first();
|
||||||
|
var conversationPath = conversationEl.data("conversation-path");
|
||||||
|
conversationEl.children().first().click();
|
||||||
|
expect(app.router.navigate).toHaveBeenCalledWith(conversationPath, {trigger: true});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -1,79 +0,0 @@
|
||||||
describe("app.views.Conversations", function(){
|
|
||||||
describe("setupConversation", function() {
|
|
||||||
context("for unread conversations", function() {
|
|
||||||
beforeEach(function() {
|
|
||||||
spec.loadFixture("conversations_unread");
|
|
||||||
// select second conversation that is still unread
|
|
||||||
$(".conversation-wrapper > .conversation.selected").removeClass("selected");
|
|
||||||
$(".conversation-wrapper > .conversation.unread").addClass("selected");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("removes the unread class from the conversation", function() {
|
|
||||||
expect($(".conversation-wrapper > .conversation.selected")).toHaveClass("unread");
|
|
||||||
new app.views.Conversations();
|
|
||||||
expect($(".conversation-wrapper > .conversation.selected")).not.toHaveClass("unread");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("removes the unread message counter from the conversation", function() {
|
|
||||||
expect($(".conversation-wrapper > .conversation.selected .unread-message-count").length).toEqual(1);
|
|
||||||
new app.views.Conversations();
|
|
||||||
expect($(".conversation-wrapper > .conversation.selected .unread-message-count").length).toEqual(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("decreases the unread message count in the header", function() {
|
|
||||||
var badge = "<div id=\"conversations-link\"><div class=\"badge\">3</div></div>";
|
|
||||||
$("header").append(badge);
|
|
||||||
expect($("#conversations-link .badge").text().trim()).toEqual("3");
|
|
||||||
expect($(".conversation-wrapper > .conversation .unread-message-count").text().trim()).toEqual("1");
|
|
||||||
new app.views.Conversations();
|
|
||||||
expect($("#conversations-link .badge").text().trim()).toEqual("2");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("removes the badge in the header if there are no unread messages left", function() {
|
|
||||||
var badge = "<div id=\"conversations-link\"><div class=\"badge\">1</div></div>";
|
|
||||||
$("header").append(badge);
|
|
||||||
expect($("#conversations-link .badge").text().trim()).toEqual("1");
|
|
||||||
expect($(".conversation-wrapper > .conversation.selected .unread-message-count").text().trim()).toEqual("1");
|
|
||||||
new app.views.Conversations();
|
|
||||||
expect($("#conversations-link .badge").text().trim()).toEqual("0");
|
|
||||||
expect($("#conversations-link .badge")).toHaveClass("hidden");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
context("for read conversations", function() {
|
|
||||||
beforeEach(function() {
|
|
||||||
spec.loadFixture("conversations_read");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("does not change the badge in the header", function() {
|
|
||||||
var badge = "<div id=\"conversations-link\"><div class=\"badge\">3</div></div>";
|
|
||||||
$("header").append(badge);
|
|
||||||
expect($("#conversations-link .badge").text().trim()).toEqual("3");
|
|
||||||
new app.views.Conversations();
|
|
||||||
expect($("#conversations-link .badge").text().trim()).toEqual("3");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("keyDown", function(){
|
|
||||||
beforeEach(function() {
|
|
||||||
this.submitCallback = jasmine.createSpy().and.returnValue(false);
|
|
||||||
spec.loadFixture("conversations_read");
|
|
||||||
new app.views.Conversations();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should submit the form with ctrl+enter", function(){
|
|
||||||
$("form#new_message").submit(this.submitCallback);
|
|
||||||
var e = $.Event("keydown", { which: Keycodes.ENTER, ctrlKey: true });
|
|
||||||
$("textarea#message_text").trigger(e);
|
|
||||||
expect(this.submitCallback).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("shouldn't submit the form without the ctrl key", function(){
|
|
||||||
$("form#new_message").submit(this.submitCallback);
|
|
||||||
var e = $.Event("keydown", { which: Keycodes.ENTER, ctrlKey: false });
|
|
||||||
$("textarea#message_text").trigger(e);
|
|
||||||
expect(this.submitCallback).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
Loading…
Reference in a new issue