Commit fc5d7084b765d96a4733137292fde96bfcdad623
1 parent
13851777
Exists in
master
and in
29 other branches
ActionItem152: implenting a tags blocks
git-svn-id: https://svn.colivre.coop.br/svn/noosfero/trunk@1259 3f533792-8f58-4932-b0fe-aaf55b0a4547
Showing
14 changed files
with
177 additions
and
13 deletions
Show diff stats
app/controllers/application.rb
... | ... | @@ -53,7 +53,7 @@ class ApplicationController < ActionController::Base |
53 | 53 | def render_not_found(path = nil) |
54 | 54 | @path ||= request.path |
55 | 55 | # raise "#{@path} not found" |
56 | - render(:file => File.join(RAILS_ROOT, 'app', 'views', 'shared', 'not_found.rhtml'), :layout => 'not_found', :status => 404) && fal | |
56 | + render(:file => File.join(RAILS_ROOT, 'app', 'views', 'shared', 'not_found.rhtml'), :layout => 'not_found', :status => 404) | |
57 | 57 | end |
58 | 58 | |
59 | 59 | def user | ... | ... |
app/controllers/my_profile/profile_design_controller.rb
app/controllers/public/profile_controller.rb
app/controllers/public/search_controller.rb
1 | 1 | class SearchController < ApplicationController |
2 | 2 | |
3 | + helper TagsHelper | |
4 | + | |
3 | 5 | SEARCHES = [] |
4 | 6 | |
5 | 7 | def self.search(&block) |
... | ... | @@ -44,7 +46,10 @@ class SearchController < ApplicationController |
44 | 46 | end |
45 | 47 | |
46 | 48 | def tags |
47 | - @tags = Tag.find(:all) | |
49 | + @tags = Tag.find(:all).inject({}) do |memo,tag| | |
50 | + memo[tag.name] = tag.taggings.count | |
51 | + memo | |
52 | + end | |
48 | 53 | end |
49 | 54 | |
50 | 55 | def tag | ... | ... |
... | ... | @@ -0,0 +1,51 @@ |
1 | +module TagsHelper | |
2 | + | |
3 | + module Cloud | |
4 | + MAX_SIZE = 32 | |
5 | + MIN_SIZE = 12 | |
6 | + end | |
7 | + | |
8 | + # <tt>tags</tt> must be a hash where the keys are tag names and the values | |
9 | + # the count of elements tagged with the tag, as returned by | |
10 | + # Profile#find_tagged_with. If not tags were returned, just returns | |
11 | + # _('No tags yet.') | |
12 | + # | |
13 | + # <tagname_option> must be a symbol representing the key to be inserted in | |
14 | + # <tt>url</tt> with the tag name as value, if <tt>url</tt> is a Hash. If | |
15 | + # <tt>url_options</tt> is a String, then the tag name is just appended to it. | |
16 | + # | |
17 | + # Example: | |
18 | + # | |
19 | + # tag_cloud({ 'first-tag' => 10, 'second-tag' => 2, 'third-tag' => 1 }, :id, { :action => 'show_tag' }) | |
20 | + # | |
21 | + # <tt>options</tt> can include one or more of the following: | |
22 | + # | |
23 | + # * <tt>:max_size</tt>: font size for the tag with largest count | |
24 | + # * <tt>:min_size</tt>: font size for the tag with smallest count | |
25 | + # | |
26 | + # The algorithm for generating the different sizes and positions is a | |
27 | + # courtesy of Aurelio: http://www.colivre.coop.br/Aurium/Nuvem | |
28 | + # (pt_BR only). | |
29 | + def tag_cloud(tags, tagname_option, url, options = {}) | |
30 | + | |
31 | + return _('No tags yet.') if tags.empty? | |
32 | + | |
33 | + max_size = options[:max_size] || Cloud::MAX_SIZE | |
34 | + min_size = options[:min_size] || Cloud::MIN_SIZE | |
35 | + | |
36 | + delta = max_size - min_size | |
37 | + max = tags.values.max.to_f | |
38 | + | |
39 | + tags.map do |tag,count| | |
40 | + v = count.to_f / max | |
41 | + style = <<-EOS | |
42 | + font-size: #{ (v * delta).round + min_size }px; | |
43 | + top: #{ -4 - (v * 4).round }px; | |
44 | + EOS | |
45 | + destination = url.kind_of?(Hash) ? url_for(url.merge(tagname_option => tag)) : (url.to_s + tag) | |
46 | + | |
47 | + link_to "#{tag} (#{count})", destination, :style => style | |
48 | + end.join("\n") | |
49 | + end | |
50 | + | |
51 | +end | ... | ... |
app/models/block.rb
app/models/profile.rb
... | ... | @@ -187,4 +187,23 @@ class Profile < ActiveRecord::Base |
187 | 187 | options |
188 | 188 | end |
189 | 189 | |
190 | + def tags(public_only = false) | |
191 | + totals = {} | |
192 | + articles.each do |article| | |
193 | + article.tags.each do |tag| | |
194 | + if totals[tag.name] | |
195 | + totals[tag.name] += 1 | |
196 | + else | |
197 | + totals[tag.name] = 1 | |
198 | + end | |
199 | + end | |
200 | + end | |
201 | + totals | |
202 | + end | |
203 | + | |
204 | + def find_tagged_with(tag) | |
205 | + # FIXME: this can be SLOW | |
206 | + articles.select {|item| item.tags.map(&:name).include?(tag) } | |
207 | + end | |
208 | + | |
190 | 209 | end | ... | ... |
... | ... | @@ -0,0 +1,15 @@ |
1 | +class TagsBlock < Block | |
2 | + | |
3 | + include TagsHelper | |
4 | + include ActionView::Helpers::UrlHelper | |
5 | + | |
6 | + def self.description | |
7 | + _('List count of contents by tag') | |
8 | + end | |
9 | + | |
10 | + def content(main_content = nil) | |
11 | + content_tag('h3', _('Tags'), :class => 'block-title') + | |
12 | + tag_cloud(owner.tags, :id, owner.generate_url(:controller => 'profile', :action => 'tag') + '/', :max_size => 20, :min_size => 10) | |
13 | + end | |
14 | + | |
15 | +end | ... | ... |
app/views/profile/index.rhtml
... | ... | @@ -13,4 +13,9 @@ |
13 | 13 | <%# FIXME %> |
14 | 14 | <li><%= link_to_function _('Friends'), 'alert("not yet")' %></li> |
15 | 15 | <li><%= link_to_function _('Communities'), 'alert("not yet")' %></li> |
16 | + | |
17 | + <li> | |
18 | + <%= _('Tags:') %> | |
19 | + <%= tag_cloud @tags, :id, { :action => 'tag' }, :max_size => 18, :min_size => 10%> | |
20 | + </li> | |
16 | 21 | </ul> | ... | ... |
app/views/search/tags.rhtml
config/routes.rb
... | ... | @@ -44,7 +44,7 @@ ActionController::Routing::Routes.draw do |map| |
44 | 44 | map.controllers 'block/:profile/:controller/:action/:id', :controller => Noosfero.pattern_for_controllers_from_design_blocks |
45 | 45 | |
46 | 46 | # public profile information |
47 | - map.profile 'profile/:profile/:action', :controller => 'profile', :action => 'index' | |
47 | + map.profile 'profile/:profile/:action/:id', :controller => 'profile', :action => 'index' | |
48 | 48 | |
49 | 49 | ###################################################### |
50 | 50 | ## Controllers that are profile-specific (for profile admins ) | ... | ... |
test/test_helper.rb
... | ... | @@ -56,6 +56,13 @@ class Test::Unit::TestCase |
56 | 56 | admin_user.login |
57 | 57 | end |
58 | 58 | |
59 | + def create_environment(domainname) | |
60 | + env = Environment.create!(:name => domainname) | |
61 | + env.domains << Domain.new(:name => domainname) | |
62 | + env.save! | |
63 | + env | |
64 | + end | |
65 | + | |
59 | 66 | def create_user(name) |
60 | 67 | User.create!(:login => name, |
61 | 68 | :email => name + '@noosfero.org', | ... | ... |
test/unit/profile_test.rb
... | ... | @@ -231,21 +231,43 @@ class ProfileTest < Test::Unit::TestCase |
231 | 231 | end |
232 | 232 | |
233 | 233 | should 'provide url to itself' do |
234 | - profile = Profile.create!(:name => "Test Profile", :identifier => 'testprofile', :environment_id => create_environment('colivre.net').id) | |
234 | + profile = Profile.create!(:name => "Test Profile", :identifier => 'testprofile', :environment_id => create_environment('mycolivre.net').id) | |
235 | 235 | |
236 | - assert_equal 'http://colivre.net/testprofile', profile.url | |
236 | + assert_equal 'http://mycolivre.net/testprofile', profile.url | |
237 | 237 | end |
238 | 238 | |
239 | 239 | should 'generate URL' do |
240 | - profile = Profile.create!(:name => "Test Profile", :identifier => 'testprofile', :environment_id => create_environment('colivre.net').id) | |
240 | + profile = Profile.create!(:name => "Test Profile", :identifier => 'testprofile', :environment_id => create_environment('mycolivre.net').id) | |
241 | 241 | |
242 | - assert_equal 'http://colivre.net/profile/testprofile/friends', profile.generate_url(:controller => 'profile', :action => 'friends') | |
242 | + assert_equal 'http://mycolivre.net/profile/testprofile/friends', profile.generate_url(:controller => 'profile', :action => 'friends') | |
243 | 243 | end |
244 | 244 | |
245 | 245 | should 'provide URL options' do |
246 | - profile = Profile.create!(:name => "Test Profile", :identifier => 'testprofile', :environment_id => create_environment('colivre.net').id) | |
246 | + profile = Profile.create!(:name => "Test Profile", :identifier => 'testprofile', :environment_id => create_environment('mycolivre.net').id) | |
247 | 247 | |
248 | - assert_equal({:host => 'colivre.net', :profile => 'testprofile'}, profile.url_options) | |
248 | + assert_equal({:host => 'mycolivre.net', :profile => 'testprofile'}, profile.url_options) | |
249 | + end | |
250 | + | |
251 | + should 'list tags for profile' do | |
252 | + profile = Profile.create!(:name => "Test Profile", :identifier => 'testprofile') | |
253 | + profile.articles.build(:name => 'first', :tag_list => 'first-tag').save! | |
254 | + profile.articles.build(:name => 'second', :tag_list => 'first-tag, second-tag').save! | |
255 | + profile.articles.build(:name => 'third', :tag_list => 'first-tag, second-tag, third-tag').save! | |
256 | + | |
257 | + assert_equal({ 'first-tag' => 3, 'second-tag' => 2, 'third-tag' => 1 }, profile.tags) | |
258 | + | |
259 | + end | |
260 | + | |
261 | + should 'find content tagged with given tag' do | |
262 | + profile = Profile.create!(:name => "Test Profile", :identifier => 'testprofile') | |
263 | + first = profile.articles.build(:name => 'first', :tag_list => 'first-tag'); first.save! | |
264 | + second = profile.articles.build(:name => 'second', :tag_list => 'first-tag, second-tag'); second.save! | |
265 | + third = profile.articles.build(:name => 'third', :tag_list => 'first-tag, second-tag, third-tag'); third.save! | |
266 | + profile.reload | |
267 | + | |
268 | + assert_equivalent [ first, second, third], profile.find_tagged_with('first-tag') | |
269 | + assert_equivalent [ second, third ], profile.find_tagged_with('second-tag') | |
270 | + assert_equivalent [ third], profile.find_tagged_with('third-tag') | |
249 | 271 | end |
250 | 272 | |
251 | 273 | private | ... | ... |
... | ... | @@ -0,0 +1,26 @@ |
1 | +require File.dirname(__FILE__) + '/../test_helper' | |
2 | + | |
3 | +class TagsBlockTest < Test::Unit::TestCase | |
4 | + | |
5 | + def setup | |
6 | + user = create_user('testinguser').person | |
7 | + user.articles.build(:name => 'article 1', :tag_list => 'first-tag').save! | |
8 | + user.articles.build(:name => 'article 2', :tag_list => 'first-tag, second-tag').save! | |
9 | + user.articles.build(:name => 'article 3', :tag_list => 'first-tag, second-tag, third-tag').save! | |
10 | + | |
11 | + box = Box.create!(:owner => user) | |
12 | + @block = TagsBlock.create!(:box => box) | |
13 | + end | |
14 | + attr_reader :block | |
15 | + | |
16 | + should 'describe itself' do | |
17 | + assert_not_equal Block.description, TagsBlock.description | |
18 | + end | |
19 | + | |
20 | + should 'generate links to tags' do | |
21 | + assert_match /profile\/testinguser\/tag\/first-tag/, block.content | |
22 | + assert_match /profile\/testinguser\/tag\/second-tag/, block.content | |
23 | + assert_match /profile\/testinguser\/tag\/third-tag/, block.content | |
24 | + end | |
25 | + | |
26 | +end | ... | ... |