Merge branch 'stable' into develop

This commit is contained in:
Dennis Schubert 2015-05-10 02:00:41 +02:00
commit 3f3148af2c
19 changed files with 144 additions and 66 deletions

View file

@ -49,6 +49,7 @@ Ruby 2.0 is no longer officially supported.
* Added link to diasporafoundation.org to invitation email [#5893](https://github.com/diaspora/diaspora/pull/5893)
* Gracefully handle missing `og:url`s [#5926](https://github.com/diaspora/diaspora/pull/5926)
* Remove private post content from "also commented" mails [#5931](https://github.com/diaspora/diaspora/pull/5931)
* Add a button to follow/unfollow tags to the mobile interface [#5941](https://github.com/diaspora/diaspora/pull/5941)
# 0.5.0.1

View file

@ -12,13 +12,13 @@ Handlebars.registerHelper('imageUrl', function(path){
return ImagePaths.get(path);
});
Handlebars.registerHelper('urlTo', function(path_helper, id, data){
Handlebars.registerHelper("urlTo", function(pathHelper, id, data){
if( !data ) {
// only one argument given to helper, mangle parameters
data = id;
return Routes[path_helper+'_path'](data.hash);
return Routes[pathHelper](data.hash);
}
return Routes[path_helper+'_path'](id, data.hash);
return Routes[pathHelper](id, data.hash);
});
Handlebars.registerHelper('linkToAuthor', function(context, block) {
@ -89,32 +89,32 @@ Handlebars.registerHelper('localTime', function(timestamp) {
return new Date(timestamp).toLocaleString();
});
Handlebars.registerHelper('fmtTags', function(tags) {
Handlebars.registerHelper("fmtTags", function(tags) {
var links = _.map(tags, function(tag) {
return '<a class="tag" href="' + Routes.tag_path(tag) + '">' +
' #' + tag +
'</a>';
}).join(' ');
return "<a class=\"tag\" href=\"" + Routes.tag(tag) + "\">" +
" #" + tag +
"</a>";
}).join(" ");
return new Handlebars.SafeString(links);
});
Handlebars.registerHelper('fmtText', function(text) {
Handlebars.registerHelper("fmtText", function(text) {
return new Handlebars.SafeString(app.helpers.textFormatter(text));
});
Handlebars.registerHelper('isCurrentPage', function(path_helper, id, options){
Handlebars.registerHelper("isCurrentPage", function(pathHelper, id, options){
var currentPage = "/"+Backbone.history.fragment;
if (currentPage === Handlebars.helpers.urlTo(path_helper, id, options.data)) {
if (currentPage === Handlebars.helpers.urlTo(pathHelper, id, options.data)) {
return options.fn(this);
} else {
return options.inverse(this);
}
});
Handlebars.registerHelper('isCurrentProfilePage', function(id, diaspora_handle, options){
var username = diaspora_handle.split("@")[0];
return Handlebars.helpers.isCurrentPage('person', id, options) ||
Handlebars.helpers.isCurrentPage('user_profile', username, options);
Handlebars.registerHelper("isCurrentProfilePage", function(id, diasporaHandle, options){
var username = diasporaHandle.split("@")[0];
return Handlebars.helpers.isCurrentPage("person", id, options) ||
Handlebars.helpers.isCurrentPage("userProfile", username, options);
});
Handlebars.registerHelper('aspectMembershipIndicator', function(contact,in_aspect) {

View file

@ -2,7 +2,7 @@
app.models.Person = Backbone.Model.extend({
url: function() {
return Routes.person_path(this.get('guid'));
return Routes.person(this.get("guid"));
},
initialize: function() {

View file

@ -83,7 +83,7 @@ app.pages.Contacts = Backbone.View.extend({
update: function() {
$("#aspect_nav .ui-sortable").removeClass("synced");
var data = JSON.stringify({ ordered_aspect_ids: $(this).sortable("toArray", { attribute: "data-aspect-id" }) });
$.ajax(Routes.order_aspects_path(),
$.ajax(Routes.orderAspects(),
{ type: "put", dataType: "text", contentType: "application/json", data: data })
.done(function() { $("#aspect_nav .ui-sortable").addClass("synced"); });
},

View file

@ -76,11 +76,11 @@ app.pages.Profile = app.views.Base.extend({
}
// a collection is set, this means we want to view photos
var route = this.streamCollection ? 'person_photos_path' : 'person_stream_path';
var route = this.streamCollection ? "personPhotos" : "personStream";
var view = this.streamViewClass ? this.streamViewClass : app.views.Stream;
app.stream = new app.models.Stream(null, {
basePath: Routes[route](app.page.model.get('guid')),
basePath: Routes[route](app.page.model.get("guid")),
collection: this.streamCollection
});
app.stream.fetch();

View file

@ -40,7 +40,7 @@ app.views.Help = app.views.StaticContentView.extend({
this.CHAT_SUBS = {
add_contact_roster_a: {
toggle_privilege: this.getChatIcons(),
contacts_page: this.linkHtml(Routes.contacts_path(), Diaspora.I18n.t('chat.contacts_page'))
contacts_page: this.linkHtml(Routes.contacts(), Diaspora.I18n.t("chat.contacts_page"))
}
};

View file

@ -74,7 +74,7 @@ app.views.NotificationDropdown = app.views.Base.extend({
getNotifications: function(){
var self = this;
$.getJSON(Routes.notifications_path(this.getParams()), function(notifications){
$.getJSON(Routes.notifications(this.getParams()), function(notifications){
$.each(notifications, function(){ self.notifications.push(this); });
self.hasMoreNotifs = notifications.length >= self.perPage;
if(self.nextPage){ self.nextPage++; }

View file

@ -49,7 +49,7 @@ app.views.SinglePostModeration = app.views.Feedback.extend({
createParticipation: function (evt) {
if(evt) { evt.preventDefault(); }
var self = this;
$.post(Routes.post_participation_path(this.model.get("id")), {}, function () {
$.post(Routes.postParticipation(this.model.get("id")), {}, function () {
self.model.set({participation: true});
self.render();
});
@ -58,7 +58,7 @@ app.views.SinglePostModeration = app.views.Feedback.extend({
destroyParticipation: function (evt) {
if(evt) { evt.preventDefault(); }
var self = this;
$.post(Routes.post_participation_path(this.model.get("id")), { _method: "delete" }, function () {
$.post(Routes.postParticipation(this.model.get("id")), { _method: "delete" }, function () {
self.model.set({participation: false});
self.render();
});

View file

@ -119,7 +119,7 @@ app.views.StreamPost = app.views.Post.extend({
createParticipation: function (evt) {
if(evt) { evt.preventDefault(); }
that = this;
$.post(Routes.post_participation_path(this.model.get("id")), {}, function () {
$.post(Routes.postParticipation(this.model.get("id")), {}, function () {
that.model.set({participation: true});
that.render();
});
@ -128,7 +128,7 @@ app.views.StreamPost = app.views.Post.extend({
destroyParticipation: function (evt) {
if(evt) { evt.preventDefault(); }
that = this;
$.post(Routes.post_participation_path(this.model.get("id")), { _method: "delete" }, function () {
$.post(Routes.postParticipation(this.model.get("id")), { _method: "delete" }, function () {
that.model.set({participation: false});
that.render();
});

View file

@ -18,6 +18,7 @@
//= require widgets/timeago
//= require mobile/mobile_file_uploader
//= require mobile/profile_aspects
//= require mobile/tag_following
$(document).ready(function(){

View file

@ -27,14 +27,14 @@ $(document).ready(function(){
if(selected.hasClass('selected')) {
// remove from aspect
var membership_id = selected.data('membership_id');
var membershipId = selected.data("membership_id");
$.ajax({
url: Routes.aspect_membership_path(membership_id),
type: 'DELETE',
dataType: 'json',
url: Routes.aspectMembership(membershipId),
type: "DELETE",
dataType: "json",
headers: {
'Accept': "application/json, text/javascript, */*; q=0.01"
"Accept": "application/json, text/javascript, */*; q=0.01"
}
}).done(function() {
selected.text(" " + Diaspora.I18n.t('aspect_dropdown.mobile_row_unchecked', {name: selected.data('name')}));
@ -50,7 +50,7 @@ $(document).ready(function(){
var person_id = $el.data('person-id');
$.ajax({
url: Routes.aspect_memberships_path(),
url: Routes.aspectMemberships(),
data: JSON.stringify({
"person_id": person_id,
"aspect_id": parseInt(selected.val(), 10)

View file

@ -0,0 +1,43 @@
$(document).ready(function(){
$(".tag_following_action").bind("tap click", function(evt){
evt.preventDefault();
var button = $(this),
tagName = button.data("name");
if(button.hasClass("btn-success")){
$.ajax({
url: Routes.tagFollowings(),
data: JSON.stringify({"name": tagName}),
type: "POST",
dataType: "json",
headers: {
"Accept": "application/json, text/javascript, */*; q=0.01"
},
contentType: "application/json; charset=UTF-8"
}).done(function(data) {
gon.preloads.tagFollowings.push(data);
button.removeClass("btn-success").addClass("btn-danger");
button.text(Diaspora.I18n.t("stream.tags.stop_following", {tag: tagName}));
}).fail(function() {
alert(Diaspora.I18n.t("stream.tags.follow_error", {name: "#" + tagName}));
});
}
else if(button.hasClass("btn-danger")){
var tagFollowing = _.findWhere(gon.preloads.tagFollowings,{name: tagName});
if(!tagFollowing) { return; }
$.ajax({
url: Routes.tagFollowing(tagFollowing.id),
dataType: "json",
type: "DELETE",
headers: {
"Accept": "application/json, text/javascript, */*; q=0.01"
}
}).done(function() {
button.removeClass("btn-danger").addClass("btn-success");
button.text(Diaspora.I18n.t("stream.tags.follow", {tag: tagName}));
}).fail(function() {
alert(Diaspora.I18n.t("stream.tags.stop_following_error", {name: "#" + tagName}));
});
}
});
});

View file

@ -1210,3 +1210,5 @@ select#aspect_ids_ {
#app #main h1 {
word-wrap: break-word;
}
.tag_following_action { margin: 5px 0 10px 0; }

View file

@ -2,7 +2,7 @@
<div class="pull-right">
{{#if is_own_profile}}
{{!-- can't block myself, so don't check it here --}}
<a href="{{urlTo 'edit_profile'}}" id="edit_profile" class="btn btn-primary creation">{{t 'people.edit_my_profile'}}</a>
<a href="{{urlTo 'editProfile'}}" id="edit_profile" class="btn btn-primary creation">{{t 'people.edit_my_profile'}}</a>
{{else}} {{#if is_blocked}}
<a href="#" id="unblock_user_button" class="btn btn-danger">{{t 'people.stop_ignoring'}}</a>
{{else}}
@ -31,7 +31,7 @@
<div class="description">
<i>{{t 'profile.you_have_no_tags'}}</i>
<span class="add_tags">
<a href="{{urlTo 'edit_profile'}}">{{t 'profile.add_some'}}</a>
<a href="{{urlTo 'editProfile'}}">{{t 'profile.add_some'}}</a>
</span>
</div>
{{/if}}
@ -74,8 +74,8 @@
</a>
</li>
{{#if show_photos}}
<li {{#isCurrentPage 'person_photos' guid}} class="active" {{/isCurrentPage}}>
<a href="{{urlTo 'person_photos' guid}}" id="photos_link">
<li {{#isCurrentPage 'personPhotos' guid}} class="active" {{/isCurrentPage}}>
<a href="{{urlTo 'personPhotos' guid}}" id="photos_link">
<i class="entypo picture"></i>
{{t 'profile.photos'}}
<div class="badge badge-default">{{photos.count}}</div>
@ -83,7 +83,7 @@
</li>
{{/if}}
{{#if show_contacts}}
<li {{#isCurrentPage 'person_contacts' guid}} class="active" {{/isCurrentPage}}>
<li {{#isCurrentPage 'personContacts' guid}} class="active" {{/isCurrentPage}}>
{{#if is_own_profile}}
<a href="{{urlTo 'contacts'}}" id="contacts_link">
<i class="entypo users"></i>
@ -91,7 +91,7 @@
<div class="badge badge-default">{{contacts.count}}</div>
</a>
{{else}}
<a href="{{urlTo 'person_contacts' guid}}" id="contacts_link">
<a href="{{urlTo 'personContacts' guid}}" id="contacts_link">
<i class="entypo users"></i>
{{t 'profile.contacts'}}
<div class="badge badge-default">{{contacts.count}}</div>

View file

@ -4,6 +4,13 @@
%h1
= @stream.display_tag_name
- if user_signed_in?
- unless tag_followed?
.btn.btn-success.tag_following_action{data: {name: @stream.tag_name}}
= t(".follow", tag: @stream.tag_name)
- else
.btn.btn-danger.tag_following_action{data: {name: @stream.tag_name}}
= t(".stop_following", tag: @stream.tag_name)
#main_stream.stream
= render 'shared/stream', :posts => @stream.stream_posts

View file

@ -0,0 +1,4 @@
JsRoutes.setup do |config|
config.camel_case = true
config.compact = true
end

View file

@ -206,6 +206,8 @@ en:
follow: "Follow #<%= tag %>"
following: "Following #<%= tag %>"
stop_following: "Stop following #<%= tag %>"
follow_error: "Couldnt follow <%= name %> :("
stop_following_error: "Couldnt stop following <%= name %> :("
header:
home: "Home"

View file

@ -2,13 +2,31 @@
Feature: Interacting with tags
Background:
Given a user with username "alice"
And "alice@alice.alice" has a public post with text "Hello! i am #newhere"
When I sign in as "alice@alice.alice"
Given following users exist:
| username |
| bob |
| alice |
And "alice@alice.alice" has a public post with text "Hello! I am #newhere"
When I sign in as "bob@bob.bob"
And I visit the mobile search page
And I fill in the following:
| q | #newhere |
And I press "Search"
Then I should see "Follow #newhere" within ".tag_following_action"
Scenario: Start and stop following a tag
When I click on selector ".tag_following_action"
Then I should see "Stop following #newhere" within ".tag_following_action"
When I am on the home page
Then I should see "Hello! I am #newhere"
Scenario: Searching for a tag
When I visit the mobile search page
And I fill in the following:
| q | #newhere |
And I press "Search"
Then I should see "#newhere" within ".ltr"
Then I should see "Stop following #newhere" within ".tag_following_action"
When I click on selector ".tag_following_action"
Then I should see "Follow #newhere" within ".tag_following_action"
When I am on the home page
Then I should not see "Hello! I am #newhere"

View file

@ -1,69 +1,69 @@
describe("app.models.Person", function() {
beforeEach(function() {
this.mutual_contact = factory.person({relationship: 'mutual'});
this.sharing_contact = factory.person({relationship :'sharing'});
this.receiving_contact = factory.person({relationship: 'receiving'});
this.blocked_contact = factory.person({relationship: 'blocked', block: {id: 1}});
this.mutualContact = factory.person({relationship: "mutual"});
this.sharingContact = factory.person({relationship: "sharing"});
this.receivingContact = factory.person({relationship: "receiving"});
this.blockedContact = factory.person({relationship: "blocked", block: {id: 1}});
});
context("#isSharing", function() {
it("indicates if the person is sharing", function() {
expect(this.mutual_contact.isSharing()).toBeTruthy();
expect(this.sharing_contact.isSharing()).toBeTruthy();
expect(this.mutualContact.isSharing()).toBeTruthy();
expect(this.sharingContact.isSharing()).toBeTruthy();
expect(this.receiving_contact.isSharing()).toBeFalsy();
expect(this.blocked_contact.isSharing()).toBeFalsy();
expect(this.receivingContact.isSharing()).toBeFalsy();
expect(this.blockedContact.isSharing()).toBeFalsy();
});
});
context("#isReceiving", function() {
it("indicates if the person is receiving", function() {
expect(this.mutual_contact.isReceiving()).toBeTruthy();
expect(this.receiving_contact.isReceiving()).toBeTruthy();
expect(this.mutualContact.isReceiving()).toBeTruthy();
expect(this.receivingContact.isReceiving()).toBeTruthy();
expect(this.sharing_contact.isReceiving()).toBeFalsy();
expect(this.blocked_contact.isReceiving()).toBeFalsy();
expect(this.sharingContact.isReceiving()).toBeFalsy();
expect(this.blockedContact.isReceiving()).toBeFalsy();
});
});
context("#isMutual", function() {
it("indicates if we share mutually with the person", function() {
expect(this.mutual_contact.isMutual()).toBeTruthy();
expect(this.mutualContact.isMutual()).toBeTruthy();
expect(this.receiving_contact.isMutual()).toBeFalsy();
expect(this.sharing_contact.isMutual()).toBeFalsy();
expect(this.blocked_contact.isMutual()).toBeFalsy();
expect(this.receivingContact.isMutual()).toBeFalsy();
expect(this.sharingContact.isMutual()).toBeFalsy();
expect(this.blockedContact.isMutual()).toBeFalsy();
});
});
context("#isBlocked", function() {
it("indicates whether we blocked the person", function() {
expect(this.blocked_contact.isBlocked()).toBeTruthy();
expect(this.blockedContact.isBlocked()).toBeTruthy();
expect(this.mutual_contact.isBlocked()).toBeFalsy();
expect(this.receiving_contact.isBlocked()).toBeFalsy();
expect(this.sharing_contact.isBlocked()).toBeFalsy();
expect(this.mutualContact.isBlocked()).toBeFalsy();
expect(this.receivingContact.isBlocked()).toBeFalsy();
expect(this.sharingContact.isBlocked()).toBeFalsy();
});
});
context("#block", function() {
it("POSTs a block to the server", function() {
this.sharing_contact.block();
this.sharingContact.block();
var request = jasmine.Ajax.requests.mostRecent();
expect(request.method).toEqual("POST");
expect($.parseJSON(request.params).block.person_id).toEqual(this.sharing_contact.id);
expect($.parseJSON(request.params).block.person_id).toEqual(this.sharingContact.id);
});
});
context("#unblock", function() {
it("DELETEs a block from the server", function(){
this.blocked_contact.unblock();
this.blockedContact.unblock();
var request = jasmine.Ajax.requests.mostRecent();
expect(request.method).toEqual("DELETE");
expect(request.url).toEqual(Routes.block_path(this.blocked_contact.get('block').id));
expect(request.url).toEqual(Routes.block(this.blockedContact.get("block").id));
});
});
});