Merge pull request #3713 from davecocoa/feature/3630-backbone-ify-followed-tags
port tagFollowings to BackBone
This commit is contained in:
commit
7b548fd571
25 changed files with 353 additions and 98 deletions
17
app/assets/javascripts/app/collections/tag_followings.js
Normal file
17
app/assets/javascripts/app/collections/tag_followings.js
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
app.collections.TagFollowings = Backbone.Collection.extend({
|
||||||
|
|
||||||
|
model: app.models.TagFollowing,
|
||||||
|
|
||||||
|
url : "/tag_followings",
|
||||||
|
|
||||||
|
create : function(model) {
|
||||||
|
var name = model.name || model.get("name");
|
||||||
|
if(!this.any(
|
||||||
|
function(tagFollowing){
|
||||||
|
return tagFollowing.get("name") === name;
|
||||||
|
})) {
|
||||||
|
Backbone.Collection.prototype.create.apply(this, arguments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
3
app/assets/javascripts/app/models/tag_following.js
Normal file
3
app/assets/javascripts/app/models/tag_following.js
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
app.models.TagFollowing = Backbone.Model.extend({
|
||||||
|
urlRoot: "/tag_followings"
|
||||||
|
});
|
||||||
|
|
@ -16,8 +16,8 @@ app.Router = Backbone.Router.extend({
|
||||||
"commented": "stream",
|
"commented": "stream",
|
||||||
"liked": "stream",
|
"liked": "stream",
|
||||||
"mentions": "stream",
|
"mentions": "stream",
|
||||||
"followed_tags": "stream",
|
"followed_tags": "followed_tags",
|
||||||
"tags/:name": "stream",
|
"tags/:name": "followed_tags",
|
||||||
"people/:id/photos": "photos",
|
"people/:id/photos": "photos",
|
||||||
|
|
||||||
"people/:id": "stream",
|
"people/:id": "stream",
|
||||||
|
|
@ -63,6 +63,24 @@ app.Router = Backbone.Router.extend({
|
||||||
app.photos = new app.models.Stream([], {collection: app.collections.Photos});
|
app.photos = new app.models.Stream([], {collection: app.collections.Photos});
|
||||||
app.page = new app.views.Photos({model : app.photos});
|
app.page = new app.views.Photos({model : app.photos});
|
||||||
$("#main_stream").html(app.page.render().el);
|
$("#main_stream").html(app.page.render().el);
|
||||||
|
},
|
||||||
|
|
||||||
|
followed_tags : function(name) {
|
||||||
|
this.stream();
|
||||||
|
|
||||||
|
app.tagFollowings = new app.collections.TagFollowings();
|
||||||
|
var followedTagsView = new app.views.TagFollowingList({collection: app.tagFollowings});
|
||||||
|
$("#tags_list").replaceWith(followedTagsView.render().el);
|
||||||
|
followedTagsView.setupAutoSuggest();
|
||||||
|
|
||||||
|
app.tagFollowings.add(preloads.tagFollowings);
|
||||||
|
|
||||||
|
if(name) {
|
||||||
|
var followedTagsAction = new app.views.TagFollowingAction(
|
||||||
|
{tagText: name}
|
||||||
|
);
|
||||||
|
$("#author_info").prepend(followedTagsAction.render().el)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
app.views.TagFollowingAction = app.views.Base.extend({
|
||||||
|
|
||||||
|
templateName: "tag_following_action",
|
||||||
|
|
||||||
|
events : {
|
||||||
|
"mouseenter .button.red_on_hover": "mouseIn",
|
||||||
|
"mouseleave .button.red_on_hover": "mouseOut",
|
||||||
|
"click .button": "tagAction"
|
||||||
|
},
|
||||||
|
|
||||||
|
initialize : function(options){
|
||||||
|
this.tagText = options.tagText;
|
||||||
|
this.getTagFollowing();
|
||||||
|
app.tagFollowings.bind("remove add", this.getTagFollowing, this);
|
||||||
|
},
|
||||||
|
|
||||||
|
presenter : function() {
|
||||||
|
return _.extend(this.defaultPresenter(), {
|
||||||
|
tag_is_followed : this.tag_is_followed(),
|
||||||
|
followString : this.followString()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
followString : function() {
|
||||||
|
if(this.tag_is_followed()) {
|
||||||
|
return Diaspora.I18n.t("stream.tags.following", {"tag" : this.model.attributes.name});
|
||||||
|
} else {
|
||||||
|
return Diaspora.I18n.t("stream.tags.follow", {"tag" : this.model.attributes.name});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
tag_is_followed : function() {
|
||||||
|
return !this.model.isNew();
|
||||||
|
},
|
||||||
|
|
||||||
|
getTagFollowing : function(tagFollowing) {
|
||||||
|
this.model = app.tagFollowings.where({"name":this.tagText})[0] ||
|
||||||
|
new app.models.TagFollowing({"name":this.tagText});
|
||||||
|
this.model.bind("change", this.render, this);
|
||||||
|
this.render();
|
||||||
|
},
|
||||||
|
|
||||||
|
mouseIn : function(){
|
||||||
|
this.$("input").removeClass("in_aspects");
|
||||||
|
this.$("input").val( Diaspora.I18n.t('stream.tags.stop_following', {tag: this.model.attributes.name} ) );
|
||||||
|
},
|
||||||
|
|
||||||
|
mouseOut : function() {
|
||||||
|
this.$("input").addClass("in_aspects");
|
||||||
|
this.$("input").val( Diaspora.I18n.t('stream.tags.following', {"tag" : this.model.attributes.name} ) );
|
||||||
|
},
|
||||||
|
|
||||||
|
tagAction : function(evt){
|
||||||
|
if(evt){ evt.preventDefault(); }
|
||||||
|
|
||||||
|
if(this.tag_is_followed()) {
|
||||||
|
this.model.destroy();
|
||||||
|
} else {
|
||||||
|
app.tagFollowings.create(this.model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
75
app/assets/javascripts/app/views/tag_following_list_view.js
Normal file
75
app/assets/javascripts/app/views/tag_following_list_view.js
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
//= require jquery.autoSuggest.custom
|
||||||
|
app.views.TagFollowingList = app.views.Base.extend({
|
||||||
|
|
||||||
|
templateName: "tag_following_list",
|
||||||
|
|
||||||
|
className : "sub_nav",
|
||||||
|
|
||||||
|
id : "tags_list",
|
||||||
|
|
||||||
|
tagName : "ul",
|
||||||
|
|
||||||
|
events: {
|
||||||
|
"submit form": "createTagFollowing"
|
||||||
|
},
|
||||||
|
|
||||||
|
initialize : function(){
|
||||||
|
this.collection.bind("add", this.appendTagFollowing, this);
|
||||||
|
},
|
||||||
|
|
||||||
|
postRenderTemplate : function() {
|
||||||
|
this.collection.each(this.appendTagFollowing, this);
|
||||||
|
},
|
||||||
|
|
||||||
|
setupAutoSuggest : function() {
|
||||||
|
this.$("input").autoSuggest("/tags", {
|
||||||
|
selectedItemProp: "name",
|
||||||
|
selectedValuesProp: "name",
|
||||||
|
searchObjProps: "name",
|
||||||
|
asHtmlID: "tags",
|
||||||
|
neverSubmit: true,
|
||||||
|
retrieveLimit: 10,
|
||||||
|
selectionLimit: false,
|
||||||
|
minChars: 2,
|
||||||
|
keyDelay: 200,
|
||||||
|
startText: "",
|
||||||
|
emptyText: "no_results",
|
||||||
|
selectionAdded: _.bind(this.suggestSelection, this)
|
||||||
|
});
|
||||||
|
|
||||||
|
this.$("input").bind('keydown', function(evt){
|
||||||
|
if(evt.keyCode == 13 || evt.keyCode == 9 || evt.keyCode == 32){
|
||||||
|
evt.preventDefault();
|
||||||
|
if( $('li.as-result-item.active').length == 0 ){
|
||||||
|
$('li.as-result-item').first().click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
presenter : function() {
|
||||||
|
return this.defaultPresenter();
|
||||||
|
},
|
||||||
|
|
||||||
|
suggestSelection : function(elem) {
|
||||||
|
this.$(".tag_input").val($(elem[0]).text().substring(2));
|
||||||
|
elem.remove();
|
||||||
|
this.createTagFollowing();
|
||||||
|
},
|
||||||
|
|
||||||
|
createTagFollowing: function(evt) {
|
||||||
|
if(evt){ evt.preventDefault(); }
|
||||||
|
var name = this.$(".tag_input").val();
|
||||||
|
|
||||||
|
this.collection.create({"name":this.$(".tag_input").val()});
|
||||||
|
this.$(".tag_input").val("");
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
appendTagFollowing: function(tag) {
|
||||||
|
this.$el.prepend(new app.views.TagFollowing({
|
||||||
|
model: tag
|
||||||
|
}).render().el);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
33
app/assets/javascripts/app/views/tag_following_view.js
Normal file
33
app/assets/javascripts/app/views/tag_following_view.js
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
app.views.TagFollowing = app.views.Base.extend({
|
||||||
|
|
||||||
|
templateName: "tag_following",
|
||||||
|
|
||||||
|
className : "unfollow",
|
||||||
|
|
||||||
|
tagName: "li",
|
||||||
|
|
||||||
|
events : {
|
||||||
|
"click .tag_following_delete": "destroyModel"
|
||||||
|
},
|
||||||
|
|
||||||
|
initialize : function(){
|
||||||
|
this.el.id = "tag-following-" + this.model.get("name");
|
||||||
|
this.model.bind("destroy", this.hide, this);
|
||||||
|
},
|
||||||
|
|
||||||
|
hide : function() {
|
||||||
|
this.$el.slideUp();
|
||||||
|
},
|
||||||
|
|
||||||
|
postRenderTemplate : function() {
|
||||||
|
this.$el.hide();
|
||||||
|
this.$el.slideDown();
|
||||||
|
},
|
||||||
|
|
||||||
|
presenter : function() {
|
||||||
|
return _.extend(this.defaultPresenter(), {
|
||||||
|
tag : this.model
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
@ -36,12 +36,10 @@ Diaspora.Pages.UsersGettingStarted = function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#awesome_button").bind("click", function(evt){
|
$("#awesome_button").bind("click", function(evt){
|
||||||
evt.preventDefault();
|
|
||||||
|
|
||||||
var confirmMessage = Diaspora.I18n.t("getting_started.no_tags");
|
var confirmMessage = Diaspora.I18n.t("getting_started.no_tags");
|
||||||
|
|
||||||
if(($("#as-selections-tags").find(".as-selection-item").length > 0) || confirm(confirmMessage)) {
|
if(($("#as-selections-tags").find(".as-selection-item").length > 0) || confirm(confirmMessage)) {
|
||||||
$('.tag_input').submit();
|
|
||||||
|
|
||||||
/* flash message prompt */
|
/* flash message prompt */
|
||||||
var message = Diaspora.I18n.t("getting_started.preparing_your_stream");
|
var message = Diaspora.I18n.t("getting_started.preparing_your_stream");
|
||||||
|
|
@ -55,18 +53,25 @@ Diaspora.Pages.UsersGettingStarted = function() {
|
||||||
|
|
||||||
/* ------ */
|
/* ------ */
|
||||||
var autocompleteInput = $("#follow_tags");
|
var autocompleteInput = $("#follow_tags");
|
||||||
|
var tagFollowings = new app.collections.TagFollowings();
|
||||||
|
|
||||||
autocompleteInput.autoSuggest("/tags", {
|
autocompleteInput.autoSuggest("/tags", {
|
||||||
selectedItemProp: "name",
|
selectedItemProp: "name",
|
||||||
|
selectedValuesProp: "name",
|
||||||
searchObjProps: "name",
|
searchObjProps: "name",
|
||||||
asHtmlID: "tags",
|
asHtmlID: "tags",
|
||||||
neverSubmit: true,
|
neverSubmit: true,
|
||||||
retriveLimit: 10,
|
retrieveLimit: 10,
|
||||||
selectionLimit: false,
|
selectionLimit: false,
|
||||||
minChars: 2,
|
minChars: 2,
|
||||||
keyDelay: 200,
|
keyDelay: 200,
|
||||||
startText: "",
|
startText: "",
|
||||||
emptyText: "no_results"
|
emptyText: "no_results",
|
||||||
|
selectionAdded: function(elem){tagFollowings.create({"name":$(elem[0]).text().substring(2)})},
|
||||||
|
selectionRemoved: function(elem){
|
||||||
|
tagFollowings.where({"name":$(elem[0]).text().substring(2)})[0].destroy();
|
||||||
|
elem.remove();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
autocompleteInput.bind('keydown', function(evt){
|
autocompleteInput.bind('keydown', function(evt){
|
||||||
|
|
|
||||||
|
|
@ -2778,6 +2778,7 @@ a.toggle_selector
|
||||||
:left 24px
|
:left 24px
|
||||||
|
|
||||||
input[type='text']
|
input[type='text']
|
||||||
|
:width 100%
|
||||||
:font
|
:font
|
||||||
:size 13px
|
:size 13px
|
||||||
|
|
||||||
|
|
|
||||||
10
app/assets/templates/tag_following_action_tpl.jst.hbs
Normal file
10
app/assets/templates/tag_following_action_tpl.jst.hbs
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
<div class="right">
|
||||||
|
<form accept-charset="UTF-8" action="/tag_followings" method="post">
|
||||||
|
<input type="submit" class="button take_action
|
||||||
|
{{#if tag_is_followed }}
|
||||||
|
red_on_hover in_aspects
|
||||||
|
{{/if}}
|
||||||
|
" type="submit" value="{{followString}}"
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
5
app/assets/templates/tag_following_list_tpl.jst.hbs
Normal file
5
app/assets/templates/tag_following_list_tpl.jst.hbs
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
<li>
|
||||||
|
<form accept-charset="UTF-8" action="/tag_followings" id="new_tag_following" method="post">
|
||||||
|
<input class="tag_input" type="text" name="name" placeholder="{{t "stream.followed_tag.add_a_tag"}}" />
|
||||||
|
</form>
|
||||||
|
</li>
|
||||||
9
app/assets/templates/tag_following_tpl.jst.hbs
Normal file
9
app/assets/templates/tag_following_tpl.jst.hbs
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
<div class="unfollow_icon hidden">
|
||||||
|
<a href="#" id="unfollow_{{name}}" rel="nofollow" class="delete tag_following_delete" title="{{t "delete"}}">
|
||||||
|
<img alt="Deletelabel" src="{{imageUrl "deletelabel.png"}}" />
|
||||||
|
<a/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a class="tag_selector" href="/tags/{{name}}">
|
||||||
|
#{{ name }}
|
||||||
|
</a>
|
||||||
|
|
@ -153,7 +153,8 @@ class PeopleController < ApplicationController
|
||||||
def redirect_if_tag_search
|
def redirect_if_tag_search
|
||||||
if search_query.starts_with?('#')
|
if search_query.starts_with?('#')
|
||||||
if search_query.length > 1
|
if search_query.length > 1
|
||||||
redirect_to tag_path(:name => search_query.delete('#.'), :q => search_query)
|
|
||||||
|
redirect_to tag_path(:name => search_query.delete('#.'))
|
||||||
else
|
else
|
||||||
flash[:error] = I18n.t('tags.show.none', :name => search_query)
|
flash[:error] = I18n.t('tags.show.none', :name => search_query)
|
||||||
redirect_to :back
|
redirect_to :back
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ class StreamsController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def followed_tags
|
def followed_tags
|
||||||
|
gon.tagFollowings = tags
|
||||||
stream_responder(Stream::FollowedTag)
|
stream_responder(Stream::FollowedTag)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
class TagFollowingsController < ApplicationController
|
class TagFollowingsController < ApplicationController
|
||||||
before_filter :authenticate_user!
|
before_filter :authenticate_user!
|
||||||
|
|
||||||
respond_to :html, :json
|
respond_to :json
|
||||||
|
|
||||||
# POST /tag_followings
|
# POST /tag_followings
|
||||||
# POST /tag_followings.xml
|
# POST /tag_followings.xml
|
||||||
|
|
@ -14,52 +14,38 @@ class TagFollowingsController < ApplicationController
|
||||||
name_normalized = ActsAsTaggableOn::Tag.normalize(params['name'])
|
name_normalized = ActsAsTaggableOn::Tag.normalize(params['name'])
|
||||||
|
|
||||||
if name_normalized.nil? || name_normalized.empty?
|
if name_normalized.nil? || name_normalized.empty?
|
||||||
flash[:error] = I18n.t('tag_followings.create.none')
|
render :nothing => true, :status => 403
|
||||||
else
|
else
|
||||||
@tag = ActsAsTaggableOn::Tag.find_or_create_by_name(name_normalized)
|
@tag = ActsAsTaggableOn::Tag.find_or_create_by_name(name_normalized)
|
||||||
@tag_following = current_user.tag_followings.new(:tag_id => @tag.id)
|
@tag_following = current_user.tag_followings.new(:tag_id => @tag.id)
|
||||||
|
|
||||||
if @tag_following.save
|
if @tag_following.save
|
||||||
flash[:notice] = I18n.t('tag_followings.create.success', :name => name_normalized)
|
render :json => @tag.to_json, :status => 201
|
||||||
else
|
else
|
||||||
flash[:error] = I18n.t('tag_followings.create.failure', :name => name_normalized)
|
render :nothing => true, :status => 403
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
redirect_to :back
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# DELETE /tag_followings/1
|
# DELETE /tag_followings/1
|
||||||
# DELETE /tag_followings/1.xml
|
# DELETE /tag_followings/1.xml
|
||||||
def destroy
|
def destroy
|
||||||
@tag = ActsAsTaggableOn::Tag.find_by_name(params[:name])
|
tag_following = current_user.tag_followings.find_by_tag_id( params['id'] )
|
||||||
tag_following = current_user.tag_followings.find_by_tag_id( @tag.id )
|
|
||||||
if tag_following && tag_following.destroy
|
if tag_following && tag_following.destroy
|
||||||
tag_unfollowed = true
|
respond_to do |format|
|
||||||
|
format.any(:js, :json) { render :nothing => true, :status => 204 }
|
||||||
|
end
|
||||||
else
|
else
|
||||||
tag_unfollowed = false
|
respond_to do |format|
|
||||||
end
|
format.any(:js, :json) {render :nothing => true, :status => 403}
|
||||||
|
|
||||||
respond_to do |format|
|
|
||||||
format.js { render 'tags/update' }
|
|
||||||
format.any {
|
|
||||||
if tag_unfollowed
|
|
||||||
flash[:notice] = I18n.t('tag_followings.destroy.success', :name => params[:name])
|
|
||||||
else
|
|
||||||
flash[:error] = I18n.t('tag_followings.destroy.failure', :name => params[:name])
|
|
||||||
end
|
|
||||||
redirect_to tag_path(:name => params[:name])
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def create_multiple
|
|
||||||
if params[:tags].present?
|
|
||||||
params[:tags].split(",").each do |name|
|
|
||||||
name_normalized = ActsAsTaggableOn::Tag.normalize(name)
|
|
||||||
@tag = ActsAsTaggableOn::Tag.find_or_create_by_name(name_normalized)
|
|
||||||
@tag_following = current_user.tag_followings.create(:tag_id => @tag.id)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
redirect_to stream_path
|
end
|
||||||
|
|
||||||
|
def index
|
||||||
|
respond_to do |format|
|
||||||
|
format.json{ render(:json => tags.to_json, :status => 200) }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,10 @@ class TagsController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
|
if user_signed_in?
|
||||||
|
gon.tagFollowings = tags
|
||||||
|
end
|
||||||
@stream = Stream::Tag.new(current_user, params[:name], :max_time => max_time, :page => params[:page])
|
@stream = Stream::Tag.new(current_user, params[:name], :max_time => max_time, :page => params[:page])
|
||||||
|
|
||||||
respond_with do |format|
|
respond_with do |format|
|
||||||
format.json { render :json => @stream.stream_posts.map { |p| LastThreeCommentsDecorator.new(PostPresenter.new(p, current_user)) }}
|
format.json { render :json => @stream.stream_posts.map { |p| LastThreeCommentsDecorator.new(PostPresenter.new(p, current_user)) }}
|
||||||
end
|
end
|
||||||
|
|
@ -47,18 +49,10 @@ class TagsController < ApplicationController
|
||||||
|
|
||||||
def prep_tags_for_javascript
|
def prep_tags_for_javascript
|
||||||
@tags.map! do |tag|
|
@tags.map! do |tag|
|
||||||
{
|
{ :name => ("#" + tag.name) }
|
||||||
:name => ("#" + tag.name),
|
|
||||||
:value => ("#" + tag.name),
|
|
||||||
:url => tag_path(tag.name)
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@tags << {
|
@tags << { :name => ('#' + params[:q]) }
|
||||||
:name => ('#' + params[:q]),
|
|
||||||
:value => ("#" + params[:q]),
|
|
||||||
:url => tag_path(params[:q].downcase)
|
|
||||||
}
|
|
||||||
@tags.uniq!
|
@tags.uniq!
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
class ActsAsTaggableOn::Tag
|
class ActsAsTaggableOn::Tag
|
||||||
|
|
||||||
|
self.include_root_in_json = false
|
||||||
|
|
||||||
def followed_count
|
def followed_count
|
||||||
@followed_count ||= TagFollowing.where(:tag_id => self.id).count
|
@followed_count ||= TagFollowing.where(:tag_id => self.id).count
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,8 @@
|
||||||
= yield(:head)
|
= yield(:head)
|
||||||
= csrf_meta_tag
|
= csrf_meta_tag
|
||||||
|
|
||||||
|
= include_gon(:camel_case => true, :namespace => :preloads)
|
||||||
|
|
||||||
%body
|
%body
|
||||||
= flash_messages
|
= flash_messages
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,15 +7,4 @@
|
||||||
%li
|
%li
|
||||||
%b=link_to t('streams.followed_tag.title'), followed_tags_stream_path, :class => 'home_selector'
|
%b=link_to t('streams.followed_tag.title'), followed_tags_stream_path, :class => 'home_selector'
|
||||||
|
|
||||||
- if @stream.is_a?(Stream::FollowedTag)
|
%ul.sub_nav#tags_list
|
||||||
%ul.sub_nav
|
|
||||||
- if tags.size > 0
|
|
||||||
- for tg in tags
|
|
||||||
%li.unfollow{:id => "tag-following-#{tg.name}"}
|
|
||||||
.unfollow_icon.hidden
|
|
||||||
= link_to image_tag("icons/monotone_close_exit_delete.png", :height => 16, :title => t('aspects.index.unfollow_tag', :tag => tg.name)), tag_tag_followings_path(:name => tg.name, :remote => true), :data => { :confirm => t('are_you_sure') }, :method => :delete, :remote => true, :id => "unfollow_" + tg.name
|
|
||||||
= link_to "##{tg.name}", tag_path(:name => tg.name), :class => "tag_selector"
|
|
||||||
%li
|
|
||||||
= form_for TagFollowing.new do |tg|
|
|
||||||
= text_field_tag :name, "", :class => "tag_input", :placeholder => t('streams.followed_tag.add_a_tag')
|
|
||||||
= tg.submit t('streams.followed_tag.follow'), :class => "button"
|
|
||||||
|
|
|
||||||
|
|
@ -9,27 +9,6 @@
|
||||||
- else
|
- else
|
||||||
= t('.whatup', :pod => @pod_url)
|
= t('.whatup', :pod => @pod_url)
|
||||||
|
|
||||||
- content_for :head do
|
|
||||||
= javascript_include_tag :home
|
|
||||||
:javascript
|
|
||||||
$(document).ready(function(){
|
|
||||||
// Change the text and color of the "follow this tag" button on hover.
|
|
||||||
$(".button.tag_following").hover(function(){
|
|
||||||
$this = $(this);
|
|
||||||
$this.removeClass("in_aspects");
|
|
||||||
$this.val("#{t('.stop_following', :tag => @stream.tag_name)}");
|
|
||||||
},
|
|
||||||
function(){
|
|
||||||
$this = $(this);
|
|
||||||
$this.addClass("in_aspects");
|
|
||||||
$this.val("#{t('.following', :tag => @stream.tag_name)}");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
$(".people_stream .pagination a").live("click", function() {
|
|
||||||
$.getScript(this.href);
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
- content_for :body_class do
|
- content_for :body_class do
|
||||||
= "tags_show"
|
= "tags_show"
|
||||||
|
|
@ -49,12 +28,6 @@
|
||||||
.span-15.last
|
.span-15.last
|
||||||
.stream_container
|
.stream_container
|
||||||
#author_info
|
#author_info
|
||||||
- if user_signed_in?
|
|
||||||
.right
|
|
||||||
- unless tag_followed?
|
|
||||||
= button_to t('.follow', :tag => @stream.tag_name), tag_tag_followings_path(:name => @stream.tag_name), :method => :post, :class => 'button take_action'
|
|
||||||
- else
|
|
||||||
= button_to t('.following', :tag => @stream.tag_name), tag_tag_followings_path(:name => @stream.tag_name), :method => :delete, :class => 'button red_on_hover tag_following in_aspects take_action'
|
|
||||||
%h2
|
%h2
|
||||||
= @stream.display_tag_name
|
= @stream.display_tag_name
|
||||||
%small
|
%small
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@
|
||||||
|
|
||||||
.row
|
.row
|
||||||
.span13
|
.span13
|
||||||
= form_tag(multiple_tag_followings_path, :method => 'post', :class => "tag_input search_form") do
|
= form_tag(tag_followings_path, :method => 'get', :class => "tag_input search_form") do
|
||||||
%fieldset
|
%fieldset
|
||||||
.clearfix
|
.clearfix
|
||||||
= label_tag 'follow_tags', t('.hashtag_suggestions'), :class => "bootstrapped"
|
= label_tag 'follow_tags', t('.hashtag_suggestions'), :class => "bootstrapped"
|
||||||
|
|
@ -75,5 +75,5 @@
|
||||||
%br
|
%br
|
||||||
%br
|
%br
|
||||||
.input
|
.input
|
||||||
= link_to "#{t('.awesome_take_me_to_diaspora')} »", "#", :id => "awesome_button", :class => "btn primary"
|
= link_to "#{t('.awesome_take_me_to_diaspora')} »", stream_path, :id => "awesome_button", :class => "btn primary"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,17 @@ en:
|
||||||
one: "Show <%= count %> more comment"
|
one: "Show <%= count %> more comment"
|
||||||
other: "Show <%= count %> more comments"
|
other: "Show <%= count %> more comments"
|
||||||
|
|
||||||
|
followed_tag:
|
||||||
|
title: "#Followed Tags"
|
||||||
|
contacts_title: "People who dig these tags"
|
||||||
|
add_a_tag: "Add a tag"
|
||||||
|
follow: "Follow"
|
||||||
|
|
||||||
|
tags:
|
||||||
|
follow: "Follow #<%= tag %>"
|
||||||
|
following: "Following #<%= tag %>"
|
||||||
|
stop_following: "Stop Following #<%= tag %>"
|
||||||
|
|
||||||
header:
|
header:
|
||||||
home: "Home"
|
home: "Home"
|
||||||
profile: "Profile"
|
profile: "Profile"
|
||||||
|
|
|
||||||
|
|
@ -74,13 +74,8 @@ Diaspora::Application.routes.draw do
|
||||||
end
|
end
|
||||||
|
|
||||||
resources :tags, :only => [:index]
|
resources :tags, :only => [:index]
|
||||||
scope "tags/:name" do
|
|
||||||
post "tag_followings" => "tag_followings#create", :as => 'tag_tag_followings'
|
|
||||||
delete "tag_followings" => "tag_followings#destroy", :as => 'tag_tag_followings'
|
|
||||||
end
|
|
||||||
|
|
||||||
post "multiple_tag_followings" => "tag_followings#create_multiple", :as => 'multiple_tag_followings'
|
resources "tag_followings", :only => [:create, :destroy, :index]
|
||||||
resources "tag_followings", :only => [:create]
|
|
||||||
|
|
||||||
get 'tags/:name' => 'tags#show', :as => 'tag'
|
get 'tags/:name' => 'tags#show', :as => 'tag'
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -67,12 +67,12 @@ describe PeopleController do
|
||||||
context 'query is a tag' do
|
context 'query is a tag' do
|
||||||
it 'goes to a tag page' do
|
it 'goes to a tag page' do
|
||||||
get :index, :q => '#babies'
|
get :index, :q => '#babies'
|
||||||
response.should redirect_to(tag_path('babies', :q => '#babies'))
|
response.should redirect_to(tag_path('babies'))
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'removes dots from the query' do
|
it 'removes dots from the query' do
|
||||||
get :index, :q => '#babi.es'
|
get :index, :q => '#babi.es'
|
||||||
response.should redirect_to(tag_path('babies', :q => '#babi.es'))
|
response.should redirect_to(tag_path('babies'))
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'stay on the page if you search for the empty hash' do
|
it 'stay on the page if you search for the empty hash' do
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
describe("app.collections.TagFollowings", function(){
|
||||||
|
beforeEach(function(){
|
||||||
|
this.collection = new app.collections.TagFollowings();
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("create", function(){
|
||||||
|
it("should not allow duplicates", function(){
|
||||||
|
this.collection.create({"name":"name"})
|
||||||
|
this.collection.create({"name":"name"})
|
||||||
|
expect(this.collection.length).toBe(1)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
50
spec/javascripts/app/views/tag_following_action_view_spec.js
Normal file
50
spec/javascripts/app/views/tag_following_action_view_spec.js
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
describe("app.views.TagFollowingAction", function(){
|
||||||
|
beforeEach(function(){
|
||||||
|
app.tagFollowings = new app.collections.TagFollowings();
|
||||||
|
this.tagName = "test_tag";
|
||||||
|
this.view = new app.views.TagFollowingAction({tagName : this.tagName})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("render", function(){
|
||||||
|
it("shows the output of followString", function(){
|
||||||
|
spyOn(this.view, "tag_is_followed").andReturn(false)
|
||||||
|
spyOn(this.view, "followString").andReturn("a_follow_string")
|
||||||
|
expect(this.view.render().$('input').val()).toMatch(/^a_follow_string$/)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should have the extra classes if the tag is followed", function(){
|
||||||
|
spyOn(this.view, "tag_is_followed").andReturn(true)
|
||||||
|
expect(this.view.render().$('input').hasClass("red_on_hover")).toBe(true)
|
||||||
|
expect(this.view.render().$('input').hasClass("in_aspects")).toBe(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("tagAction", function(){
|
||||||
|
it("toggles the tagFollowed from followed to unfollowed", function(){
|
||||||
|
// first set the tag to followed
|
||||||
|
var origModel = this.view.model;
|
||||||
|
this.view.model.set("id", 3);
|
||||||
|
|
||||||
|
expect(this.view.tag_is_followed()).toBe(true);
|
||||||
|
spyOn(this.view.model, "destroy").andCallFake(_.bind(function(){
|
||||||
|
// model.destroy leads to collection.remove, which is bound to getTagFollowing
|
||||||
|
this.view.getTagFollowing();
|
||||||
|
}, this) )
|
||||||
|
this.view.tagAction();
|
||||||
|
expect(origModel.destroy).toHaveBeenCalled()
|
||||||
|
|
||||||
|
expect(this.view.tag_is_followed()).toBe(false);
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
it("toggles the tagFollowed from unfollowed to followed", function(){
|
||||||
|
expect(this.view.tag_is_followed()).toBe(false);
|
||||||
|
spyOn(app.tagFollowings, "create").andCallFake(function(model){
|
||||||
|
// 'save' the model by giving it an id
|
||||||
|
model.set("id", 3)
|
||||||
|
})
|
||||||
|
this.view.tagAction();
|
||||||
|
expect(this.view.tag_is_followed()).toBe(true);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
Loading…
Reference in a new issue