Commit 841621ab0a17b37c13f2e8f3d9259bbd943c8d0e
Committed by
Joenio Costa
1 parent
3c6a2941
Exists in
master
and in
29 other branches
Improving profile/communities listing and show a profile balloon when trigger is clicked
(ActionItem1587,ActionItem1588)
Showing
29 changed files
with
1225 additions
and
41 deletions
Show diff stats
... | ... | @@ -0,0 +1,58 @@ |
1 | +class BrowseController < PublicController | |
2 | + | |
3 | + no_design_blocks | |
4 | + | |
5 | + FILTERS = %w( | |
6 | + more_recent | |
7 | + more_active | |
8 | + more_popular | |
9 | + ) | |
10 | + | |
11 | + def people | |
12 | + @filter = filter | |
13 | + @title = self.filter_description(params[:action] + '_' + @filter ) | |
14 | + | |
15 | + @results = @environment.people.send(@filter) | |
16 | + | |
17 | + if params[:query].blank? | |
18 | + @results = @results.paginate(:per_page => 27, :page => params[:page]) | |
19 | + else | |
20 | + @results = @results.find_by_contents(params[:query]).paginate(:per_page => 27, :page => params[:page]) | |
21 | + end | |
22 | + end | |
23 | + | |
24 | + def communities | |
25 | + @filter = filter | |
26 | + @title = self.filter_description(params[:action] + '_' + @filter ) | |
27 | + | |
28 | + @results = @environment.communities.send(@filter) | |
29 | + | |
30 | + if params[:query].blank? | |
31 | + @results = @results.paginate(:per_page => 27, :page => params[:page]) | |
32 | + else | |
33 | + @results = @results.find_by_contents(params[:query]).paginate(:per_page => 27, :page => params[:page]) | |
34 | + end | |
35 | + end | |
36 | + | |
37 | + protected | |
38 | + | |
39 | + def filter | |
40 | + if FILTERS.include?(params[:filter]) | |
41 | + params[:filter] | |
42 | + else | |
43 | + 'more_recent' | |
44 | + end | |
45 | + end | |
46 | + | |
47 | + def filter_description(str) | |
48 | + { | |
49 | + 'people_more_recent' => _('People more recent'), | |
50 | + 'people_more_active' => _('People more active'), | |
51 | + 'people_more_popular' => _('People more popular'), | |
52 | + 'communities_more_recent' => _('Communities more recent'), | |
53 | + 'communities_more_active' => _('Communities more active'), | |
54 | + 'communities_more_popular' => _('Communities more popular'), | |
55 | + }[str] || str | |
56 | + end | |
57 | + | |
58 | +end | ... | ... |
app/helpers/application_helper.rb
... | ... | @@ -479,9 +479,38 @@ module ApplicationHelper |
479 | 479 | :class => the_class |
480 | 480 | end |
481 | 481 | |
482 | + def links_for_balloon(profile) | |
483 | + if environment.enabled?(:show_balloon_with_profile_links_when_clicked) | |
484 | + if profile.kind_of?(Person) | |
485 | + [ | |
486 | + {_('Home Page') => url_for(profile.url)}, | |
487 | + {_('Profile') => url_for(profile.public_profile_url)}, | |
488 | + {_('Friends') => url_for(:controller => :profile, :action => :friends, :profile => profile.identifier)}, | |
489 | + {_('Communities') => url_for(:controller => :profile, :action => :communities, :profile => profile.identifier)} | |
490 | + ] | |
491 | + elsif profile.kind_of?(Community) | |
492 | + [ | |
493 | + {_('Home Page') => url_for(profile.url)}, | |
494 | + {_('Profile') => url_for(profile.public_profile_url)}, | |
495 | + {_('Members') => url_for(:controller => :profile, :action => :members, :profile => profile.identifier)}, | |
496 | + {_('Agenda') => url_for(:controller => :profile, :action => :events, :profile => profile.identifier)} | |
497 | + ] | |
498 | + elsif profile.kind_of?(Enterprise) | |
499 | + [ | |
500 | + {_('Home Page') => url_for(profile.url)}, | |
501 | + {_('Products') => catalog_path(profile.identifier)}, | |
502 | + {_('Members') => url_for(:controller => :profile, :action => :members, :profile => profile.identifier)}, | |
503 | + {_('Agenda') => url_for(:controller => :profile, :action => :events, :profile => profile.identifier)} | |
504 | + ] | |
505 | + else | |
506 | + [] | |
507 | + end | |
508 | + end | |
509 | + end | |
510 | + | |
482 | 511 | # displays a link to the profile homepage with its image (as generated by |
483 | 512 | # #profile_image) and its name below it. |
484 | - def profile_image_link( profile, size=:portrait, tag='li' ) | |
513 | + def profile_image_link( profile, size=:portrait, tag='li', extra_info = nil ) | |
485 | 514 | if profile.class == Person |
486 | 515 | name = profile.short_name |
487 | 516 | city = content_tag 'span', content_tag( 'span', profile.city, :class => 'locality' ), :class => 'adr' |
... | ... | @@ -489,11 +518,14 @@ module ApplicationHelper |
489 | 518 | name = profile.short_name |
490 | 519 | city = '' |
491 | 520 | end |
521 | + extra_info = extra_info.nil? ? '' : content_tag( 'span', extra_info, :class => 'extra_info' ) | |
522 | + links = links_for_balloon(profile) | |
492 | 523 | content_tag tag, |
524 | + (environment.enabled?(:show_balloon_with_profile_links_when_clicked) ? link_to( content_tag( 'span', _('Profile links')), '#', :onclick => "toggleSubmenu(this, '#{profile.short_name}', #{links.to_json}); return false", :class => 'menu-submenu-trigger' ) : "") + | |
493 | 525 | link_to( |
494 | 526 | content_tag( 'span', profile_image( profile, size ), :class => 'profile-image' ) + |
495 | 527 | content_tag( 'span', h(name), :class => ( profile.class == Person ? 'fn' : 'org' ) ) + |
496 | - city + profile_sex_icon( profile ) + profile_cat_icons( profile ), | |
528 | + city + extra_info + profile_sex_icon( profile ) + profile_cat_icons( profile ), | |
497 | 529 | profile.url, |
498 | 530 | :onclick => 'document.location.href = this.href', # work-arround for ie. |
499 | 531 | :class => 'profile_link url', |
... | ... | @@ -1019,4 +1051,34 @@ module ApplicationHelper |
1019 | 1051 | ") : '') |
1020 | 1052 | end |
1021 | 1053 | |
1054 | + def browse_people_menu | |
1055 | + links = [ | |
1056 | + {_('More Recent') => url_for({:controller => 'browse', :action => 'people', :filter => 'more_recent'})}, | |
1057 | + {_('More Active') => url_for({:controller => 'browse', :action => 'people', :filter => 'more_active'})}, | |
1058 | + {_('More Popular') => url_for({:controller => 'browse', :action => 'people', :filter => 'more_popular'})} | |
1059 | + ] | |
1060 | + if logged_in? | |
1061 | + links.push(_('My friends') => url_for({:profile => current_user.login, :controller => 'friends'})) | |
1062 | + links.push(_('Invite friends') => url_for({:profile => current_user.login, :controller => 'invite', :action => 'friends'})) | |
1063 | + end | |
1064 | + | |
1065 | + link_to(content_tag(:span, _('People'), :class => 'icon-menu-people'), {:controller => "browse", :action => 'people'}, :id => 'submenu-people') + | |
1066 | + link_to(content_tag(:span, _('People Menu')), '#', :onclick => "toggleSubmenu(this,'',#{links.to_json})", :class => 'menu-submenu-trigger up', :id => 'submenu-people-trigger') | |
1067 | + end | |
1068 | + | |
1069 | + def browse_communities_menu | |
1070 | + links = [ | |
1071 | + {_('More Recent') => url_for({:controller => 'browse', :action => 'communities', :filter => 'more_recent'})}, | |
1072 | + {_('More Active') => url_for({:controller => 'browse', :action => 'communities', :filter => 'more_active'})}, | |
1073 | + {_('More Popular') => url_for({:controller => 'browse', :action => 'communities', :filter => 'more_popular'})} | |
1074 | + ] | |
1075 | + if logged_in? | |
1076 | + links.push(_('My communities') => url_for({:profile => current_user.login, :controller => 'memberships'})) | |
1077 | + links.push(_('New community') => url_for({:profile => current_user.login, :controller => 'memberships', :action => 'new_community'})) | |
1078 | + end | |
1079 | + | |
1080 | + link_to(content_tag(:span, _('Communities'), :class => 'icon-menu-community'), {:controller => "browse", :action => 'communities'}, :id => 'submenu-communities') + | |
1081 | + link_to(content_tag(:span, _('Communities Menu')), '#', :onclick => "toggleSubmenu(this,'',#{links.to_json})", :class => 'menu-submenu-trigger up', :id => 'submenu-communities-trigger') | |
1082 | + end | |
1083 | + | |
1022 | 1084 | end | ... | ... |
app/models/enterprise.rb
app/models/environment.rb
... | ... | @@ -108,6 +108,7 @@ class Environment < ActiveRecord::Base |
108 | 108 | 'enable_organization_url_change' => _("Allow organizations to change their URL"), |
109 | 109 | 'admin_must_approve_new_communities' => _("Admin must approve creation of communities"), |
110 | 110 | 'enterprises_are_disabled_when_created' => __('Enterprises are disabled when created'), |
111 | + 'show_balloon_with_profile_links_when_clicked' => _('Show a balloon with profile links when a profile image is clicked'), | |
111 | 112 | } |
112 | 113 | end |
113 | 114 | ... | ... |
app/models/person.rb
... | ... | @@ -8,6 +8,12 @@ class Person < Profile |
8 | 8 | |
9 | 9 | has_many :requested_tasks, :class_name => 'Task', :foreign_key => :requestor_id, :dependent => :destroy |
10 | 10 | |
11 | + named_scope :more_popular, | |
12 | + :select => "#{Profile.qualified_column_names}, count(friend_id) as total", | |
13 | + :group => Profile.qualified_column_names, | |
14 | + :joins => :friendships, | |
15 | + :order => "total DESC" | |
16 | + | |
11 | 17 | after_destroy do |person| |
12 | 18 | Friendship.find(:all, :conditions => { :friend_id => person.id}).each { |friendship| friendship.destroy } |
13 | 19 | end |
... | ... | @@ -286,4 +292,13 @@ class Person < Profile |
286 | 292 | def relationships_cache_key |
287 | 293 | cache_key + '-profile-relationships' |
288 | 294 | end |
295 | + | |
296 | + def more_popular_label | |
297 | + amount = self.friends.count | |
298 | + { | |
299 | + 0 => _('none'), | |
300 | + 1 => _('one friend') | |
301 | + }[amount] || _("%s friends") % amount | |
302 | + end | |
303 | + | |
289 | 304 | end | ... | ... |
app/models/profile.rb
... | ... | @@ -57,7 +57,23 @@ class Profile < ActiveRecord::Base |
57 | 57 | |
58 | 58 | acts_as_taggable |
59 | 59 | |
60 | + def self.qualified_column_names | |
61 | + Profile.column_names.map{|n| [Profile.table_name, n].join('.')}.join(',') | |
62 | + end | |
63 | + | |
60 | 64 | named_scope :visible, :conditions => { :visible => true } |
65 | + named_scope :more_recent, :order => "created_at DESC" | |
66 | + named_scope :more_popular, | |
67 | + :select => "#{Profile.qualified_column_names}, count(resource_id) as total", | |
68 | + :group => Profile.qualified_column_names, | |
69 | + :joins => :role_assignments, | |
70 | + :order => "total DESC" | |
71 | + named_scope :more_active, | |
72 | + :select => "#{Profile.qualified_column_names}, count(articles.id) as total, sum(articles.comments_count) as total_comments", | |
73 | + :joins => :articles, | |
74 | + :group => Profile.qualified_column_names, | |
75 | + :order => "total DESC, total_comments DESC", | |
76 | + :conditions => ["articles.created_at BETWEEN ? AND ?", 7.days.ago, DateTime.now] | |
61 | 77 | |
62 | 78 | # FIXME ugly workaround |
63 | 79 | def self.human_attribute_name(attrib) |
... | ... | @@ -675,6 +691,26 @@ private :generate_url, :url_options |
675 | 691 | cache_key + '-members-page-' + page |
676 | 692 | end |
677 | 693 | |
694 | + def more_recent_label | |
695 | + _("Since: ") | |
696 | + end | |
697 | + | |
698 | + def more_active_label | |
699 | + amount = self.articles.count | |
700 | + { | |
701 | + 0 => _('none'), | |
702 | + 1 => _('one article') | |
703 | + }[amount] || _("%s articles") % amount | |
704 | + end | |
705 | + | |
706 | + def more_popular_label | |
707 | + amount = self.members.count | |
708 | + { | |
709 | + 0 => _('none'), | |
710 | + 1 => _('one member') | |
711 | + }[amount] || _("%s members") % amount | |
712 | + end | |
713 | + | |
678 | 714 | protected |
679 | 715 | |
680 | 716 | def display_private_info_to?(user) |
... | ... | @@ -684,4 +720,5 @@ private :generate_url, :url_options |
684 | 720 | (user == self) || (user.is_admin?(self.environment)) || user.is_admin?(self) || user.memberships.include?(self) |
685 | 721 | end |
686 | 722 | end |
723 | + | |
687 | 724 | end | ... | ... |
... | ... | @@ -0,0 +1,19 @@ |
1 | +<div id="browse-results"> | |
2 | + | |
3 | + <div class='browse-results-innerbox'> | |
4 | + <% if @results.empty? %> | |
5 | + <div class="browse-results-type-empty"> | |
6 | + <div> <%= _('None') %> </div> | |
7 | + </div><!-- end class="browse-results-innerbox" --> | |
8 | + <% end %> | |
9 | + <ul class='common-profile-list-block'> | |
10 | + <% @results.each do |result| %> | |
11 | + <%= render :partial => partial_for_class(result.class), :locals => {:profile => result} %> | |
12 | + <% end %> | |
13 | + </ul> | |
14 | + <br style='clear: both;'> | |
15 | + </div> | |
16 | + | |
17 | + <br style="clear:both" /> | |
18 | +</div><!-- end id="browse-results" --> | |
19 | + | ... | ... |
... | ... | @@ -0,0 +1 @@ |
1 | +<%= profile_image_link profile, :portrait, 'li', @filter == 'more_recent' ? profile.send(@filter + '_label') + show_date(profile.created_at) : profile.send(@filter + '_label') %> | ... | ... |
... | ... | @@ -0,0 +1,10 @@ |
1 | +<% form_tag( { :controller => 'browse', :action => action}, :method => 'get', :class => 'search_form' ) do %> | |
2 | + | |
3 | + <div class="search-field"> | |
4 | + <span class="formfield"> | |
5 | + <%= text_field_tag 'query', @query, :size => 50 %> | |
6 | + </span> | |
7 | + <%= submit_button(:search, _('Search')) %> | |
8 | + </div> | |
9 | + | |
10 | +<% end %> | ... | ... |
config/routes.rb
... | ... | @@ -51,6 +51,10 @@ ActionController::Routing::Routes.draw do |map| |
51 | 51 | # search |
52 | 52 | map.connect 'search/:action/*category_path', :controller => 'search' |
53 | 53 | |
54 | + # Browse | |
55 | + map.connect 'browse/:action/:filter', :controller => 'browse' | |
56 | + map.connect 'browse/:action', :controller => 'browse' | |
57 | + | |
54 | 58 | # events |
55 | 59 | map.events 'profile/:profile/events_by_day', :controller => 'events', :action => 'events_by_day', :profile => /#{Noosfero.identifier_format}/ |
56 | 60 | map.events 'profile/:profile/events/:year/:month/:day', :controller => 'events', :action => 'events', :year => /\d*/, :month => /\d*/, :day => /\d*/, :profile => /#{Noosfero.identifier_format}/ | ... | ... |
... | ... | @@ -0,0 +1,62 @@ |
1 | +Feature: balloon | |
2 | + I want to view a balloon when mouse clicks on profile trigger | |
3 | + | |
4 | + Background: | |
5 | + Given I am on the homepage | |
6 | + Given the following users | |
7 | + | login | name | | |
8 | + | joaosilva | Joao Silva | | |
9 | + And the following communities | |
10 | + | identifier | name | | |
11 | + | sample | Sample | | |
12 | + | |
13 | + @selenium | |
14 | + Scenario: I should not see trigger if not enabled | |
15 | + Given the following blocks | |
16 | + | owner | type | | |
17 | + | environment | PeopleBlock | | |
18 | + And feature "show_balloon_with_profile_links_when_clicked" is disabled on environment | |
19 | + And I go to the homepage | |
20 | + Then I should not see "Friends" | |
21 | + | |
22 | + @selenium | |
23 | + Scenario: I should not see trigger by default | |
24 | + Given the following blocks | |
25 | + | owner | type | | |
26 | + | environment | PeopleBlock | | |
27 | + And feature "show_balloon_with_profile_links_when_clicked" is enabled on environment | |
28 | + And I go to the homepage | |
29 | + Then I should not see "Friends" | |
30 | + | |
31 | + @selenium | |
32 | + Scenario: I should see balloon when clicked on block trigger | |
33 | + Given the following blocks | |
34 | + | owner | type | | |
35 | + | environment | PeopleBlock | | |
36 | + And feature "show_balloon_with_profile_links_when_clicked" is enabled on environment | |
37 | + And I go to the homepage | |
38 | + When I click ".menu-submenu-trigger" | |
39 | + Then I should see "Profile" | |
40 | + And I should see "Friends" | |
41 | + And I should see "Home Page" | |
42 | + | |
43 | + @selenium | |
44 | + Scenario: I should not see trigger if not enabled on page | |
45 | + Given feature "show_balloon_with_profile_links_when_clicked" is disabled on environment | |
46 | + And I go to /assets/communities | |
47 | + Then I should not see "Members" | |
48 | + | |
49 | + @selenium | |
50 | + Scenario: I should not see trigger by default on page | |
51 | + Given feature "show_balloon_with_profile_links_when_clicked" is enabled on environment | |
52 | + And I go to /assets/communities | |
53 | + Then I should not see "Members" | |
54 | + | |
55 | + @selenium | |
56 | + Scenario: I should see balloon when clicked on page trigger | |
57 | + Given feature "show_balloon_with_profile_links_when_clicked" is enabled on environment | |
58 | + And I go to /assets/communities | |
59 | + When I click ".menu-submenu-trigger" | |
60 | + Then I should see "Members" | |
61 | + And I should see "Agenda" | |
62 | + And I should see "Home Page" | ... | ... |
... | ... | @@ -0,0 +1,89 @@ |
1 | +Feature: browse | |
2 | + As a noosfero visitor | |
3 | + I want to browse people and communities | |
4 | + | |
5 | + Background: | |
6 | + Given I am on the homepage | |
7 | + And the following users | |
8 | + | login | name | | |
9 | + | joaosilva | Joao Silva | | |
10 | + | pedrosilva | Pedro Silva | | |
11 | + | pauloneto | Paulo Neto | | |
12 | + And the following communities | |
13 | + | identifier | name | | |
14 | + | comunity-silva | Community Silva | | |
15 | + | comunity-neto | Community Neto | | |
16 | + | |
17 | + @selenium | |
18 | + Scenario: Show people browse menu | |
19 | + Given I should not see "More Recent" | |
20 | + And I should not see "More Active" | |
21 | + And I should not see "More Popular" | |
22 | + When I click "#submenu-people-trigger" | |
23 | + Then I should see "More Recent" | |
24 | + And I should see "More Active" | |
25 | + And I should see "More Popular" | |
26 | + | |
27 | + @selenium | |
28 | + Scenario: People browse menu should add logged information | |
29 | + Given I am logged in as "joaosilva" | |
30 | + And I should not see "More Recent" | |
31 | + And I should not see "More Active" | |
32 | + And I should not see "More Popular" | |
33 | + And I should not see "Invite friends" | |
34 | + And I should not see "My friends" | |
35 | + When I click "#submenu-people-trigger" | |
36 | + Then I should see "More Recent" | |
37 | + And I should see "More Active" | |
38 | + And I should see "More Popular" | |
39 | + And I should see "Invite friends" | |
40 | + And I should see "My friends" | |
41 | + | |
42 | + @selenium | |
43 | + Scenario: Browse people by query | |
44 | + Given I go to /browse/people | |
45 | + When I fill in "query" with "Silva" | |
46 | + And I press "Search" | |
47 | + Then I should see "Joao Silva" | |
48 | + And I should see "Pedro Silva" | |
49 | + And I should not see "Paulo Neto" | |
50 | + And I should not see "Community Silva" | |
51 | + And I should not see "Community Neto" | |
52 | + | |
53 | + @selenium | |
54 | + Scenario: Communities browse menu should add logged information | |
55 | + Given I am logged in as "joaosilva" | |
56 | + And I am on the homepage | |
57 | + And I should not see "More Recent" | |
58 | + And I should not see "More Active" | |
59 | + And I should not see "More Popular" | |
60 | + And I should not see "My communities" | |
61 | + And I should not see "New community" | |
62 | + When I click "#submenu-communities-trigger" | |
63 | + Then I should see "More Recent" | |
64 | + And I should see "More Active" | |
65 | + And I should see "More Popular" | |
66 | + And I should see "My communities" | |
67 | + And I should see "New community" | |
68 | + | |
69 | + @selenium | |
70 | + Scenario: Show communities browse menu | |
71 | + Given I should not see "More Recent" | |
72 | + And I should not see "More Active" | |
73 | + And I should not see "More Popular" | |
74 | + When I click "#submenu-communities-trigger" | |
75 | + Then I should see "More Recent" | |
76 | + And I should see "More Active" | |
77 | + And I should see "More Popular" | |
78 | + | |
79 | + @selenium | |
80 | + Scenario: Browse communities by query | |
81 | + Given I go to /browse/communities | |
82 | + When I fill in "query" with "Silva" | |
83 | + And I press "Search" | |
84 | + Then I should see "Community Silva" | |
85 | + And I should not see "Joao Silva" | |
86 | + And I should not see "Pedro Silva" | |
87 | + And I should not see "Paulo Neto" | |
88 | + And I should not see "Community Neto" | |
89 | + | ... | ... |
features/manage_products.feature
... | ... | @@ -17,31 +17,31 @@ Feature: manage products |
17 | 17 | | Bicycle | |
18 | 18 | And the following products |
19 | 19 | | owner | category | name | description | |
20 | - | redemoinho | bicycle | Bike 1 | bicycle 1 | | |
21 | - | redemoinho | bicycle | Bike 2 | bicycle 2 | | |
22 | - | redemoinho | bicycle | Bike 3 | bicycle 3 | | |
23 | - | redemoinho | bicycle | Bike 4 | bicycle 4 | | |
24 | - | redemoinho | bicycle | Bike 5 | bicycle 5 | | |
25 | - | redemoinho | bicycle | Bike 6 | bicycle 6 | | |
26 | - | redemoinho | bicycle | Bike 7 | bicycle 7 | | |
27 | - | redemoinho | bicycle | Bike 8 | bicycle 8 | | |
28 | - | redemoinho | bicycle | Bike 9 | bicycle 9 | | |
29 | - | redemoinho | bicycle | Bike 10| bicycle 10 | | |
30 | - | redemoinho | bicycle | Bike 11| bicycle 11 | | |
20 | + | redemoinho | bicycle | Bike A | bicycle 1 | | |
21 | + | redemoinho | bicycle | Bike B | bicycle 2 | | |
22 | + | redemoinho | bicycle | Bike C | bicycle 3 | | |
23 | + | redemoinho | bicycle | Bike D | bicycle 4 | | |
24 | + | redemoinho | bicycle | Bike E | bicycle 5 | | |
25 | + | redemoinho | bicycle | Bike F | bicycle 6 | | |
26 | + | redemoinho | bicycle | Bike G | bicycle 7 | | |
27 | + | redemoinho | bicycle | Bike H | bicycle 8 | | |
28 | + | redemoinho | bicycle | Bike I | bicycle 9 | | |
29 | + | redemoinho | bicycle | Bike J | bicycle 10 | | |
30 | + | redemoinho | bicycle | Bike K | bicycle 11 | | |
31 | 31 | When I go to /catalog/redemoinho |
32 | - Then I should see "Bike 1" | |
33 | - And I should see "Bike 2" | |
34 | - And I should see "Bike 3" | |
35 | - And I should see "Bike 4" | |
36 | - And I should see "Bike 5" | |
37 | - And I should see "Bike 6" | |
38 | - And I should see "Bike 7" | |
39 | - And I should see "Bike 8" | |
40 | - And I should see "Bike 9" | |
41 | - And I should see "Bike 10" | |
42 | - And I should not see "Bike 11" | |
32 | + Then I should see "Bike A" within "#product_list" | |
33 | + And I should see "Bike B" within "#product_list" | |
34 | + And I should see "Bike C" within "#product_list" | |
35 | + And I should see "Bike D" within "#product_list" | |
36 | + And I should see "Bike E" within "#product_list" | |
37 | + And I should see "Bike F" within "#product_list" | |
38 | + And I should see "Bike G" within "#product_list" | |
39 | + And I should see "Bike H" within "#product_list" | |
40 | + And I should see "Bike I" within "#product_list" | |
41 | + And I should see "Bike J" within "#product_list" | |
42 | + And I should not see "Bike K" within "#product_list" | |
43 | 43 | When I follow "Next" |
44 | - Then I should see "Bike 11" | |
44 | + Then I should see "Bike K" within "#product_list" | |
45 | 45 | |
46 | 46 | Scenario: listing products and services |
47 | 47 | Given I am logged in as "joaosilva" | ... | ... |
public/designs/themes/base/navigation.rhtml
1 | -<li><a href="/assets/people"><span class='icon-menu-people'><%= _('People') %></span></a></li> | |
2 | -<li><a href="/assets/communities"><span class='icon-menu-community'><%= _('Communities') %></span></a></li> | |
3 | -<li><a href="/assets/enterprises"><span class='icon-menu-enterprise'><%= _('Enterprises') %></span></a></li> | |
4 | -<li><a href="/assets/products"><span class='icon-menu-product'><%= _('Products') %></span></a></li> | |
1 | +<li> | |
2 | + <%= browse_people_menu %> | |
3 | +</li> | |
4 | +<li> | |
5 | + <%= browse_communities_menu %> | |
6 | +</li> | |
5 | 7 | <li><a href="/assets/events"><span class='icon-menu-events'><%= _('Events') %></span></a></li> | ... | ... |
public/designs/themes/base/style.css
... | ... | @@ -201,18 +201,20 @@ body, th, td, input { |
201 | 201 | margin: 0px; |
202 | 202 | padding: 0px 10px 0px 0px; |
203 | 203 | float: right; |
204 | - overflow: hidden; | |
205 | 204 | } |
206 | 205 | |
207 | 206 | #navigation li { |
208 | 207 | list-style: none; |
209 | 208 | display: block; |
210 | - height: 54px; | |
209 | + height: auto; | |
210 | + width: 125px; | |
211 | 211 | float: left; |
212 | - border-left: 1px solid #888a85; | |
212 | + text-align: center; | |
213 | + position: relative; | |
213 | 214 | } |
214 | 215 | |
215 | 216 | #navigation a { |
217 | + border-left: 1px solid #888a85; | |
216 | 218 | display: block; |
217 | 219 | font-size: 15px; |
218 | 220 | line-height: 42px; |
... | ... | @@ -225,11 +227,71 @@ body, th, td, input { |
225 | 227 | } |
226 | 228 | |
227 | 229 | #navigation span { |
228 | - padding: 0px 10px 0px 35px; | |
229 | - background-position: 15px 50%; | |
230 | + padding: 0px 0px 0px 30px; | |
231 | + background-position: 5px 50%; | |
230 | 232 | background-repeat: no-repeat; |
231 | 233 | } |
232 | 234 | |
235 | +#navigation .menu-submenu ul, #navigation .menu-submenu li{ | |
236 | + float: none; | |
237 | + text-align: right; | |
238 | + border-left: 0px; | |
239 | +} | |
240 | + | |
241 | +#navigation .menu-submenu ul{ | |
242 | + border: 1px solid #888a85; | |
243 | + border-top: 0px; | |
244 | + border-left: 0px; | |
245 | + background-color: #ccc; | |
246 | + padding-right: 2px; | |
247 | + height: auto; | |
248 | + display: block; | |
249 | +} | |
250 | + | |
251 | +#navigation .menu-submenu{ | |
252 | + bottom: -75px; | |
253 | + width: 126px; | |
254 | + top: 0px; | |
255 | + right: 0px; | |
256 | + position: relative; | |
257 | +} | |
258 | + | |
259 | +#navigation .menu-submenu a{ | |
260 | + padding: 4px 5px; | |
261 | + font-size: 12px; | |
262 | + line-height: normal; | |
263 | +} | |
264 | + | |
265 | +#navigation .menu-submenu-trigger { | |
266 | + background: #eee url(/images/down-arrow.png) center center no-repeat; | |
267 | + border: 0px; | |
268 | + height: 8px; | |
269 | + width: 124px; | |
270 | +} | |
271 | +#navigation li:hover .menu-submenu-trigger:hover { | |
272 | + background: #eee url(/images/down-arrow.png) center center no-repeat; | |
273 | +} | |
274 | + | |
275 | +#navigation li:hover .menu-submenu-trigger{ | |
276 | + display: block; | |
277 | +} | |
278 | + | |
279 | +#navigation li .menu-submenu-trigger{ | |
280 | + display: none; | |
281 | +} | |
282 | + | |
283 | +#navigation .menu-submenu-header, #navigation .menu-submenu-footer, #navigation .menu-submenu h4{ | |
284 | + display: none; | |
285 | +} | |
286 | + | |
287 | +#navigation .common-profile-list-block .vcard .menu-submenu-trigger, | |
288 | +.menu-submenu-trigger { | |
289 | + left: 1px; | |
290 | + top: 33px; | |
291 | + -moz-border-radius: 0px; | |
292 | + -webkit-border-radius: 0px; | |
293 | +} | |
294 | + | |
233 | 295 | /***************************** boxes ********************************/ |
234 | 296 | |
235 | 297 | .template-default .box-1 { /* Center */ |
... | ... | @@ -1119,12 +1181,12 @@ hr.pre-posts, hr.sep-posts { |
1119 | 1181 | /******** controller-friends action-friends-index ********/ |
1120 | 1182 | |
1121 | 1183 | .action-friends-index .profile-list li, |
1122 | -.common-profile-list-block .vcard a { | |
1184 | +.common-profile-list-block .vcard { | |
1123 | 1185 | border: 1px solid transparent; |
1124 | 1186 | } |
1125 | 1187 | |
1126 | 1188 | .action-friends-index .profile-list li:hover, |
1127 | -.common-profile-list-block .vcard a:hover { | |
1189 | +.common-profile-list-block .vcard:hover { | |
1128 | 1190 | border: 1px solid #CCC; |
1129 | 1191 | -moz-border-radius: 5px; |
1130 | 1192 | -webkit-border-radius: 5px; |
... | ... | @@ -1132,6 +1194,11 @@ hr.pre-posts, hr.sep-posts { |
1132 | 1194 | text-decoration: none; |
1133 | 1195 | } |
1134 | 1196 | |
1197 | +.common-profile-list-block .vcard a, | |
1198 | +.common-profile-list-block .vcard a:hover { | |
1199 | + background: transparent; | |
1200 | + border: 0; | |
1201 | +} | |
1135 | 1202 | |
1136 | 1203 | /******** controller-profile action-profile-index ********/ |
1137 | 1204 | |
... | ... | @@ -1205,4 +1272,56 @@ table.profile th { |
1205 | 1272 | border-bottom: 2px solid black; |
1206 | 1273 | } |
1207 | 1274 | |
1275 | +/**************************** Browse *******************************/ | |
1208 | 1276 | |
1277 | +.controller-browse #content .search_form { | |
1278 | + background: #DDD; | |
1279 | + -moz-border-radius: 5px; | |
1280 | + -webkit-border-radius: 5px; | |
1281 | + padding: 12px 15px 13px 15px; | |
1282 | + position: relative; | |
1283 | + text-align: left; | |
1284 | +} | |
1285 | + | |
1286 | +.controller-browse a { | |
1287 | + color: #555753; | |
1288 | +} | |
1289 | + | |
1290 | +.browse-results-innerbox { | |
1291 | + margin-top: 10px; | |
1292 | + border-bottom: none; | |
1293 | + border: 1px solid #CCC; | |
1294 | + background: url(imgs/comment-bg-S.png) 0% 100% repeat-x; | |
1295 | + padding-bottom: 10px; | |
1296 | + | |
1297 | +} | |
1298 | +.browse-results-innerbox ul{ | |
1299 | + padding: 0px; | |
1300 | +} | |
1301 | + | |
1302 | +.browse-results-innerbox .browse-results-type-empty div { | |
1303 | + text-align: center; | |
1304 | + color: #DDD; | |
1305 | + font-weight: bold; | |
1306 | + font-size: 30px; | |
1307 | + padding: 70px 10px 0px 0px; | |
1308 | + border: none; | |
1309 | + | |
1310 | +} | |
1311 | + | |
1312 | +.search-results-type-article.search-results-innerbox { | |
1313 | + padding: 5px 0px 5px 10px; | |
1314 | + max-height: 215px; | |
1315 | + height: 225px; | |
1316 | +} | |
1317 | + | |
1318 | +#content .search-results-type-article li { | |
1319 | + padding: 5px 0px; | |
1320 | +} | |
1321 | + | |
1322 | +.search-results-type-article a { | |
1323 | + text-decoration: none; | |
1324 | +} | |
1325 | +.search-results-type-article a:hover { | |
1326 | + text-decoration: underline; | |
1327 | +} | ... | ... |
1.91 KB
1.01 KB
267 Bytes
407 Bytes
261 Bytes
public/javascripts/application.js
... | ... | @@ -214,3 +214,52 @@ function expandCategory(block, id) { |
214 | 214 | } |
215 | 215 | } |
216 | 216 | } |
217 | + | |
218 | +function toggleSubmenu(trigger, title, link_list) { | |
219 | + trigger.onclick = function() { | |
220 | + var submenu = jQuery(trigger).siblings('.menu-submenu'); | |
221 | + var hide = false; | |
222 | + if (submenu.length > 0 && submenu.is(':visible')) hide = true; | |
223 | + hideAllSubmenus(); | |
224 | + // Hide or show this submenu if it already exists | |
225 | + if (submenu.length > 0) { | |
226 | + if (!hide) { | |
227 | + var direction = 'down'; | |
228 | + if (submenu.hasClass('up')) direction = 'up'; | |
229 | + submenu.show('slide', { 'direction' : direction }, 'slow'); | |
230 | + } | |
231 | + } | |
232 | + return false; | |
233 | + } | |
234 | + | |
235 | + hideAllSubmenus(); | |
236 | + // Build and show this submenu if it doesn't exist yet | |
237 | + var direction = 'down'; | |
238 | + if (jQuery(trigger).hasClass('up')) direction = 'up'; | |
239 | + var submenu = jQuery('<div></div>').attr('class', 'menu-submenu ' + direction).attr('style', 'display: none'); | |
240 | + var header = jQuery('<div></div>').attr('class', 'menu-submenu-header'); | |
241 | + var content = jQuery('<div></div>').attr('class', 'menu-submenu-content'); | |
242 | + var list = jQuery('<ul></ul>').attr('class', 'menu-submenu-list'); | |
243 | + var footer = jQuery('<div></div>').attr('class', 'menu-submenu-footer'); | |
244 | + content.append('<h4>' + title + '</h4>'); | |
245 | + jQuery.each(link_list, function(index, link_hash) { | |
246 | + for (label in link_hash) { | |
247 | + list.append('<li><a href="' + link_hash[label] + '">' + label + '</a></li>'); | |
248 | + } | |
249 | + }); | |
250 | + content.append(list); | |
251 | + submenu.append(header).append(content).append(footer); | |
252 | + jQuery(trigger).before(submenu); | |
253 | + submenu.show('slide', { 'direction' : direction }, 'slow'); | |
254 | +} | |
255 | + | |
256 | +function hideAllSubmenus() { | |
257 | + jQuery('.menu-submenu.up:visible').hide('slide', { 'direction' : 'up' }, 'slow'); | |
258 | + jQuery('.menu-submenu.down:visible').hide('slide', { 'direction' : 'down' }, 'slow'); | |
259 | +} | |
260 | + | |
261 | +// Hide visible ballons when clicked outside them | |
262 | +jQuery(document).ready(function() { | |
263 | + jQuery('body').click(function() { hideAllSubmenus(); }); | |
264 | + jQuery('.menu-submenu-trigger').click(function(e) { e.stopPropagation(); }); | |
265 | +}); | ... | ... |
public/stylesheets/application.css
... | ... | @@ -1644,13 +1644,13 @@ input.disabled { |
1644 | 1644 | margin: 0px; |
1645 | 1645 | padding: 0px; |
1646 | 1646 | list-style: none; |
1647 | - display: inline; | |
1647 | + position: relative; | |
1648 | 1648 | } |
1649 | 1649 | |
1650 | 1650 | .common-profile-list-block .vcard a { |
1651 | 1651 | display: block; |
1652 | - height: 95px; | |
1653 | - max-height: 92px; | |
1652 | + height: 112px; | |
1653 | + max-height: 112px; | |
1654 | 1654 | padding-top: 3px; |
1655 | 1655 | margin: 0px 2px; |
1656 | 1656 | float: left; |
... | ... | @@ -1738,6 +1738,12 @@ input.disabled { |
1738 | 1738 | display: none; |
1739 | 1739 | } |
1740 | 1740 | |
1741 | +.common-profile-list-block .extra_info { | |
1742 | + font-size: 9px; | |
1743 | + opacity: 0.5; | |
1744 | + filter: alpha(opacity=50); | |
1745 | +} | |
1746 | + | |
1741 | 1747 | |
1742 | 1748 | /* ==> blocks/recent-documents-block.css <<= */ |
1743 | 1749 | |
... | ... | @@ -3603,7 +3609,6 @@ h1#agenda-title { |
3603 | 3609 | border: 1px solid #2A5896; |
3604 | 3610 | padding: 10px 0px 10px 10px; |
3605 | 3611 | height: 205px; |
3606 | - overflow: auto; | |
3607 | 3612 | position: relative; /* work-arround-bug fo MSIE */ |
3608 | 3613 | } |
3609 | 3614 | |
... | ... | @@ -3630,6 +3635,7 @@ h1#agenda-title { |
3630 | 3635 | .controller-search .only-one-result-box .search-results-innerbox, |
3631 | 3636 | .controller-search .only-one-result-box .search-results-innerbox.common-profile-list-block { |
3632 | 3637 | height: auto; |
3638 | + float: left; | |
3633 | 3639 | padding: 10px 4px 10px 10px; |
3634 | 3640 | } |
3635 | 3641 | |
... | ... | @@ -4088,3 +4094,100 @@ h1#agenda-title { |
4088 | 4094 | .categories-block .ui-icon { |
4089 | 4095 | margin-top: 2px; |
4090 | 4096 | } |
4097 | + | |
4098 | +/* Profile balloon */ | |
4099 | + | |
4100 | +.common-profile-list-block .vcard { | |
4101 | + position: relative !important; | |
4102 | + float: left; | |
4103 | +} | |
4104 | + | |
4105 | +.common-profile-list-block .vcard .menu-submenu-trigger, | |
4106 | +.menu-submenu-trigger { | |
4107 | + display: none; | |
4108 | + width: 16px; | |
4109 | + height: 16px; | |
4110 | + position: absolute; | |
4111 | + top: -1px; | |
4112 | + left: -3px; | |
4113 | + overflow: hidden; | |
4114 | + background: #efefef url(/images/top-arrow.png) center center no-repeat; | |
4115 | + border: 1px solid #ccc; | |
4116 | + z-index: 2; | |
4117 | + -moz-border-radius: 5px; | |
4118 | + -webkit-border-radius: 5px; | |
4119 | +} | |
4120 | + | |
4121 | +.common-profile-list-block .vcard .menu-submenu-trigger:hover, | |
4122 | +.menu-submenu-trigger:hover { | |
4123 | + background: #fff url(/images/top-arrow.png) center center no-repeat; | |
4124 | + border: 1px solid #ccc; | |
4125 | +} | |
4126 | + | |
4127 | +.menu-submenu-trigger span { | |
4128 | + display: none; | |
4129 | +} | |
4130 | + | |
4131 | +.common-profile-list-block .vcard:hover .menu-submenu-trigger { | |
4132 | + display: block; | |
4133 | +} | |
4134 | + | |
4135 | +.menu-submenu { | |
4136 | + position: absolute; | |
4137 | + bottom: 115px; | |
4138 | + right: -27px; | |
4139 | + z-index: 11; | |
4140 | + width: 150px; | |
4141 | + padding: 0; | |
4142 | + text-align: left; | |
4143 | +} | |
4144 | + | |
4145 | +.menu-submenu-footer { | |
4146 | + background: transparent url(/images/balloon-footer.png) center center no-repeat; | |
4147 | + height: 29px; | |
4148 | + margin: 0; | |
4149 | +} | |
4150 | + | |
4151 | +.menu-submenu-header { | |
4152 | + background: transparent url(/images/balloon-header.png) center center no-repeat; | |
4153 | + height: 17px; | |
4154 | + margin: 0; | |
4155 | +} | |
4156 | + | |
4157 | +.menu-submenu-content { | |
4158 | + background: transparent url(/images/balloon-middle.png) top left repeat-y; | |
4159 | + margin: 0; | |
4160 | + padding: 0; | |
4161 | + width: 100%; | |
4162 | +} | |
4163 | + | |
4164 | +#content .menu-submenu-content ul { | |
4165 | + margin: 0; | |
4166 | + padding: 0; | |
4167 | + width: 100% !important; | |
4168 | + min-width: 100% !important; | |
4169 | +} | |
4170 | + | |
4171 | +#content .menu-submenu-content ul a { | |
4172 | + text-align: left; | |
4173 | + padding-left: 12px; | |
4174 | +} | |
4175 | + | |
4176 | +.common-profile-list-block .vcard .menu-submenu a { | |
4177 | + float: none; | |
4178 | + display: block; | |
4179 | + height: auto; | |
4180 | + font-size: 12px; | |
4181 | +} | |
4182 | + | |
4183 | +#content .menu-submenu h4 { | |
4184 | + margin: 0; | |
4185 | + font-size: 12px; | |
4186 | + font-weight: bold; | |
4187 | + text-align: left; | |
4188 | + margin: 0 auto; | |
4189 | + padding-bottom: 3px; | |
4190 | + margin-bottom: 3px; | |
4191 | + border-bottom: 1px solid #000; | |
4192 | + width: 90%; | |
4193 | +} | ... | ... |
... | ... | @@ -0,0 +1,221 @@ |
1 | +require File.dirname(__FILE__) + '/../test_helper' | |
2 | +require 'browse_controller' | |
3 | + | |
4 | +# Re-raise errors caught by the controller. | |
5 | +class BrowseController; def rescue_action(e) raise e end; end | |
6 | + | |
7 | +class BrowseControllerTest < Test::Unit::TestCase | |
8 | + | |
9 | + def setup | |
10 | + @controller = BrowseController.new | |
11 | + @request = ActionController::TestRequest.new | |
12 | + @request.stubs(:ssl?).returns(false) | |
13 | + @response = ActionController::TestResponse.new | |
14 | + | |
15 | + # By pass user validation on person creation | |
16 | + user = mock() | |
17 | + user.stubs(:id).returns(1) | |
18 | + user.stubs(:valid?).returns(true) | |
19 | + user.stubs(:email).returns('some@test.com') | |
20 | + user.stubs(:save!).returns(true) | |
21 | + Person.any_instance.stubs(:user).returns(user) | |
22 | + end | |
23 | + | |
24 | + should 'search for people' do | |
25 | + Person.delete_all | |
26 | + small = create(Person, :name => 'A small person for testing', :user_id => 1) | |
27 | + create(Person, :name => 'A big person for testing', :user_id => 2) | |
28 | + | |
29 | + get :people, :query => 'small' | |
30 | + assert_equal [small], assigns(:results) | |
31 | + end | |
32 | + | |
33 | + should 'list all people order by more recent one by default' do | |
34 | + Person.delete_all | |
35 | + p1 = create(Person, :name => 'Testing person 1', :user_id => 1, :created_at => DateTime.now - 2) | |
36 | + p2 = create(Person, :name => 'Testing person 2', :user_id => 2, :created_at => DateTime.now - 1) | |
37 | + p3 = create(Person, :name => 'Testing person 3', :user_id => 3) | |
38 | + | |
39 | + get :people | |
40 | + assert_equal [p3,p2,p1] , assigns(:results) | |
41 | + end | |
42 | + | |
43 | + should 'paginate search of people in groups of 27' do | |
44 | + Person.delete_all | |
45 | + | |
46 | + 1.upto(30).map do |n| | |
47 | + create(Person, :name => 'Testing person', :user_id => n) | |
48 | + end | |
49 | + | |
50 | + get :people | |
51 | + assert_equal 30 , Person.count | |
52 | + assert_equal 27 , assigns(:results).count | |
53 | + assert_tag :a, '', :attributes => {:class => 'next_page'} | |
54 | + end | |
55 | + | |
56 | + should 'paginate ferret search of people in groups of 27' do | |
57 | + Person.delete_all | |
58 | + | |
59 | + 1.upto(30).map do |n| | |
60 | + create(Person, :name => 'Testing person', :user_id => n) | |
61 | + end | |
62 | + | |
63 | + get :people, :query => 'Testing' | |
64 | + assert_equal 27 , assigns(:results).count | |
65 | + assert_tag :a, '', :attributes => {:class => 'next_page'} | |
66 | + end | |
67 | + | |
68 | + should 'list all people filter by more active' do | |
69 | + Person.delete_all | |
70 | + p1 = create(Person, :name => 'Testing person 1', :user_id => 1) | |
71 | + p2 = create(Person, :name => 'Testing person 2', :user_id => 2) | |
72 | + p3 = create(Person, :name => 'Testing person 3', :user_id => 3) | |
73 | + Article.delete_all | |
74 | + fast_create(Article, :profile_id => p1, :created_at => 1.day.ago) | |
75 | + fast_create(Article, :profile_id => p2, :created_at => DateTime.now.beginning_of_day) | |
76 | + get :people, :filter => 'more_active' | |
77 | + assert_equal [p1,p2] , assigns(:results) | |
78 | + end | |
79 | + | |
80 | + should 'filter more popular people' do | |
81 | + Person.delete_all | |
82 | + p1 = create(Person, :name => 'Testing person 1', :user_id => 1) | |
83 | + p2 = create(Person, :name => 'Testing person 2', :user_id => 2) | |
84 | + p3 = create(Person, :name => 'Testing person 3', :user_id => 3) | |
85 | + | |
86 | + p1.add_friend(p2) | |
87 | + p2.add_friend(p1) | |
88 | + p2.add_friend(p3) | |
89 | + get :people, :filter => 'more_popular' | |
90 | + assert_equal [p2,p1] , assigns(:results) | |
91 | + end | |
92 | + | |
93 | + should 'the people filter be only the hardcoded one' do | |
94 | + get :people, :filter => 'more_recent' | |
95 | + assert_equal 'more_recent' , assigns(:filter) | |
96 | + | |
97 | + get :people, :filter => 'more_active' | |
98 | + assert_equal 'more_active' , assigns(:filter) | |
99 | + | |
100 | + get :people, :filter => 'more_popular' | |
101 | + assert_equal 'more_popular' , assigns(:filter) | |
102 | + | |
103 | + get :people, :filter => 'more_anything' | |
104 | + assert_equal 'more_recent' , assigns(:filter) | |
105 | + end | |
106 | + | |
107 | + should 'the people filter define the title' do | |
108 | + get :people, :filter => 'more_recent' | |
109 | + assert_equal 'People more recent' , assigns(:title) | |
110 | + assert_tag :h1, :content => 'People more recent' | |
111 | + | |
112 | + get :people, :filter => 'more_active' | |
113 | + assert_equal 'People more active' , assigns(:title) | |
114 | + assert_tag :h1, :content => 'People more active' | |
115 | + | |
116 | + get :people, :filter => 'more_popular' | |
117 | + assert_equal 'People more popular' , assigns(:title) | |
118 | + assert_tag :h1, :content => 'People more popular' | |
119 | + | |
120 | + get :people, :filter => 'more_anything' | |
121 | + assert_equal 'People more recent' , assigns(:title) | |
122 | + assert_tag :h1, :content => 'People more recent' | |
123 | + end | |
124 | + | |
125 | + should 'search for community' do | |
126 | + small = create(Community, :name => 'A small community for testing') | |
127 | + create(Community, :name => 'A big community for testing') | |
128 | + | |
129 | + get :communities, :query => 'small' | |
130 | + assert_equal [small], assigns(:results) | |
131 | + end | |
132 | + | |
133 | + should 'list all community order by more recent one by default' do | |
134 | + c1 = create(Community, :name => 'Testing community 1', :created_at => DateTime.now - 2) | |
135 | + c2 = create(Community, :name => 'Testing community 2', :created_at => DateTime.now - 1) | |
136 | + c3 = create(Community, :name => 'Testing community 3') | |
137 | + | |
138 | + get :communities | |
139 | + assert_equal [c3,c2,c1] , assigns(:results) | |
140 | + end | |
141 | + | |
142 | + should 'paginate search of communities in groups of 27' do | |
143 | + 1.upto(30).map do |n| | |
144 | + create(Community, :name => 'Testing community') | |
145 | + end | |
146 | + | |
147 | + get :communities | |
148 | + assert_equal 30 , Community.count | |
149 | + assert_equal 27 , assigns(:results).count | |
150 | + assert_tag :a, '', :attributes => {:class => 'next_page'} | |
151 | + end | |
152 | + | |
153 | + should 'paginate ferret search of communities in groups of 27' do | |
154 | + 1.upto(30).map do |n| | |
155 | + create(Community, :name => 'Testing community') | |
156 | + end | |
157 | + | |
158 | + get :communities, :query => 'Testing' | |
159 | + assert_equal 27 , assigns(:results).count | |
160 | + assert_tag :a, '', :attributes => {:class => 'next_page'} | |
161 | + end | |
162 | + | |
163 | + should 'list all communities filter by more active' do | |
164 | + c1 = create(Community, :name => 'Testing community 1') | |
165 | + c2 = create(Community, :name => 'Testing community 2') | |
166 | + c3 = create(Community, :name => 'Testing community 3') | |
167 | + Article.delete_all | |
168 | + fast_create(Article, :profile_id => c1, :created_at => 1.day.ago) | |
169 | + fast_create(Article, :profile_id => c2, :created_at => DateTime.now.beginning_of_day) | |
170 | + get :communities, :filter => 'more_active' | |
171 | + assert_equal [c1,c2] , assigns(:results) | |
172 | + end | |
173 | + | |
174 | + should 'filter more popular communities' do | |
175 | + Person.delete_all | |
176 | + c1 = create(Community, :name => 'Testing community 1') | |
177 | + c2 = create(Community, :name => 'Testing community 2') | |
178 | + create(Community, :name => 'Testing community 3') | |
179 | + | |
180 | + p1 = create(Person, :name => 'Testing person 1', :user_id => 1) | |
181 | + p2 = create(Person, :name => 'Testing person 2', :user_id => 2) | |
182 | + c1.add_member(p1) | |
183 | + c2.add_member(p1) | |
184 | + c2.add_member(p2) | |
185 | + get :communities, :filter => 'more_popular' | |
186 | + assert_equal [c2,c1] , assigns(:results) | |
187 | + end | |
188 | + | |
189 | + should 'the communities filter be only the hardcoded one' do | |
190 | + get :communities, :filter => 'more_recent' | |
191 | + assert_equal 'more_recent' , assigns(:filter) | |
192 | + | |
193 | + get :communities, :filter => 'more_active' | |
194 | + assert_equal 'more_active' , assigns(:filter) | |
195 | + | |
196 | + get :communities, :filter => 'more_popular' | |
197 | + assert_equal 'more_popular' , assigns(:filter) | |
198 | + | |
199 | + get :communities, :filter => 'more_anything' | |
200 | + assert_equal 'more_recent' , assigns(:filter) | |
201 | + end | |
202 | + | |
203 | + should 'the communities filter define the title' do | |
204 | + get :communities, :filter => 'more_recent' | |
205 | + assert_equal 'Communities more recent' , assigns(:title) | |
206 | + assert_tag :h1, :content => 'Communities more recent' | |
207 | + | |
208 | + get :communities, :filter => 'more_active' | |
209 | + assert_equal 'Communities more active' , assigns(:title) | |
210 | + assert_tag :h1, :content => 'Communities more active' | |
211 | + | |
212 | + get :communities, :filter => 'more_popular' | |
213 | + assert_equal 'Communities more popular' , assigns(:title) | |
214 | + assert_tag :h1, :content => 'Communities more popular' | |
215 | + | |
216 | + get :communities, :filter => 'more_anything' | |
217 | + assert_equal 'Communities more recent' , assigns(:title) | |
218 | + assert_tag :h1, :content => 'Communities more recent' | |
219 | + end | |
220 | + | |
221 | +end | ... | ... |
test/integration/routing_test.rb
... | ... | @@ -216,4 +216,11 @@ class RoutingTest < ActionController::IntegrationTest |
216 | 216 | assert_routing('/doc', :controller => 'doc', :action => 'index') |
217 | 217 | end |
218 | 218 | |
219 | + # browse controller | |
220 | + def test_browse_routing | |
221 | + assert_routing('/browse/people', :controller => 'browse', :action => 'people') | |
222 | + assert_routing('/browse/people/more_popular', :controller => 'browse', :action => 'people', :filter => 'more_popular') | |
223 | + assert_routing('/browse/communities', :controller => 'browse', :action => 'communities') | |
224 | + assert_routing('/browse/communities/more_active', :controller => 'browse', :action => 'communities', :filter => 'more_active') | |
225 | + end | |
219 | 226 | end | ... | ... |
test/unit/application_helper_test.rb
... | ... | @@ -567,6 +567,60 @@ class ApplicationHelperTest < Test::Unit::TestCase |
567 | 567 | assert_equal environment.theme, current_theme |
568 | 568 | end |
569 | 569 | |
570 | + should 'trunc to 15 chars the big filename' do | |
571 | + assert_equal 'AGENDA(...).mp3', short_filename('AGENDA_CULTURA_-_FESTA_DE_VAQUEIROS_PONTO_DE_SERRA_PRETA_BAIXA.mp3',15) | |
572 | + end | |
573 | + | |
574 | + should 'trunc to default limit the big filename' do | |
575 | + assert_equal 'AGENDA_CULTURA_-_FESTA_DE_VAQUEIRO(...).mp3', short_filename('AGENDA_CULTURA_-_FESTA_DE_VAQUEIROS_PONTO_DE_SERRA_PRETA_BAIXA.mp3') | |
576 | + end | |
577 | + | |
578 | + should 'does not trunc short filename' do | |
579 | + assert_equal 'filename.mp3', short_filename('filename.mp3') | |
580 | + end | |
581 | + | |
582 | + should 'return nil when :show_balloon_with_profile_links_when_clicked is not enabled in environment' do | |
583 | + env = Environment.default | |
584 | + env.stubs(:enabled?).with(:show_balloon_with_profile_links_when_clicked).returns(false) | |
585 | + stubs(:environment).returns(env) | |
586 | + profile = Profile.new | |
587 | + assert_nil links_for_balloon(profile) | |
588 | + end | |
589 | + | |
590 | + should 'return ordered list of links to balloon to Person' do | |
591 | + env = Environment.default | |
592 | + env.stubs(:enabled?).with(:show_balloon_with_profile_links_when_clicked).returns(true) | |
593 | + stubs(:environment).returns(env) | |
594 | + person = Person.new | |
595 | + person.stubs(:url).returns('url for person') | |
596 | + person.stubs(:public_profile_url).returns('url for person') | |
597 | + links = links_for_balloon(person) | |
598 | + assert_equal ['Home Page', 'Profile', 'Friends', 'Communities'], links.map{|i| i.keys.first} | |
599 | + end | |
600 | + | |
601 | + should 'return ordered list of links to balloon to Community' do | |
602 | + env = Environment.default | |
603 | + env.stubs(:enabled?).with(:show_balloon_with_profile_links_when_clicked).returns(true) | |
604 | + stubs(:environment).returns(env) | |
605 | + community = Community.new | |
606 | + community.stubs(:url).returns('url for community') | |
607 | + community.stubs(:public_profile_url).returns('url for community') | |
608 | + links = links_for_balloon(community) | |
609 | + assert_equal ['Home Page', 'Profile', 'Members', 'Agenda'], links.map{|i| i.keys.first} | |
610 | + end | |
611 | + | |
612 | + should 'return ordered list of links to balloon to Enterprise' do | |
613 | + env = Environment.default | |
614 | + env.stubs(:enabled?).with(:show_balloon_with_profile_links_when_clicked).returns(true) | |
615 | + stubs(:environment).returns(env) | |
616 | + enterprise = Enterprise.new | |
617 | + enterprise.stubs(:url).returns('url for enterprise') | |
618 | + enterprise.stubs(:public_profile_url).returns('url for enterprise') | |
619 | + stubs(:catalog_path) | |
620 | + links = links_for_balloon(enterprise) | |
621 | + assert_equal ['Home Page', 'Products', 'Members', 'Agenda'], links.map{|i| i.keys.first} | |
622 | + end | |
623 | + | |
570 | 624 | protected |
571 | 625 | |
572 | 626 | def url_for(args = {}) | ... | ... |
test/unit/person_test.rb
... | ... | @@ -588,4 +588,51 @@ class PersonTest < Test::Unit::TestCase |
588 | 588 | end |
589 | 589 | end |
590 | 590 | |
591 | + should "return none on label if the person hasn't friends" do | |
592 | + p = fast_create(Person) | |
593 | + assert_equal 0, p.friends.count | |
594 | + assert_equal "none", p.more_popular_label | |
595 | + end | |
596 | + | |
597 | + should "return one friend on label if the profile has one member" do | |
598 | + p1 = fast_create(Person) | |
599 | + p2 = fast_create(Person) | |
600 | + p1.add_friend(p2) | |
601 | + assert_equal 1, p1.friends.count | |
602 | + assert_equal "one friend", p1.more_popular_label | |
603 | + end | |
604 | + | |
605 | + should "return the number of friends on label if the person has more than one friend" do | |
606 | + p1 = fast_create(Person) | |
607 | + p2 = fast_create(Person) | |
608 | + p3 = fast_create(Person) | |
609 | + p1.add_friend(p2) | |
610 | + p1.add_friend(p3) | |
611 | + assert_equal 2, p1.friends.count | |
612 | + assert_equal "2 friends", p1.more_popular_label | |
613 | + | |
614 | + p4 = fast_create(Person) | |
615 | + p1.add_friend(p4) | |
616 | + assert_equal 3, p1.friends.count | |
617 | + assert_equal "3 friends", p1.more_popular_label | |
618 | + end | |
619 | + | |
620 | + should 'find more popular people' do | |
621 | + Person.delete_all | |
622 | + env = fast_create(Environment) | |
623 | + p1 = fast_create(Person) | |
624 | + p2 = fast_create(Person) | |
625 | + p3 = fast_create(Person) | |
626 | + | |
627 | + p1.add_friend(p2) | |
628 | + assert_equal [p1], Person.more_popular | |
629 | + | |
630 | + p2.add_friend(p1) | |
631 | + p2.add_friend(p3) | |
632 | + assert_equal [p2,p1] , Person.more_popular | |
633 | + | |
634 | + p2.remove_friend(p3) | |
635 | + assert_equal [p1,p2] , Person.more_popular | |
636 | + end | |
637 | + | |
591 | 638 | end | ... | ... |
test/unit/profile_test.rb
... | ... | @@ -1563,6 +1563,212 @@ class ProfileTest < Test::Unit::TestCase |
1563 | 1563 | assert_match /<!-- .* --> <h1> Wellformed html code <\/h1>/, profile.custom_footer |
1564 | 1564 | end |
1565 | 1565 | |
1566 | + should 'find more recent people' do | |
1567 | + Person.delete_all | |
1568 | + p1 = fast_create(Person,:created_at => 4.days.ago) | |
1569 | + p2 = fast_create(Person, :created_at => DateTime.now) | |
1570 | + p3 = fast_create(Person, :created_at => 2.days.ago) | |
1571 | + | |
1572 | + assert_equal [p2,p3,p1] , Person.more_recent | |
1573 | + | |
1574 | + p4 = fast_create(Person, :created_at => 3.days.ago) | |
1575 | + assert_equal [p2,p3,p4,p1] , Person.more_recent | |
1576 | + end | |
1577 | + | |
1578 | + should 'find more active people' do | |
1579 | + Person.delete_all | |
1580 | + p1 = fast_create(Person) | |
1581 | + p2 = fast_create(Person) | |
1582 | + p3 = fast_create(Person) | |
1583 | + Article.delete_all | |
1584 | + fast_create(Article, :profile_id => p1, :created_at => 7.days.ago) | |
1585 | + fast_create(Article, :profile_id => p1, :created_at => DateTime.now.beginning_of_day) | |
1586 | + fast_create(Article, :profile_id => p2, :created_at => DateTime.now.beginning_of_day) | |
1587 | + assert_equal [p1,p2] , Person.more_active | |
1588 | + | |
1589 | + fast_create(Article, :profile_id => p2, :created_at => 1.day.ago) | |
1590 | + fast_create(Article, :profile_id => p2, :created_at => 5.days.ago) | |
1591 | + fast_create(Article, :profile_id => p3, :created_at => 2.days.ago) | |
1592 | + assert_equal [p2,p1,p3] , Person.more_active | |
1593 | + end | |
1594 | + | |
1595 | + should 'the ties on more active people be solved by the number of comments' do | |
1596 | + Person.delete_all | |
1597 | + p1 = fast_create(Person) | |
1598 | + p2 = fast_create(Person) | |
1599 | + Article.delete_all | |
1600 | + a1 = fast_create(Article, :profile_id => p1, :created_at => DateTime.now.beginning_of_day) | |
1601 | + a2 = fast_create(Article, :profile_id => p2, :created_at => DateTime.now.beginning_of_day) | |
1602 | + assert_equal [], [p1,p2] - Person.more_active | |
1603 | + assert_equal [], Person.more_active - [p1, p2] | |
1604 | + | |
1605 | + a2.comments.build(:title => 'test comment', :body => 'anything', :author => p1).save! | |
1606 | + assert_equal [p2,p1] , Person.more_active | |
1607 | + | |
1608 | + a1.comments.build(:title => 'test comment', :body => 'anything', :author => p2).save! | |
1609 | + a1.comments.build(:title => 'test comment', :body => 'anything', :author => p2).save! | |
1610 | + assert_equal [p1,p2] , Person.more_active | |
1611 | + end | |
1612 | + | |
1613 | + should 'more active people take in consideration only articles created current the last week' do | |
1614 | + Person.delete_all | |
1615 | + env = fast_create(Environment) | |
1616 | + p1 = fast_create(Person) | |
1617 | + p2 = fast_create(Person) | |
1618 | + p3 = fast_create(Person) | |
1619 | + Article.delete_all | |
1620 | + fast_create(Article, :profile_id => p1, :created_at => DateTime.now.beginning_of_day) | |
1621 | + fast_create(Article, :profile_id => p2, :created_at => 10.days.ago) | |
1622 | + assert_equal [p1] , Person.more_active | |
1623 | + | |
1624 | + fast_create(Article, :profile_id => p2, :created_at => DateTime.now.beginning_of_day) | |
1625 | + fast_create(Article, :profile_id => p2, :created_at => 7.days.ago) | |
1626 | + fast_create(Article, :profile_id => p3, :created_at => 8.days.ago) | |
1627 | + assert_equal [p2,p1] , Person.more_active | |
1628 | + end | |
1629 | + | |
1630 | + should 'find more recent community' do | |
1631 | + c1 = fast_create(Community, :created_at => 3.days.ago) | |
1632 | + c2 = fast_create(Community, :created_at => 1.day.ago) | |
1633 | + c3 = fast_create(Community, :created_at => DateTime.now) | |
1634 | + | |
1635 | + assert_equal [c3,c2,c1] , Community.more_recent | |
1636 | + | |
1637 | + c4 = fast_create(Community, :created_at => 2.days.ago) | |
1638 | + assert_equal [c3,c2,c4,c1] , Community.more_recent | |
1639 | + end | |
1640 | + | |
1641 | + should 'find more active community' do | |
1642 | + c1 = fast_create(Community) | |
1643 | + c2 = fast_create(Community) | |
1644 | + c3 = fast_create(Community) | |
1645 | + | |
1646 | + Article.delete_all | |
1647 | + fast_create(Article, :profile_id => c1, :created_at => 1.day.ago) | |
1648 | + fast_create(Article, :profile_id => c1, :created_at => DateTime.now.beginning_of_day) | |
1649 | + fast_create(Article, :profile_id => c2, :created_at => DateTime.now.beginning_of_day) | |
1650 | + assert_equal [c1,c2], Community.more_active | |
1651 | + | |
1652 | + fast_create(Article, :profile_id => c2, :created_at => 2.days.ago) | |
1653 | + fast_create(Article, :profile_id => c2, :created_at => 7.days.ago) | |
1654 | + fast_create(Article, :profile_id => c3, :created_at => 1.day.ago) | |
1655 | + assert_equal [c2,c1,c3] , Community.more_active | |
1656 | + end | |
1657 | + | |
1658 | + should 'the ties on more active communities be solved by the number of comments' do | |
1659 | + env = create(Environment) | |
1660 | + Community.delete_all | |
1661 | + c1 = fast_create(Community) | |
1662 | + c2 = fast_create(Community) | |
1663 | + Article.delete_all | |
1664 | + a1 = fast_create(Article, :profile_id => c1, :created_at => DateTime.now.beginning_of_day) | |
1665 | + a2 = fast_create(Article, :profile_id => c2, :created_at => DateTime.now.beginning_of_day) | |
1666 | + assert_equal [c1,c2] , Community.more_active | |
1667 | + | |
1668 | + p1 = fast_create(Person) | |
1669 | + a2.comments.build(:title => 'test comment', :body => 'anything', :author => p1).save! | |
1670 | + assert_equal [c2,c1] , Community.more_active | |
1671 | + | |
1672 | + a1.comments.build(:title => 'test comment', :body => 'anything', :author => p1).save! | |
1673 | + a1.comments.build(:title => 'test comment', :body => 'anything', :author => p1).save! | |
1674 | + assert_equal [c1,c2] , Community.more_active | |
1675 | + end | |
1676 | + | |
1677 | + should 'more active communities take in consideration only articles created current the last week' do | |
1678 | + c1 = fast_create(Community) | |
1679 | + c2 = fast_create(Community) | |
1680 | + c3 = fast_create(Community) | |
1681 | + Article.delete_all | |
1682 | + fast_create(Article, :profile_id => c1, :created_at => DateTime.now.beginning_of_day) | |
1683 | + fast_create(Article, :profile_id => c2, :created_at => 10.days.ago) | |
1684 | + assert_equal [c1] , Community.more_active | |
1685 | + | |
1686 | + fast_create(Article, :profile_id => c2, :created_at => DateTime.now.beginning_of_day) | |
1687 | + fast_create(Article, :profile_id => c2, :created_at => 7.days.ago) | |
1688 | + fast_create(Article, :profile_id => c3, :created_at => 8.days.ago) | |
1689 | + assert_equal [c2,c1] , Community.more_active | |
1690 | + end | |
1691 | + | |
1692 | + should 'find more popular communities' do | |
1693 | + Community.delete_all | |
1694 | + | |
1695 | + c1 = fast_create(Community) | |
1696 | + c2 = fast_create(Community) | |
1697 | + fast_create(Community) | |
1698 | + | |
1699 | + p1 = fast_create(Person) | |
1700 | + p2 = fast_create(Person) | |
1701 | + c1.add_member(p1) | |
1702 | + assert_equal [c1] , Community.more_popular | |
1703 | + | |
1704 | + c2.add_member(p1) | |
1705 | + c2.add_member(p2) | |
1706 | + assert_equal [c2,c1] , Community.more_popular | |
1707 | + | |
1708 | + c2.remove_member(p2) | |
1709 | + c2.remove_member(p1) | |
1710 | + assert_equal [c1] , Community.more_popular | |
1711 | + end | |
1712 | + | |
1713 | + should "return the more recent label" do | |
1714 | + p = fast_create(Profile) | |
1715 | + assert_equal "Since: ", p.more_recent_label | |
1716 | + end | |
1717 | + | |
1718 | + should "return none on label if the profile hasn't articles" do | |
1719 | + p = fast_create(Profile) | |
1720 | + assert_equal 0, p.articles.count | |
1721 | + assert_equal "none", p.more_active_label | |
1722 | + end | |
1723 | + | |
1724 | + should "return one article on label if the profile has one article" do | |
1725 | + p = fast_create(Profile) | |
1726 | + fast_create(Article, :profile_id => p.id) | |
1727 | + assert_equal 1, p.articles.count | |
1728 | + assert_equal "one article", p.more_active_label | |
1729 | + end | |
1730 | + | |
1731 | + should "return number of artciles on label if the profile has more than one article" do | |
1732 | + p = fast_create(Profile) | |
1733 | + fast_create(Article, :profile_id => p.id) | |
1734 | + fast_create(Article, :profile_id => p.id) | |
1735 | + assert_equal 2, p.articles.count | |
1736 | + assert_equal "2 articles", p.more_active_label | |
1737 | + | |
1738 | + fast_create(Article, :profile_id => p.id) | |
1739 | + assert_equal 3, p.articles.count | |
1740 | + assert_equal "3 articles", p.more_active_label | |
1741 | + end | |
1742 | + | |
1743 | + should "return none on label if the profile hasn't members" do | |
1744 | + p = fast_create(Profile) | |
1745 | + assert_equal 0, p.members.count | |
1746 | + assert_equal "none", p.more_popular_label | |
1747 | + end | |
1748 | + | |
1749 | + should "return one member on label if the profile has one member" do | |
1750 | + p = fast_create(Person) | |
1751 | + c = fast_create(Community) | |
1752 | + c.add_member(p) | |
1753 | + assert_equal 1, c.members.count | |
1754 | + assert_equal "one member", c.more_popular_label | |
1755 | + end | |
1756 | + | |
1757 | + should "return the number of members on label if the profile has more than one member" do | |
1758 | + p1 = fast_create(Profile) | |
1759 | + p2 = fast_create(Person) | |
1760 | + c = fast_create(Community) | |
1761 | + c.add_member(p1) | |
1762 | + c.add_member(p2) | |
1763 | + assert_equal 2, c.members.count | |
1764 | + assert_equal "2 members", c.more_popular_label | |
1765 | + | |
1766 | + p3 = fast_create(Person) | |
1767 | + c.add_member(p3) | |
1768 | + assert_equal 3, c.members.count | |
1769 | + assert_equal "3 members", c.more_popular_label | |
1770 | + end | |
1771 | + | |
1566 | 1772 | private |
1567 | 1773 | |
1568 | 1774 | def assert_invalid_identifier(id) | ... | ... |