diff --git a/app/assets/javascripts/app/collections/tag_followings.js b/app/assets/javascripts/app/collections/tag_followings.js
new file mode 100644
index 000000000..d969a598b
--- /dev/null
+++ b/app/assets/javascripts/app/collections/tag_followings.js
@@ -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);
+ }
+ }
+
+});
diff --git a/app/assets/javascripts/app/models/tag_following.js b/app/assets/javascripts/app/models/tag_following.js
new file mode 100644
index 000000000..b2ab35977
--- /dev/null
+++ b/app/assets/javascripts/app/models/tag_following.js
@@ -0,0 +1,3 @@
+app.models.TagFollowing = Backbone.Model.extend({
+ urlRoot: "/tag_followings"
+});
diff --git a/app/assets/javascripts/app/router.js b/app/assets/javascripts/app/router.js
index 1e9a19425..6fcd6c95b 100644
--- a/app/assets/javascripts/app/router.js
+++ b/app/assets/javascripts/app/router.js
@@ -16,8 +16,8 @@ app.Router = Backbone.Router.extend({
"commented": "stream",
"liked": "stream",
"mentions": "stream",
- "followed_tags": "stream",
- "tags/:name": "stream",
+ "followed_tags": "followed_tags",
+ "tags/:name": "followed_tags",
"people/:id/photos": "photos",
"people/:id": "stream",
@@ -63,6 +63,24 @@ app.Router = Backbone.Router.extend({
app.photos = new app.models.Stream([], {collection: app.collections.Photos});
app.page = new app.views.Photos({model : app.photos});
$("#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)
+ }
}
});
diff --git a/app/assets/javascripts/app/views/tag_following_action_view.js b/app/assets/javascripts/app/views/tag_following_action_view.js
new file mode 100644
index 000000000..fbfe2bae2
--- /dev/null
+++ b/app/assets/javascripts/app/views/tag_following_action_view.js
@@ -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);
+ }
+ }
+});
\ No newline at end of file
diff --git a/app/assets/javascripts/app/views/tag_following_list_view.js b/app/assets/javascripts/app/views/tag_following_list_view.js
new file mode 100644
index 000000000..192d276ea
--- /dev/null
+++ b/app/assets/javascripts/app/views/tag_following_list_view.js
@@ -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);
+ }
+
+});
\ No newline at end of file
diff --git a/app/assets/javascripts/app/views/tag_following_view.js b/app/assets/javascripts/app/views/tag_following_view.js
new file mode 100644
index 000000000..f59defb32
--- /dev/null
+++ b/app/assets/javascripts/app/views/tag_following_view.js
@@ -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
+ })
+ }
+
+});
\ No newline at end of file
diff --git a/app/assets/javascripts/pages/users-getting-started.js b/app/assets/javascripts/pages/users-getting-started.js
index ec59feb8f..c402ee35c 100644
--- a/app/assets/javascripts/pages/users-getting-started.js
+++ b/app/assets/javascripts/pages/users-getting-started.js
@@ -36,12 +36,10 @@ Diaspora.Pages.UsersGettingStarted = function() {
});
$("#awesome_button").bind("click", function(evt){
- evt.preventDefault();
var confirmMessage = Diaspora.I18n.t("getting_started.no_tags");
if(($("#as-selections-tags").find(".as-selection-item").length > 0) || confirm(confirmMessage)) {
- $('.tag_input').submit();
/* flash message prompt */
var message = Diaspora.I18n.t("getting_started.preparing_your_stream");
@@ -55,18 +53,25 @@ Diaspora.Pages.UsersGettingStarted = function() {
/* ------ */
var autocompleteInput = $("#follow_tags");
+ var tagFollowings = new app.collections.TagFollowings();
autocompleteInput.autoSuggest("/tags", {
selectedItemProp: "name",
+ selectedValuesProp: "name",
searchObjProps: "name",
asHtmlID: "tags",
neverSubmit: true,
- retriveLimit: 10,
+ retrieveLimit: 10,
selectionLimit: false,
minChars: 2,
keyDelay: 200,
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){
diff --git a/app/assets/stylesheets/application.css.sass b/app/assets/stylesheets/application.css.sass
index 50343261e..f2dc85d55 100644
--- a/app/assets/stylesheets/application.css.sass
+++ b/app/assets/stylesheets/application.css.sass
@@ -2778,6 +2778,7 @@ a.toggle_selector
:left 24px
input[type='text']
+ :width 100%
:font
:size 13px
diff --git a/app/assets/templates/tag_following_action_tpl.jst.hbs b/app/assets/templates/tag_following_action_tpl.jst.hbs
new file mode 100644
index 000000000..606f6778f
--- /dev/null
+++ b/app/assets/templates/tag_following_action_tpl.jst.hbs
@@ -0,0 +1,10 @@
+
+
+
\ No newline at end of file
diff --git a/app/assets/templates/tag_following_list_tpl.jst.hbs b/app/assets/templates/tag_following_list_tpl.jst.hbs
new file mode 100644
index 000000000..279fbefa7
--- /dev/null
+++ b/app/assets/templates/tag_following_list_tpl.jst.hbs
@@ -0,0 +1,5 @@
+
+
+
\ No newline at end of file
diff --git a/app/assets/templates/tag_following_tpl.jst.hbs b/app/assets/templates/tag_following_tpl.jst.hbs
new file mode 100644
index 000000000..d19868afb
--- /dev/null
+++ b/app/assets/templates/tag_following_tpl.jst.hbs
@@ -0,0 +1,9 @@
+
+
+
+ #{{ name }}
+
diff --git a/app/controllers/people_controller.rb b/app/controllers/people_controller.rb
index 473165f83..d54a02f1e 100644
--- a/app/controllers/people_controller.rb
+++ b/app/controllers/people_controller.rb
@@ -153,7 +153,8 @@ class PeopleController < ApplicationController
def redirect_if_tag_search
if search_query.starts_with?('#')
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
flash[:error] = I18n.t('tags.show.none', :name => search_query)
redirect_to :back
diff --git a/app/controllers/streams_controller.rb b/app/controllers/streams_controller.rb
index a28f47715..4d6f2852c 100644
--- a/app/controllers/streams_controller.rb
+++ b/app/controllers/streams_controller.rb
@@ -52,6 +52,7 @@ class StreamsController < ApplicationController
end
def followed_tags
+ gon.tagFollowings = tags
stream_responder(Stream::FollowedTag)
end
diff --git a/app/controllers/tag_followings_controller.rb b/app/controllers/tag_followings_controller.rb
index fc5aa0ca4..c447d9e92 100644
--- a/app/controllers/tag_followings_controller.rb
+++ b/app/controllers/tag_followings_controller.rb
@@ -6,7 +6,7 @@
class TagFollowingsController < ApplicationController
before_filter :authenticate_user!
- respond_to :html, :json
+ respond_to :json
# POST /tag_followings
# POST /tag_followings.xml
@@ -14,52 +14,38 @@ class TagFollowingsController < ApplicationController
name_normalized = ActsAsTaggableOn::Tag.normalize(params['name'])
if name_normalized.nil? || name_normalized.empty?
- flash[:error] = I18n.t('tag_followings.create.none')
+ render :nothing => true, :status => 403
else
@tag = ActsAsTaggableOn::Tag.find_or_create_by_name(name_normalized)
@tag_following = current_user.tag_followings.new(:tag_id => @tag.id)
if @tag_following.save
- flash[:notice] = I18n.t('tag_followings.create.success', :name => name_normalized)
+ render :json => @tag.to_json, :status => 201
else
- flash[:error] = I18n.t('tag_followings.create.failure', :name => name_normalized)
+ render :nothing => true, :status => 403
end
end
- redirect_to :back
end
# DELETE /tag_followings/1
# DELETE /tag_followings/1.xml
def destroy
- @tag = ActsAsTaggableOn::Tag.find_by_name(params[:name])
- tag_following = current_user.tag_followings.find_by_tag_id( @tag.id )
+ tag_following = current_user.tag_followings.find_by_tag_id( params['id'] )
+
if tag_following && tag_following.destroy
- tag_unfollowed = true
+ respond_to do |format|
+ format.any(:js, :json) { render :nothing => true, :status => 204 }
+ end
else
- tag_unfollowed = false
- end
-
- 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)
+ respond_to do |format|
+ format.any(:js, :json) {render :nothing => true, :status => 403}
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
diff --git a/app/controllers/tags_controller.rb b/app/controllers/tags_controller.rb
index 45a8ee954..13766ac13 100644
--- a/app/controllers/tags_controller.rb
+++ b/app/controllers/tags_controller.rb
@@ -32,8 +32,10 @@ class TagsController < ApplicationController
end
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])
-
respond_with do |format|
format.json { render :json => @stream.stream_posts.map { |p| LastThreeCommentsDecorator.new(PostPresenter.new(p, current_user)) }}
end
@@ -47,18 +49,10 @@ class TagsController < ApplicationController
def prep_tags_for_javascript
@tags.map! do |tag|
- {
- :name => ("#" + tag.name),
- :value => ("#" + tag.name),
- :url => tag_path(tag.name)
- }
+ { :name => ("#" + tag.name) }
end
- @tags << {
- :name => ('#' + params[:q]),
- :value => ("#" + params[:q]),
- :url => tag_path(params[:q].downcase)
- }
+ @tags << { :name => ('#' + params[:q]) }
@tags.uniq!
end
end
diff --git a/app/models/acts_as_taggable_on/tag.rb b/app/models/acts_as_taggable_on/tag.rb
index 1806262e7..70b77f69b 100644
--- a/app/models/acts_as_taggable_on/tag.rb
+++ b/app/models/acts_as_taggable_on/tag.rb
@@ -1,5 +1,7 @@
class ActsAsTaggableOn::Tag
+ self.include_root_in_json = false
+
def followed_count
@followed_count ||= TagFollowing.where(:tag_id => self.id).count
end
diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml
index af2d720fc..3aa6a640b 100644
--- a/app/views/layouts/application.html.haml
+++ b/app/views/layouts/application.html.haml
@@ -46,6 +46,8 @@
= yield(:head)
= csrf_meta_tag
+ = include_gon(:camel_case => true, :namespace => :preloads)
+
%body
= flash_messages
diff --git a/app/views/tags/_followed_tags_listings.haml b/app/views/tags/_followed_tags_listings.haml
index d61837c18..defb05517 100644
--- a/app/views/tags/_followed_tags_listings.haml
+++ b/app/views/tags/_followed_tags_listings.haml
@@ -7,15 +7,4 @@
%li
%b=link_to t('streams.followed_tag.title'), followed_tags_stream_path, :class => 'home_selector'
- - if @stream.is_a?(Stream::FollowedTag)
- %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"
+ %ul.sub_nav#tags_list
diff --git a/app/views/tags/show.haml b/app/views/tags/show.haml
index 02f11a6b8..d04b53c5c 100644
--- a/app/views/tags/show.haml
+++ b/app/views/tags/show.haml
@@ -9,27 +9,6 @@
- else
= 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
= "tags_show"
@@ -49,12 +28,6 @@
.span-15.last
.stream_container
#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
= @stream.display_tag_name
%small
diff --git a/app/views/users/getting_started.haml b/app/views/users/getting_started.haml
index 63b0a728a..0e75475ab 100644
--- a/app/views/users/getting_started.haml
+++ b/app/views/users/getting_started.haml
@@ -63,7 +63,7 @@
.row
.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
.clearfix
= label_tag 'follow_tags', t('.hashtag_suggestions'), :class => "bootstrapped"
@@ -75,5 +75,5 @@
%br
%br
.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"
diff --git a/config/locales/javascript/javascript.en.yml b/config/locales/javascript/javascript.en.yml
index 851f5236d..d5f960636 100644
--- a/config/locales/javascript/javascript.en.yml
+++ b/config/locales/javascript/javascript.en.yml
@@ -106,6 +106,17 @@ en:
one: "Show <%= count %> more comment"
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:
home: "Home"
profile: "Profile"
diff --git a/config/routes.rb b/config/routes.rb
index 89f2e91d2..781166415 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -74,13 +74,8 @@ Diaspora::Application.routes.draw do
end
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]
+ resources "tag_followings", :only => [:create, :destroy, :index]
get 'tags/:name' => 'tags#show', :as => 'tag'
diff --git a/spec/controllers/people_controller_spec.rb b/spec/controllers/people_controller_spec.rb
index fb311c9b1..21bbcc87c 100644
--- a/spec/controllers/people_controller_spec.rb
+++ b/spec/controllers/people_controller_spec.rb
@@ -67,12 +67,12 @@ describe PeopleController do
context 'query is a tag' do
it 'goes to a tag page' do
get :index, :q => '#babies'
- response.should redirect_to(tag_path('babies', :q => '#babies'))
+ response.should redirect_to(tag_path('babies'))
end
it 'removes dots from the query' do
get :index, :q => '#babi.es'
- response.should redirect_to(tag_path('babies', :q => '#babi.es'))
+ response.should redirect_to(tag_path('babies'))
end
it 'stay on the page if you search for the empty hash' do
diff --git a/spec/javascripts/app/collections/tag_following_collection_spec.js b/spec/javascripts/app/collections/tag_following_collection_spec.js
new file mode 100644
index 000000000..6567a3b0a
--- /dev/null
+++ b/spec/javascripts/app/collections/tag_following_collection_spec.js
@@ -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)
+ })
+ })
+})
diff --git a/spec/javascripts/app/views/tag_following_action_view_spec.js b/spec/javascripts/app/views/tag_following_action_view_spec.js
new file mode 100644
index 000000000..f82d60bb3
--- /dev/null
+++ b/spec/javascripts/app/views/tag_following_action_view_spec.js
@@ -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);
+ })
+ })
+})