diff --git a/app/controllers/application.rb b/app/controllers/application.rb index bb49a27..212c008 100644 --- a/app/controllers/application.rb +++ b/app/controllers/application.rb @@ -53,7 +53,7 @@ class ApplicationController < ActionController::Base def render_not_found(path = nil) @path ||= request.path # raise "#{@path} not found" - render(:file => File.join(RAILS_ROOT, 'app', 'views', 'shared', 'not_found.rhtml'), :layout => 'not_found', :status => 404) && fal + render(:file => File.join(RAILS_ROOT, 'app', 'views', 'shared', 'not_found.rhtml'), :layout => 'not_found', :status => 404) end def user diff --git a/app/controllers/my_profile/profile_design_controller.rb b/app/controllers/my_profile/profile_design_controller.rb index 366a8fb..6bb60ab 100644 --- a/app/controllers/my_profile/profile_design_controller.rb +++ b/app/controllers/my_profile/profile_design_controller.rb @@ -3,7 +3,7 @@ class ProfileDesignController < BoxOrganizerController needs_profile def available_blocks - @available_blocks ||= [ Block, ArticleBlock ] + @available_blocks ||= [ Block, ArticleBlock, TagsBlock ] end end diff --git a/app/controllers/public/profile_controller.rb b/app/controllers/public/profile_controller.rb index 4e05b9d..e741ea5 100644 --- a/app/controllers/public/profile_controller.rb +++ b/app/controllers/public/profile_controller.rb @@ -1,3 +1,14 @@ class ProfileController < ApplicationController needs_profile + + helper TagsHelper + + def index + @tags = profile.tags + end + + def tag + @tag = profile.content_tagged_with(params[:id]) + end + end diff --git a/app/controllers/public/search_controller.rb b/app/controllers/public/search_controller.rb index b626975..1a17c1e 100644 --- a/app/controllers/public/search_controller.rb +++ b/app/controllers/public/search_controller.rb @@ -1,5 +1,7 @@ class SearchController < ApplicationController + helper TagsHelper + SEARCHES = [] def self.search(&block) @@ -44,7 +46,10 @@ class SearchController < ApplicationController end def tags - @tags = Tag.find(:all) + @tags = Tag.find(:all).inject({}) do |memo,tag| + memo[tag.name] = tag.taggings.count + memo + end end def tag diff --git a/app/helpers/tags_helper.rb b/app/helpers/tags_helper.rb new file mode 100644 index 0000000..2829131 --- /dev/null +++ b/app/helpers/tags_helper.rb @@ -0,0 +1,51 @@ +module TagsHelper + + module Cloud + MAX_SIZE = 32 + MIN_SIZE = 12 + end + + # tags must be a hash where the keys are tag names and the values + # the count of elements tagged with the tag, as returned by + # Profile#find_tagged_with. If not tags were returned, just returns + # _('No tags yet.') + # + # must be a symbol representing the key to be inserted in + # url with the tag name as value, if url is a Hash. If + # url_options is a String, then the tag name is just appended to it. + # + # Example: + # + # tag_cloud({ 'first-tag' => 10, 'second-tag' => 2, 'third-tag' => 1 }, :id, { :action => 'show_tag' }) + # + # options can include one or more of the following: + # + # * :max_size: font size for the tag with largest count + # * :min_size: font size for the tag with smallest count + # + # The algorithm for generating the different sizes and positions is a + # courtesy of Aurelio: http://www.colivre.coop.br/Aurium/Nuvem + # (pt_BR only). + def tag_cloud(tags, tagname_option, url, options = {}) + + return _('No tags yet.') if tags.empty? + + max_size = options[:max_size] || Cloud::MAX_SIZE + min_size = options[:min_size] || Cloud::MIN_SIZE + + delta = max_size - min_size + max = tags.values.max.to_f + + tags.map do |tag,count| + v = count.to_f / max + style = <<-EOS + font-size: #{ (v * delta).round + min_size }px; + top: #{ -4 - (v * 4).round }px; + EOS + destination = url.kind_of?(Hash) ? url_for(url.merge(tagname_option => tag)) : (url.to_s + tag) + + link_to "#{tag} (#{count})", destination, :style => style + end.join("\n") + end + +end diff --git a/app/models/block.rb b/app/models/block.rb index eee9e24..05bb50d 100644 --- a/app/models/block.rb +++ b/app/models/block.rb @@ -1,4 +1,8 @@ class Block < ActiveRecord::Base + + # to be able to generate HTML + include ActionView::Helpers::TagHelper + acts_as_list :scope => :box belongs_to :box diff --git a/app/models/profile.rb b/app/models/profile.rb index 5c0b7f2..48cb783 100644 --- a/app/models/profile.rb +++ b/app/models/profile.rb @@ -187,4 +187,23 @@ class Profile < ActiveRecord::Base options end + def tags(public_only = false) + totals = {} + articles.each do |article| + article.tags.each do |tag| + if totals[tag.name] + totals[tag.name] += 1 + else + totals[tag.name] = 1 + end + end + end + totals + end + + def find_tagged_with(tag) + # FIXME: this can be SLOW + articles.select {|item| item.tags.map(&:name).include?(tag) } + end + end diff --git a/app/models/tags_block.rb b/app/models/tags_block.rb new file mode 100644 index 0000000..8927ce9 --- /dev/null +++ b/app/models/tags_block.rb @@ -0,0 +1,15 @@ +class TagsBlock < Block + + include TagsHelper + include ActionView::Helpers::UrlHelper + + def self.description + _('List count of contents by tag') + end + + def content(main_content = nil) + content_tag('h3', _('Tags'), :class => 'block-title') + + tag_cloud(owner.tags, :id, owner.generate_url(:controller => 'profile', :action => 'tag') + '/', :max_size => 20, :min_size => 10) + end + +end diff --git a/app/views/profile/index.rhtml b/app/views/profile/index.rhtml index 0991704..42c3a3b 100644 --- a/app/views/profile/index.rhtml +++ b/app/views/profile/index.rhtml @@ -13,4 +13,9 @@ <%# FIXME %>
  • <%= link_to_function _('Friends'), 'alert("not yet")' %>
  • <%= link_to_function _('Communities'), 'alert("not yet")' %>
  • + +
  • + <%= _('Tags:') %> + <%= tag_cloud @tags, :id, { :action => 'tag' }, :max_size => 18, :min_size => 10%> +
  • diff --git a/app/views/search/tags.rhtml b/app/views/search/tags.rhtml index 7915fc0..938320c 100644 --- a/app/views/search/tags.rhtml +++ b/app/views/search/tags.rhtml @@ -1,5 +1,4 @@

    <%= _('Tag cloud') %>

    -<% @tags.each do |t| %> - <%= link_to("#{t.name} (#{t.taggings.count})", { :action => 'tag', :tag => t.name }, :style => "font-size: #{14 + 2 * t.taggings.count}px;") %> -<% end %> +<%= tag_cloud(@tags, :tag, :action => 'tag') %> + diff --git a/config/routes.rb b/config/routes.rb index c9920b9..98adf7a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -44,7 +44,7 @@ ActionController::Routing::Routes.draw do |map| map.controllers 'block/:profile/:controller/:action/:id', :controller => Noosfero.pattern_for_controllers_from_design_blocks # public profile information - map.profile 'profile/:profile/:action', :controller => 'profile', :action => 'index' + map.profile 'profile/:profile/:action/:id', :controller => 'profile', :action => 'index' ###################################################### ## Controllers that are profile-specific (for profile admins ) diff --git a/test/test_helper.rb b/test/test_helper.rb index 7b09edd..a208b89 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -56,6 +56,13 @@ class Test::Unit::TestCase admin_user.login end + def create_environment(domainname) + env = Environment.create!(:name => domainname) + env.domains << Domain.new(:name => domainname) + env.save! + env + end + def create_user(name) User.create!(:login => name, :email => name + '@noosfero.org', diff --git a/test/unit/profile_test.rb b/test/unit/profile_test.rb index a7889be..4285eee 100644 --- a/test/unit/profile_test.rb +++ b/test/unit/profile_test.rb @@ -231,21 +231,43 @@ class ProfileTest < Test::Unit::TestCase end should 'provide url to itself' do - profile = Profile.create!(:name => "Test Profile", :identifier => 'testprofile', :environment_id => create_environment('colivre.net').id) + profile = Profile.create!(:name => "Test Profile", :identifier => 'testprofile', :environment_id => create_environment('mycolivre.net').id) - assert_equal 'http://colivre.net/testprofile', profile.url + assert_equal 'http://mycolivre.net/testprofile', profile.url end should 'generate URL' do - profile = Profile.create!(:name => "Test Profile", :identifier => 'testprofile', :environment_id => create_environment('colivre.net').id) + profile = Profile.create!(:name => "Test Profile", :identifier => 'testprofile', :environment_id => create_environment('mycolivre.net').id) - assert_equal 'http://colivre.net/profile/testprofile/friends', profile.generate_url(:controller => 'profile', :action => 'friends') + assert_equal 'http://mycolivre.net/profile/testprofile/friends', profile.generate_url(:controller => 'profile', :action => 'friends') end should 'provide URL options' do - profile = Profile.create!(:name => "Test Profile", :identifier => 'testprofile', :environment_id => create_environment('colivre.net').id) + profile = Profile.create!(:name => "Test Profile", :identifier => 'testprofile', :environment_id => create_environment('mycolivre.net').id) - assert_equal({:host => 'colivre.net', :profile => 'testprofile'}, profile.url_options) + assert_equal({:host => 'mycolivre.net', :profile => 'testprofile'}, profile.url_options) + end + + should 'list tags for profile' do + profile = Profile.create!(:name => "Test Profile", :identifier => 'testprofile') + profile.articles.build(:name => 'first', :tag_list => 'first-tag').save! + profile.articles.build(:name => 'second', :tag_list => 'first-tag, second-tag').save! + profile.articles.build(:name => 'third', :tag_list => 'first-tag, second-tag, third-tag').save! + + assert_equal({ 'first-tag' => 3, 'second-tag' => 2, 'third-tag' => 1 }, profile.tags) + + end + + should 'find content tagged with given tag' do + profile = Profile.create!(:name => "Test Profile", :identifier => 'testprofile') + first = profile.articles.build(:name => 'first', :tag_list => 'first-tag'); first.save! + second = profile.articles.build(:name => 'second', :tag_list => 'first-tag, second-tag'); second.save! + third = profile.articles.build(:name => 'third', :tag_list => 'first-tag, second-tag, third-tag'); third.save! + profile.reload + + assert_equivalent [ first, second, third], profile.find_tagged_with('first-tag') + assert_equivalent [ second, third ], profile.find_tagged_with('second-tag') + assert_equivalent [ third], profile.find_tagged_with('third-tag') end private diff --git a/test/unit/tags_block_test.rb b/test/unit/tags_block_test.rb new file mode 100644 index 0000000..2b9d334 --- /dev/null +++ b/test/unit/tags_block_test.rb @@ -0,0 +1,26 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class TagsBlockTest < Test::Unit::TestCase + + def setup + user = create_user('testinguser').person + user.articles.build(:name => 'article 1', :tag_list => 'first-tag').save! + user.articles.build(:name => 'article 2', :tag_list => 'first-tag, second-tag').save! + user.articles.build(:name => 'article 3', :tag_list => 'first-tag, second-tag, third-tag').save! + + box = Box.create!(:owner => user) + @block = TagsBlock.create!(:box => box) + end + attr_reader :block + + should 'describe itself' do + assert_not_equal Block.description, TagsBlock.description + end + + should 'generate links to tags' do + assert_match /profile\/testinguser\/tag\/first-tag/, block.content + assert_match /profile\/testinguser\/tag\/second-tag/, block.content + assert_match /profile\/testinguser\/tag\/third-tag/, block.content + end + +end -- libgit2 0.21.2