Commit 9103171c933a3a92834ea3c48802ed5bd344baf1
Exists in
master
and in
29 other branches
Merge branch 'solr-searches' of https://github.com/coletivoEITA/noosfero-ecosol into ecosol-solr
Conflicts: app/models/enterprise.rb
Showing
444 changed files
with
120699 additions
and
14351 deletions
Show diff stats
Too many changes.
To preserve performance only 100 of 444 files displayed.
HACKING
... | ... | @@ -40,6 +40,8 @@ commands and make sure you understand what you are doing): |
40 | 40 | cp config/database.yml.sqlite3 config/database.yml |
41 | 41 | # create tmp directory if it doesn't exist |
42 | 42 | mkdir tmp |
43 | + # start Solr | |
44 | + rake solr:start | |
43 | 45 | # create the development database |
44 | 46 | rake db:schema:load |
45 | 47 | # run pending migrations | ... | ... |
INSTALL
... | ... | @@ -13,7 +13,7 @@ You need to install some packages Noosfero depends on. On Debian GNU/Linux or |
13 | 13 | Debian-based systems, all of these packages are available through the Debian |
14 | 14 | archive. You can install them with the following command: |
15 | 15 | |
16 | - # apt-get install ruby rake po4a libgettext-ruby-util libgettext-ruby-data libgettext-ruby1.8 libsqlite3-ruby rcov librmagick-ruby libredcloth-ruby libwill-paginate-ruby iso-codes libfeedparser-ruby libferret-ruby libdaemons-ruby thin tango-icon-theme libhpricot-ruby | |
16 | + # apt-get install ruby rake po4a libgettext-ruby-util libgettext-ruby-data libgettext-ruby1.8 libsqlite3-ruby rcov librmagick-ruby libredcloth-ruby libwill-paginate-ruby iso-codes libfeedparser-ruby openjdk-6-jre libdaemons-ruby thin tango-icon-theme libhpricot-ruby | |
17 | 17 | |
18 | 18 | On other systems, they may or may not be available through your regular package |
19 | 19 | management system. Below are the links to their homepages. |
... | ... | @@ -24,7 +24,7 @@ management system. Below are the links to their homepages. |
24 | 24 | * Ruby-GetText: http://www.yotabanana.com/hiki/ruby-gettext.html?ruby-gettext (at least version 1.9.0) |
25 | 25 | * Ruby-sqlite3: http://rubyforge.org/projects/sqlite-ruby |
26 | 26 | * rcov: http://eigenclass.org/hiki/rcov |
27 | -* Ferret: http://ferret.davebalmain.com/trac | |
27 | +* Solr: http://lucene.apache.org/solr | |
28 | 28 | * RMagick: http://rmagick.rubyforge.org/ |
29 | 29 | * RedCloth: http://redcloth.org/ |
30 | 30 | * will_paginate: http://github.com/mislav/will_paginate/wikis |
... | ... | @@ -115,7 +115,7 @@ $ tar -zxvf noosfero-0.27.1.tar.gz |
115 | 115 | $ ln -s noosfero-0.27.1 current |
116 | 116 | $ cd current |
117 | 117 | |
118 | -Copy config/ferret_server.yml.dist to config/ferret_server.yml. You will | |
118 | +Copy config/solr.yml.dist to config/solr.yml. You will | |
119 | 119 | probably not need to customize this configuration, but have a look at it. |
120 | 120 | |
121 | 121 | Create the thin configuration file: |
... | ... | @@ -241,6 +241,10 @@ Compile the translations: |
241 | 241 | |
242 | 242 | $ RAILS_ENV=production rake noosfero:translations:compile |
243 | 243 | |
244 | +Run Solr: | |
245 | + | |
246 | +$ rake solr:start | |
247 | + | |
244 | 248 | Now we have to create some initial data. To create your default environment |
245 | 249 | (the first one), run the command below: |
246 | 250 | ... | ... |
Rakefile
app/controllers/application.rb
1 | 1 | require 'application_controller' |
2 | + | |
3 | +# his is the application's main controller. Features defined here are | |
4 | +# available in all controllers. | |
5 | +class ApplicationController < ActionController::Base | |
6 | + | |
7 | + before_filter :change_pg_schema | |
8 | + | |
9 | + include ApplicationHelper | |
10 | + layout :get_layout | |
11 | + def get_layout | |
12 | + prepend_view_path('public/' + theme_path) | |
13 | + theme_option(:layout) || 'application' | |
14 | + end | |
15 | + | |
16 | + filter_parameter_logging :password | |
17 | + | |
18 | + def log_processing | |
19 | + super | |
20 | + return unless ENV['RAILS_ENV'] == 'production' | |
21 | + if logger && logger.info? | |
22 | + logger.info(" HTTP Referer: #{request.referer}") | |
23 | + logger.info(" User Agent: #{request.user_agent}") | |
24 | + logger.info(" Accept-Language: #{request.headers['HTTP_ACCEPT_LANGUAGE']}") | |
25 | + end | |
26 | + end | |
27 | + | |
28 | + helper :document | |
29 | + helper :language | |
30 | + | |
31 | + def self.no_design_blocks | |
32 | + @no_design_blocks = true | |
33 | + end | |
34 | + def self.uses_design_blocks? | |
35 | + !@no_design_blocks | |
36 | + end | |
37 | + def uses_design_blocks? | |
38 | + !@no_design_blocks && self.class.uses_design_blocks? | |
39 | + end | |
40 | + | |
41 | + # Be sure to include AuthenticationSystem in Application Controller instead | |
42 | + include AuthenticatedSystem | |
43 | + include PermissionCheck | |
44 | + | |
45 | + def self.require_ssl(*options) | |
46 | + before_filter :check_ssl, *options | |
47 | + end | |
48 | + def check_ssl | |
49 | + return true if (request.ssl? || ENV['RAILS_ENV'] == 'development') | |
50 | + redirect_to_ssl | |
51 | + end | |
52 | + def redirect_to_ssl | |
53 | + if environment.enable_ssl | |
54 | + redirect_to(params.merge(:protocol => 'https://', :host => ssl_hostname)) | |
55 | + true | |
56 | + else | |
57 | + false | |
58 | + end | |
59 | + end | |
60 | + | |
61 | + def self.refuse_ssl(*options) | |
62 | + before_filter :avoid_ssl, *options | |
63 | + end | |
64 | + def avoid_ssl | |
65 | + if (!request.ssl? || ENV['RAILS_ENV'] == 'development') | |
66 | + true | |
67 | + else | |
68 | + redirect_to(params.merge(:protocol => 'http://')) | |
69 | + false | |
70 | + end | |
71 | + end | |
72 | + | |
73 | + before_filter :set_locale | |
74 | + def set_locale | |
75 | + FastGettext.available_locales = Noosfero.available_locales | |
76 | + FastGettext.default_locale = Noosfero.default_locale | |
77 | + FastGettext.set_locale(params[:lang] || session[:lang] || Noosfero.default_locale || request.env['HTTP_ACCEPT_LANGUAGE'] || 'en') | |
78 | + if params[:lang] | |
79 | + session[:lang] = params[:lang] | |
80 | + end | |
81 | + end | |
82 | + | |
83 | + include NeedsProfile | |
84 | + | |
85 | + before_filter :detect_stuff_by_domain | |
86 | + before_filter :init_noosfero_plugins | |
87 | + attr_reader :environment | |
88 | + | |
89 | + before_filter :load_terminology | |
90 | + | |
91 | + # declares that the given <tt>actions</tt> cannot be accessed by other HTTP | |
92 | + # method besides POST. | |
93 | + def self.post_only(actions, redirect = { :action => 'index'}) | |
94 | + verify :method => :post, :only => actions, :redirect_to => redirect | |
95 | + end | |
96 | + | |
97 | + helper_method :current_person, :current_person | |
98 | + | |
99 | + def change_pg_schema | |
100 | + if Noosfero::MultiTenancy.on? and ActiveRecord::Base.postgresql? | |
101 | + Noosfero::MultiTenancy.db_by_host = request.host | |
102 | + end | |
103 | + end | |
104 | + | |
105 | + protected | |
106 | + | |
107 | + def boxes_editor? | |
108 | + false | |
109 | + end | |
110 | + | |
111 | + def content_editor? | |
112 | + false | |
113 | + end | |
114 | + | |
115 | + def user | |
116 | + current_user.person if logged_in? | |
117 | + end | |
118 | + | |
119 | + alias :current_person :user | |
120 | + | |
121 | + # TODO: move this logic somewhere else (Domain class?) | |
122 | + def detect_stuff_by_domain | |
123 | + @domain = Domain.find_by_name(request.host) | |
124 | + if @domain.nil? | |
125 | + @environment = Environment.default | |
126 | + else | |
127 | + @environment = @domain.environment | |
128 | + @profile = @domain.profile | |
129 | + end | |
130 | + end | |
131 | + | |
132 | + def init_noosfero_plugins | |
133 | + @plugins = Noosfero::Plugin::Manager.new(self) | |
134 | + @plugins.enabled_plugins.map(&:class).each do |plugin| | |
135 | + prepend_view_path(plugin.view_path) | |
136 | + end | |
137 | + init_noosfero_plugins_controller_filters | |
138 | + end | |
139 | + | |
140 | + # This is a generic method that initialize any possible filter defined by a | |
141 | + # plugin to the current controller being initialized. | |
142 | + def init_noosfero_plugins_controller_filters | |
143 | + @plugins.enabled_plugins.each do |plugin| | |
144 | + plugin.send(self.class.name.underscore + '_filters').each do |plugin_filter| | |
145 | + self.class.send(plugin_filter[:type], plugin.class.name.underscore + '_' + plugin_filter[:method_name], (plugin_filter[:options] || {})) | |
146 | + self.class.send(:define_method, plugin.class.name.underscore + '_' + plugin_filter[:method_name], plugin_filter[:block]) | |
147 | + end | |
148 | + end | |
149 | + end | |
150 | + | |
151 | + def load_terminology | |
152 | + # cache terminology for performance | |
153 | + @@terminology_cache ||= {} | |
154 | + @@terminology_cache[environment.id] ||= environment.terminology | |
155 | + Noosfero.terminology = @@terminology_cache[environment.id] | |
156 | + end | |
157 | + | |
158 | + def render_not_found(path = nil) | |
159 | + @no_design_blocks = true | |
160 | + @path ||= request.path | |
161 | + render :template => 'shared/not_found.rhtml', :status => 404, :layout => get_layout | |
162 | + end | |
163 | + alias :render_404 :render_not_found | |
164 | + | |
165 | + def render_access_denied(message = nil, title = nil) | |
166 | + @no_design_blocks = true | |
167 | + @message = message | |
168 | + @title = title | |
169 | + render :template => 'shared/access_denied.rhtml', :status => 403 | |
170 | + end | |
171 | + | |
172 | +end | ... | ... |
app/controllers/my_profile/cms_controller.rb
... | ... | @@ -286,7 +286,7 @@ class CmsController < MyProfileController |
286 | 286 | |
287 | 287 | def search |
288 | 288 | query = params[:q] |
289 | - results = query.blank? ? [] : profile.articles.published.find_by_contents(query) | |
289 | + results = query.blank? ? [] : profile.articles.published.find_by_contents(query)[:results] | |
290 | 290 | render :text => article_list_to_json(results), :content_type => 'application/json' |
291 | 291 | end |
292 | 292 | def media_upload | ... | ... |
app/controllers/my_profile/maps_controller.rb
... | ... | @@ -6,16 +6,48 @@ class MapsController < MyProfileController |
6 | 6 | @profile_data = profile |
7 | 7 | if request.post? |
8 | 8 | begin |
9 | + country = params[:profile_data][:country] | |
10 | + city = params[:profile_data][:city] | |
11 | + state = params[:profile_data][:state] | |
12 | + nregion = NationalRegion.validate!(city, state, country) | |
13 | + unless nregion.blank? | |
14 | + params[:profile_data][:national_region_code] = nregion.national_region_code | |
15 | + end | |
16 | + | |
9 | 17 | Profile.transaction do |
10 | 18 | if profile.update_attributes!(params[:profile_data]) |
11 | 19 | session[:notice] = _('Address was updated successfully!') |
12 | 20 | redirect_to :action => 'edit_location' |
13 | 21 | end |
14 | 22 | end |
15 | - rescue | |
16 | - flash[:error] = _('Address could not be saved.') | |
23 | + rescue Exception => exc | |
24 | + flash[:error] = exc.message | |
17 | 25 | end |
18 | 26 | end |
19 | 27 | end |
20 | 28 | |
29 | + def google_map | |
30 | + render :partial => 'google_map.js' | |
31 | + end | |
32 | + | |
33 | + def search_city | |
34 | + | |
35 | + term = params[:term]; | |
36 | + | |
37 | + regions = NationalRegion.search_city(term + "%", true).map {|r|{ :label => r.city , :category => r.state}} | |
38 | + | |
39 | + render :json => regions | |
40 | + | |
41 | + end | |
42 | + | |
43 | + def search_state | |
44 | + | |
45 | + term = params[:term]; | |
46 | + | |
47 | + regions = NationalRegion.search_state(term + "%", true).map {|r|{ :label => r.state}} | |
48 | + | |
49 | + render :json => regions | |
50 | + | |
51 | + end | |
52 | + | |
21 | 53 | end | ... | ... |
app/controllers/public/browse_controller.rb
... | ... | @@ -1,77 +0,0 @@ |
1 | -class BrowseController < PublicController | |
2 | - | |
3 | - no_design_blocks | |
4 | - | |
5 | - FILTERS = %w( | |
6 | - more_recent | |
7 | - more_active | |
8 | - more_popular | |
9 | - more_comments | |
10 | - more_views | |
11 | - ) | |
12 | - | |
13 | - def per_page | |
14 | - 27 | |
15 | - end | |
16 | - | |
17 | - def people | |
18 | - @filter = filter | |
19 | - @title = self.filter_description(params[:action] + '_' + @filter ) | |
20 | - | |
21 | - @results = @environment.people.visible.send(@filter) | |
22 | - | |
23 | - if !params[:query].blank? | |
24 | - @results = @results.find_by_contents(params[:query]) | |
25 | - end | |
26 | - @results = @results.compact.paginate(:per_page => per_page, :page => params[:page]) | |
27 | - end | |
28 | - | |
29 | - def communities | |
30 | - @filter = filter | |
31 | - @title = self.filter_description(params[:action] + '_' + @filter ) | |
32 | - | |
33 | - @results = @environment.communities.visible.send(@filter) | |
34 | - | |
35 | - if !params[:query].blank? | |
36 | - @results = @results.find_by_contents(params[:query]) | |
37 | - end | |
38 | - @results = @results.compact.paginate(:per_page => per_page, :page => params[:page]) | |
39 | - end | |
40 | - | |
41 | - def contents | |
42 | - @filter = filter | |
43 | - @title = self.filter_description(params[:action] + '_' + @filter ) | |
44 | - | |
45 | - @results = @environment.articles.published.text_articles.send(@filter) | |
46 | - | |
47 | - if !params[:query].blank? | |
48 | - @results = @results.find_by_contents(params[:query]) | |
49 | - end | |
50 | - @results = @results.compact.paginate(:per_page => per_page, :page => params[:page]) | |
51 | - end | |
52 | - | |
53 | - protected | |
54 | - | |
55 | - def filter | |
56 | - if FILTERS.include?(params[:filter]) | |
57 | - params[:filter] | |
58 | - else | |
59 | - 'more_recent' | |
60 | - end | |
61 | - end | |
62 | - | |
63 | - def filter_description(str) | |
64 | - { | |
65 | - 'people_more_recent' => _('More recent people'), | |
66 | - 'people_more_active' => _('More active people'), | |
67 | - 'people_more_popular' => _('More popular people'), | |
68 | - 'communities_more_recent' => _('More recent communities'), | |
69 | - 'communities_more_active' => _('More active communities'), | |
70 | - 'communities_more_popular' => _('More popular communities'), | |
71 | - 'contents_more_recent' => _('More recent contents'), | |
72 | - 'contents_more_views' => _('Most viewed contents'), | |
73 | - 'contents_more_comments' => _('Most commented contents'), | |
74 | - }[str] || str | |
75 | - end | |
76 | - | |
77 | -end |
... | ... | @@ -0,0 +1,30 @@ |
1 | +class MapBalloonController < PublicController | |
2 | + | |
3 | + helper SearchHelper | |
4 | + | |
5 | + before_filter :load_profile, :only => [:person, :enterprise, :community] | |
6 | + | |
7 | + def product | |
8 | + @product = Product.find(params[:id]) | |
9 | + render :action => 'product', :layout => false | |
10 | + end | |
11 | + | |
12 | + def person | |
13 | + render :action => 'profile', :layout => false | |
14 | + end | |
15 | + | |
16 | + def enterprise | |
17 | + render :action => 'profile', :layout => false | |
18 | + end | |
19 | + | |
20 | + def community | |
21 | + render :action => 'profile', :layout => false | |
22 | + end | |
23 | + | |
24 | + protected | |
25 | + | |
26 | + def load_profile | |
27 | + @profile = Profile.find(params[:id]) | |
28 | + end | |
29 | + | |
30 | +end | ... | ... |
app/controllers/public/profile_search_controller.rb
... | ... | @@ -8,11 +8,11 @@ class ProfileSearchController < PublicController |
8 | 8 | def index |
9 | 9 | @q = params[:q] |
10 | 10 | unless @q.blank? |
11 | - @filtered_query = remove_stop_words(@q) | |
12 | 11 | if params[:where] == 'environment' |
13 | 12 | redirect_to :controller => 'search', :query => @q |
14 | 13 | else |
15 | - @results = profile.articles.published.find_by_contents(@filtered_query).paginate(:per_page => 10, :page => params[:page]) | |
14 | + @results = Article.find_by_contents(@q, {:per_page => 10, :page => params[:page]}, | |
15 | + {:filter_queries => ["profile_id:#{profile.id}", 'public:true']})[:results] | |
16 | 16 | end |
17 | 17 | end |
18 | 18 | end | ... | ... |
app/controllers/public/search_controller.rb
1 | 1 | class SearchController < PublicController |
2 | 2 | |
3 | 3 | helper TagsHelper |
4 | + include SearchHelper | |
5 | + include ActionView::Helpers::NumberHelper | |
4 | 6 | |
5 | 7 | before_filter :load_category |
6 | - before_filter :prepare_filter | |
7 | - before_filter :check_search_whole_site | |
8 | 8 | before_filter :load_search_assets |
9 | - before_filter :check_valid_assets, :only => [ :assets ] | |
9 | + before_filter :load_query | |
10 | 10 | |
11 | 11 | no_design_blocks |
12 | 12 | |
13 | - protected | |
13 | + def facets_browse | |
14 | + @asset = params[:asset] | |
15 | + @asset_class = asset_class(@asset) | |
14 | 16 | |
15 | - def load_search_assets | |
16 | - @search_in = where_to_search | |
17 | - @searching = {} | |
18 | - @search_in.each do |key, name| | |
19 | - @searching[key] = (params[:asset].blank? && (params[:find_in].nil? || params[:find_in].empty? || params[:find_in].include?(key.to_s))) || (params[:asset] == key.to_s) | |
20 | - end | |
17 | + @facets_only = true | |
18 | + send(@asset) | |
19 | + | |
20 | + @facet = @asset_class.map_facets_for(environment).find { |facet| facet[:id] == params[:facet_id] } | |
21 | + raise 'Facet not found' if @facet.nil? | |
22 | + | |
23 | + render :layout => false | |
21 | 24 | end |
22 | 25 | |
23 | - def prepare_filter | |
24 | - if @category | |
25 | - @noosfero_finder = CategoryFinder.new(@category) | |
26 | + def articles | |
27 | + if !@empty_query | |
28 | + full_text_search ['public:true'] | |
26 | 29 | else |
27 | - @noosfero_finder = EnvironmentFinder.new(@environment) | |
30 | + @results[@asset] = @environment.articles.public.send(@filter).paginate(paginate_options) | |
28 | 31 | end |
29 | 32 | end |
30 | 33 | |
31 | - def check_search_whole_site | |
32 | - if params[:search_whole_site_yes] or params[:search_whole_site] == 'yes' | |
33 | - redirect_to params.merge(:category_path => [], :search_whole_site => nil, :search_whole_site_yes => nil) | |
34 | - end | |
34 | + def contents | |
35 | + redirect_to params.merge(:action => :articles) | |
35 | 36 | end |
36 | 37 | |
37 | - def check_valid_assets | |
38 | - @asset = params[:asset].to_sym | |
39 | - if !where_to_search.map(&:first).include?(@asset) | |
40 | - render :text => 'go away', :status => 403 | |
41 | - return | |
38 | + def people | |
39 | + if !@empty_query | |
40 | + full_text_search ['public:true'] | |
41 | + else | |
42 | + @results[@asset] = @environment.people.visible.send(@filter).paginate(paginate_options) | |
42 | 43 | end |
43 | 44 | end |
44 | 45 | |
45 | - def events | |
46 | - @category_id = @category ? @category.id : nil | |
47 | - | |
48 | - @selected_day = nil | |
49 | - @events_of_the_day = [] | |
50 | - date = build_date(params[:year], params[:month], params[:day]) | |
51 | - | |
52 | - if params[:day] || !params[:year] && !params[:month] | |
53 | - @selected_day = date | |
54 | - if @category_id and Category.exists?(@category_id) | |
55 | - @events_of_the_day = environment.events.by_day(@selected_day).in_category(Category.find(@category_id)) | |
46 | + def products | |
47 | + if !@empty_query | |
48 | + full_text_search ['public:true'] | |
49 | + else | |
50 | + @one_page = true | |
51 | + @geosearch = logged_in? && current_user.person.lat && current_user.person.lng | |
52 | + | |
53 | + extra_limit = LIST_SEARCH_LIMIT*5 | |
54 | + sql_options = {:limit => LIST_SEARCH_LIMIT, :order => 'random()'} | |
55 | + if @geosearch | |
56 | + full_text_search ['public:true', "{!geofilt}"], :sql_options => sql_options, :extra_limit => extra_limit, | |
57 | + :alternate_query => "{!boost b=recip(geodist(),#{1/DistBoost},1,1)}", | |
58 | + :radius => DistFilt, :latitude => current_user.person.lat, :longitude => current_user.person.lng | |
56 | 59 | else |
57 | - @events_of_the_day = environment.events.by_day(@selected_day) | |
60 | + full_text_search ['public:true'], :sql_options => sql_options, :extra_limit => extra_limit, | |
61 | + :boost_functions => ['recip(ms(NOW/HOUR,updated_at),1.3e-10,1,1)'] | |
58 | 62 | end |
59 | 63 | end |
60 | - | |
61 | - events = @results[:events] | |
62 | - | |
63 | - @calendar = populate_calendar(date, events) | |
64 | - @previous_calendar = populate_calendar(date - 1.month, events) | |
65 | - @next_calendar = populate_calendar(date + 1.month, events) | |
66 | 64 | end |
67 | 65 | |
68 | - def people | |
69 | - #nothing, just to enable | |
70 | - end | |
71 | 66 | def enterprises |
72 | - load_product_categories_menu(:enterprises) | |
73 | - @categories_menu = true | |
74 | - end | |
75 | - def communities | |
76 | - #nothing, just to enable | |
77 | - end | |
78 | - def articles | |
79 | - #nothins, just to enable | |
80 | - end | |
81 | - | |
82 | - def products | |
83 | - load_product_categories_menu(:products) | |
84 | - @categories_menu = true | |
67 | + if !@empty_query | |
68 | + full_text_search ['public:true'] | |
69 | + else | |
70 | + @filter_title = _('Enterprises from network') | |
71 | + @results[@asset] = @environment.enterprises.visible.paginate(paginate_options) | |
72 | + end | |
85 | 73 | end |
86 | 74 | |
87 | - def load_product_categories_menu(asset) | |
88 | - @results[asset].uniq! | |
89 | - # REFACTOR DUPLICATED CODE inner loop doing the same thing that outter loop | |
90 | - | |
91 | - if !@query.blank? || @region && !params[:radius].blank? | |
92 | - @result_ids = @noosfero_finder.find(asset, @filtered_query, calculate_find_options(asset, nil, params[:page], @product_category, @region, params[:radius], params[:year], params[:month]).merge({:limit => :all})) | |
75 | + def communities | |
76 | + if !@empty_query | |
77 | + full_text_search ['public:true'] | |
78 | + else | |
79 | + @results[@asset] = @environment.communities.visible.send(@filter).paginate(paginate_options) | |
93 | 80 | end |
94 | - | |
95 | 81 | end |
96 | 82 | |
97 | - def calculate_find_options(asset, limit, page, product_category, region, radius, year, month) | |
98 | - result = { :product_category => product_category, :per_page => limit, :page => page } | |
99 | - if [:enterprises, :people, :products].include?(asset) && region | |
100 | - result.merge!(:within => radius, :region => region.id) | |
101 | - end | |
83 | + def events | |
84 | + year = (params[:year] ? params[:year].to_i : Date.today.year) | |
85 | + month = (params[:month] ? params[:month].to_i : Date.today.month) | |
86 | + day = (params[:day] ? params[:day].to_i : Date.today.day) | |
87 | + date = build_date(params[:year], params[:month], params[:day]) | |
88 | + date_range = (date - 1.month)..(date + 1.month).at_end_of_month | |
102 | 89 | |
103 | - if month || year | |
104 | - date = Date.new(year.to_i, month.to_i, 1) | |
105 | - result[:date_range] = (date - 1.month)..(date + 1.month).at_end_of_month | |
90 | + @selected_day = nil | |
91 | + @events_of_the_day = [] | |
92 | + if params[:day] || !params[:year] && !params[:month] | |
93 | + @selected_day = date | |
94 | + @events_of_the_day = @category ? | |
95 | + environment.events.by_day(@selected_day).in_category(Category.find(@category_id)) : | |
96 | + environment.events.by_day(@selected_day) | |
106 | 97 | end |
107 | 98 | |
108 | - result | |
109 | - end | |
110 | - | |
111 | - # limit the number of results per page | |
112 | - # TODO: dont hardcore like this | |
113 | - def limit | |
114 | - searching = @searching.values.select{|v|v} | |
115 | - if params[:display] == 'map' | |
116 | - 2000 | |
99 | + if !@empty_query | |
100 | + full_text_search | |
117 | 101 | else |
118 | - (searching.size == 1) ? 20 : 6 | |
102 | + @results[@asset] = date_range ? environment.events.by_range(date_range) : environment.events | |
119 | 103 | end |
120 | - end | |
121 | - | |
122 | - public | |
123 | - | |
124 | - include SearchHelper | |
125 | 104 | |
126 | - ###################################################### | |
127 | - | |
128 | - def where_to_search | |
129 | - [ | |
130 | - [ :articles, N_('Articles') ], | |
131 | - [ :enterprises, N_('Enterprises') ], | |
132 | - [ :people, N_('People') ], | |
133 | - [ :communities, N_('Communities') ], | |
134 | - [ :products, N_('Products') ], | |
135 | - [ :events, N_('Events') ] | |
136 | - ].select {|key, name| !environment.enabled?('disable_asset_' + key.to_s) } | |
137 | - end | |
138 | - | |
139 | - def cities | |
140 | - @cities = City.find(:all, :order => 'name', :conditions => ['parent_id = ? and lat is not null and lng is not null', params[:state_id]]) | |
141 | - render :action => 'cities', :layout => false | |
142 | - end | |
143 | - | |
144 | - def complete_region | |
145 | - # FIXME this logic should be in the model | |
146 | - @regions = Region.find(:all, :conditions => [ '(name like ? or name like ?) and lat is not null and lng is not null', '%' + params[:region][:name] + '%', '%' + params[:region][:name].capitalize + '%' ]) | |
147 | - render :action => 'complete_region', :layout => false | |
105 | + events = @results[@asset] | |
106 | + @calendar = populate_calendar(date, events) | |
107 | + @previous_calendar = populate_calendar(date - 1.month, events) | |
108 | + @next_calendar = populate_calendar(date + 1.month, events) | |
148 | 109 | end |
149 | 110 | |
150 | 111 | def index |
151 | - @query = params[:query] || '' | |
152 | - @filtered_query = remove_stop_words(@query) | |
153 | - @product_category = ProductCategory.find(params[:product_category]) if params[:product_category] | |
154 | - | |
155 | - @region = City.find_by_id(params[:city]) if !params[:city].blank? && params[:city] =~ /^\d+$/ | |
156 | - | |
157 | - # how many assets we are searching for? | |
158 | - number_of_result_assets = @searching.values.select{|v| v}.size | |
159 | - | |
160 | 112 | @results = {} |
161 | 113 | @order = [] |
162 | 114 | @names = {} |
115 | + @results_only = true | |
163 | 116 | |
164 | - where_to_search.select { |key,description| @searching[key] }.each do |key, description| | |
117 | + @enabled_searchs.select { |key,description| @searching[key] }.each do |key, description| | |
118 | + load_query | |
119 | + @asset = key | |
120 | + send(key) | |
165 | 121 | @order << key |
166 | - @results[key] = @noosfero_finder.find(key, @filtered_query, calculate_find_options(key, limit, params[:page], @product_category, @region, params[:radius], params[:year], params[:month])) | |
167 | 122 | @names[key] = getterm(description) |
168 | 123 | end |
124 | + @asset = nil | |
125 | + @facets = {} | |
169 | 126 | |
170 | - if @results.keys.size == 1 | |
171 | - specific_action = @results.keys.first | |
172 | - if respond_to?(specific_action) | |
173 | - @asset_name = getterm(@names[@results.keys.first]) | |
174 | - send(specific_action) | |
175 | - render :action => specific_action | |
176 | - return | |
177 | - end | |
178 | - end | |
179 | - | |
180 | - render :action => 'index' | |
127 | + render :action => @results.keys.first if @results.keys.size == 1 | |
181 | 128 | end |
182 | 129 | |
183 | - alias :assets :index | |
184 | - | |
185 | - ####################################################### | |
130 | + # keep old URLs workings | |
131 | + def assets | |
132 | + params[:action] = params[:asset].is_a?(Array) ? :index : params.delete(:asset) | |
133 | + redirect_to params | |
134 | + end | |
186 | 135 | |
187 | 136 | # view the summary of one category |
188 | 137 | def category_index |
189 | 138 | @results = {} |
190 | 139 | @order = [] |
191 | 140 | @names = {} |
141 | + limit = MULTIPLE_SEARCH_LIMIT | |
192 | 142 | [ |
193 | - [ :people, _('People'), @noosfero_finder.recent('people', limit) ], | |
194 | - [ :enterprises, __('Enterprises'), @noosfero_finder.recent('enterprises', limit) ], | |
195 | - [ :products, _('Products'), @noosfero_finder.recent('products', limit) ], | |
196 | - [ :events, _('Upcoming events'), @noosfero_finder.upcoming_events({:per_page => limit}) ], | |
197 | - [ :communities, __('Communities'), @noosfero_finder.recent('communities', limit) ], | |
198 | - [ :most_commented_articles, _('Most commented articles'), @noosfero_finder.most_commented_articles(limit) ], | |
199 | - [ :articles, _('Articles'), @noosfero_finder.recent('text_articles', limit) ] | |
200 | - ].each do |key, name, list| | |
201 | - @order << key | |
202 | - @results[key] = list | |
203 | - @names[key] = name | |
143 | + [ :people, _('People'), :recent_people ], | |
144 | + [ :enterprises, _('Enterprises'), :recent_enterprises ], | |
145 | + [ :products, _('Products'), :recent_products ], | |
146 | + [ :events, _('Upcoming events'), :upcoming_events ], | |
147 | + [ :communities, _('Communities'), :recent_communities ], | |
148 | + [ :articles, _('Contents'), :recent_articles ] | |
149 | + ].each do |asset, name, filter| | |
150 | + @order << asset | |
151 | + @results[asset] = @category.send(filter, limit) | |
152 | + raise "nao total #{asset}" unless @results[asset].respond_to?(:total_entries) | |
153 | + @names[asset] = name | |
204 | 154 | end |
205 | 155 | end |
206 | - attr_reader :category | |
207 | 156 | |
208 | 157 | def tags |
209 | 158 | @tags_cache_key = "tags_env_#{environment.id.to_s}" |
... | ... | @@ -216,25 +165,138 @@ class SearchController < PublicController |
216 | 165 | @tag = params[:tag] |
217 | 166 | @tag_cache_key = "tag_#{CGI.escape(@tag.to_s)}_env_#{environment.id.to_s}_page_#{params[:npage]}" |
218 | 167 | if is_cache_expired?(@tag_cache_key) |
219 | - @tagged = environment.articles.find_tagged_with(@tag).paginate(:per_page => 10, :page => params[:npage]) | |
168 | + @asset = :articles | |
169 | + @results[@asset] = environment.articles.find_tagged_with(@tag).paginate(paginate_options) | |
220 | 170 | end |
221 | 171 | end |
222 | 172 | |
173 | + def events_by_day | |
174 | + @selected_day = build_date(params[:year], params[:month], params[:day]) | |
175 | + @events_of_the_day = environment.events.by_day(@selected_day) | |
176 | + render :partial => 'events/events_by_day' | |
177 | + end | |
178 | + | |
223 | 179 | ####################################################### |
180 | + protected | |
181 | + | |
182 | + def load_query | |
183 | + @asset = params[:action].to_sym | |
184 | + @order ||= [@asset] | |
185 | + @results ||= {} | |
186 | + @filter = filter | |
187 | + @filter_title = filter_description(@asset, @filter) | |
224 | 188 | |
225 | - def popup | |
226 | - @regions = Region.find(:all).select{|r|r.lat && r.lng} | |
227 | - render :action => 'popup', :layout => false | |
189 | + @query = params[:query] || '' | |
190 | + @empty_query = @category.nil? && @query.blank? | |
228 | 191 | end |
229 | 192 | |
230 | - def events_by_day | |
231 | - @selected_day = build_date(params[:year], params[:month], params[:day]) | |
232 | - if params[:category_id] and Category.exists?(params[:category_id]) | |
233 | - @events_of_the_day = environment.events.by_day(@selected_day).in_category(Category.find(params[:category_id])) | |
193 | + def load_category | |
194 | + unless params[:category_path].blank? | |
195 | + path = params[:category_path].join('/') | |
196 | + @category = environment.categories.find_by_path(path) | |
197 | + if @category.nil? | |
198 | + render_not_found(path) | |
199 | + else | |
200 | + @category_id = @category.id | |
201 | + end | |
202 | + end | |
203 | + end | |
204 | + | |
205 | + FILTERS = %w( | |
206 | + more_recent | |
207 | + more_active | |
208 | + more_popular | |
209 | + ) | |
210 | + def filter | |
211 | + if FILTERS.include?(params[:filter]) | |
212 | + params[:filter] | |
234 | 213 | else |
235 | - @events_of_the_day = environment.events.by_day(@selected_day) | |
214 | + 'more_recent' | |
236 | 215 | end |
237 | - render :partial => 'events/events_by_day' | |
216 | + end | |
217 | + | |
218 | + def filter_description(asset, filter) | |
219 | + { | |
220 | + 'articles_more_recent' => _('More recent contents from network'), | |
221 | + 'articles_more_popular' => _('More read contents from network'), | |
222 | + 'people_more_recent' => _('More recent people from network'), | |
223 | + 'people_more_active' => _('More active people from network'), | |
224 | + 'people_more_popular' => _('More popular people from network'), | |
225 | + 'communities_more_recent' => _('More recent communities from network'), | |
226 | + 'communities_more_active' => _('More active communities from network'), | |
227 | + 'communities_more_popular' => _('More popular communities from network'), | |
228 | + 'products_more_recent' => _('Highlights'), | |
229 | + }[asset.to_s + '_' + filter] | |
230 | + end | |
231 | + | |
232 | + def load_search_assets | |
233 | + @enabled_searchs = [ | |
234 | + [ :articles, _('Contents') ], | |
235 | + [ :enterprises, _('Enterprises') ], | |
236 | + [ :people, _('People') ], | |
237 | + [ :communities, _('Communities') ], | |
238 | + [ :products, _('Products and Services') ], | |
239 | + [ :events, _('Events') ] | |
240 | + ].select {|key, name| !environment.enabled?('disable_asset_' + key.to_s) } | |
241 | + | |
242 | + @searching = {} | |
243 | + @titles = {} | |
244 | + @enabled_searchs.each do |key, name| | |
245 | + @titles[key] = name | |
246 | + @searching[key] = params[:action] == 'index' || params[:action] == key.to_s | |
247 | + end | |
248 | + end | |
249 | + | |
250 | + def limit | |
251 | + searching = @searching.values.select{ |v| v } | |
252 | + if params[:display] == 'map' | |
253 | + MAP_SEARCH_LIMIT | |
254 | + elsif searching.size <= 1 | |
255 | + if [:people, :communities].include? @asset | |
256 | + BLOCKS_SEARCH_LIMIT | |
257 | + elsif @asset == :enterprises and @empty_query | |
258 | + BLOCKS_SEARCH_LIMIT | |
259 | + else | |
260 | + LIST_SEARCH_LIMIT | |
261 | + end | |
262 | + else | |
263 | + MULTIPLE_SEARCH_LIMIT | |
264 | + end | |
265 | + end | |
266 | + | |
267 | + def paginate_options(page = params[:page]) | |
268 | + { :per_page => limit, :page => page } | |
269 | + end | |
270 | + | |
271 | + def full_text_search(filters = [], options = {}) | |
272 | + paginate_options = paginate_options(params[:page]) | |
273 | + asset_class = asset_class(@asset) | |
274 | + | |
275 | + solr_options = options | |
276 | + if !@results_only and asset_class.respond_to? :facets | |
277 | + solr_options.merge! asset_class.facets_find_options(params[:facet]) | |
278 | + solr_options[:all_facets] = true | |
279 | + solr_options[:limit] = 0 if @facets_only | |
280 | + end | |
281 | + solr_options[:filter_queries] ||= [] | |
282 | + solr_options[:filter_queries] += filters | |
283 | + solr_options[:filter_queries] << "environment_id:#{environment.id}" | |
284 | + solr_options[:filter_queries] << asset_class.facet_category_query.call(@category) if @category | |
285 | + | |
286 | + solr_options[:boost_functions] ||= [] | |
287 | + params[:order_by] = nil if params[:order_by] == 'none' | |
288 | + if params[:order_by] | |
289 | + order = SortOptions[@asset][params[:order_by].to_sym] | |
290 | + raise "Unknown order by" if order.nil? | |
291 | + order[:solr_opts].each do |opt, value| | |
292 | + solr_options[opt] = value.is_a?(Proc) ? instance_eval(&value) : value | |
293 | + end | |
294 | + end | |
295 | + | |
296 | + ret = asset_class.find_by_contents(@query, paginate_options, solr_options) | |
297 | + @results[@asset] = ret[:results] | |
298 | + @facets = ret[:facets] | |
299 | + @all_facets = ret[:all_facets] | |
238 | 300 | end |
239 | 301 | |
240 | 302 | end | ... | ... |
app/helpers/application_helper.rb
... | ... | @@ -4,7 +4,7 @@ require 'redcloth' |
4 | 4 | # application. |
5 | 5 | module ApplicationHelper |
6 | 6 | |
7 | - include PermissionName | |
7 | + include PermissionNameHelper | |
8 | 8 | |
9 | 9 | include LightboxHelper |
10 | 10 | |
... | ... | @@ -574,7 +574,7 @@ module ApplicationHelper |
574 | 574 | end |
575 | 575 | extra_info = extra_info.nil? ? '' : content_tag( 'span', extra_info, :class => 'extra_info' ) |
576 | 576 | links = links_for_balloon(profile) |
577 | - content_tag tag, | |
577 | + content_tag('div', content_tag(tag, | |
578 | 578 | (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 #{trigger_class}", :url => url) : "") + |
579 | 579 | link_to( |
580 | 580 | content_tag( 'span', profile_image( profile, size ), :class => 'profile-image' ) + |
... | ... | @@ -584,7 +584,7 @@ module ApplicationHelper |
584 | 584 | :class => 'profile_link url', |
585 | 585 | :help => _('Click on this icon to go to the <b>%s</b>\'s home page') % profile.name, |
586 | 586 | :title => profile.name ), |
587 | - :class => 'vcard' | |
587 | + :class => 'vcard'), :class => 'common-profile-list-block') | |
588 | 588 | end |
589 | 589 | |
590 | 590 | def gravatar_url_for(email, options = {}) |
... | ... | @@ -890,22 +890,6 @@ module ApplicationHelper |
890 | 890 | result |
891 | 891 | end |
892 | 892 | |
893 | - def search_page_title(title, options={}) | |
894 | - title = "<h1>" + title + "</h1>" | |
895 | - title += "<h2 class='query'>" + _("Searched for '%s'") % options[:query] + "</h2>" if !options[:query].blank? | |
896 | - title += "<h2 class='query'>" + _("In category %s") % options[:category] + "</h2>" if !options[:category].blank? | |
897 | - title += "<h2 class='query'>" + _("within %d km from %s") % [options[:distance], options[:region]] + "</h2>" if !options[:distance].blank? && !options[:region].blank? | |
898 | - title += "<h2 class='query'>" + _("%d results found") % options[:total_results] + "</h2>" if !options[:total_results].blank? | |
899 | - title | |
900 | - end | |
901 | - | |
902 | - def search_page_link_to_all(options={}) | |
903 | - if options[:category] | |
904 | - title = "<div align='center'>" + _('In all categories') + "</div>" | |
905 | - link_to title, :action => 'assets', :asset => options[:asset], :category_path => [] | |
906 | - end | |
907 | - end | |
908 | - | |
909 | 893 | def template_stylesheet_path |
910 | 894 | if profile.nil? |
911 | 895 | "/designs/templates/#{environment.layout_template}/stylesheets/style.css" |
... | ... | @@ -982,6 +966,7 @@ module ApplicationHelper |
982 | 966 | def noosfero_stylesheets |
983 | 967 | [ |
984 | 968 | 'application', |
969 | + 'search', | |
985 | 970 | 'thickbox', |
986 | 971 | 'lightbox', |
987 | 972 | 'colorpicker', |
... | ... | @@ -1001,7 +986,7 @@ module ApplicationHelper |
1001 | 986 | end |
1002 | 987 | |
1003 | 988 | def tokeninput_stylesheets |
1004 | - ['token-input', 'token-input-facebook', 'token-input-mac'] | |
989 | + ['token-input', 'token-input-facebook', 'token-input-mac', 'token-input-facet'] | |
1005 | 990 | end |
1006 | 991 | |
1007 | 992 | def noosfero_layout_features |
... | ... | @@ -1100,33 +1085,46 @@ module ApplicationHelper |
1100 | 1085 | ") : '') |
1101 | 1086 | end |
1102 | 1087 | |
1103 | - def browse_people_menu | |
1088 | + def search_contents_menu | |
1089 | + links = [ | |
1090 | + {s_('contents|More Recent') => {:href => url_for({:controller => 'search', :action => 'contents', :filter => 'more_recent'})}}, | |
1091 | + {s_('contents|More Read') => {:href => url_for({:controller => 'search', :action => 'contents', :filter => 'more_popular'})}} | |
1092 | + ] | |
1093 | + if logged_in? | |
1094 | + links.push(_('New Content') => lightbox_options({:href => url_for({:controller => 'cms', :action => 'new', :profile => current_user.login, :cms => true})})) | |
1095 | + end | |
1096 | + | |
1097 | + link_to(content_tag(:span, _('Contents'), :class => 'icon-menu-articles'), {:controller => "search", :action => 'contents', :category_path => ''}, :id => 'submenu-contents') + | |
1098 | + link_to(content_tag(:span, _('Contents Menu')), '#', :onclick => "toggleSubmenu(this,'',#{links.to_json}); return false", :class => 'menu-submenu-trigger up', :id => 'submenu-contents-trigger') | |
1099 | + end | |
1100 | + | |
1101 | + def search_people_menu | |
1104 | 1102 | links = [ |
1105 | - {s_('people|More Recent') => {:href => url_for({:controller => 'browse', :action => 'people', :filter => 'more_recent'})}}, | |
1106 | - {s_('people|More Active') => {:href => url_for({:controller => 'browse', :action => 'people', :filter => 'more_active'})}}, | |
1107 | - {s_('people|More Popular') => {:href => url_for({:controller => 'browse', :action => 'people', :filter => 'more_popular'})}} | |
1103 | + {s_('people|More Recent') => {:href => url_for({:controller => 'search', :action => 'people', :filter => 'more_recent'})}}, | |
1104 | + {s_('people|More Active') => {:href => url_for({:controller => 'search', :action => 'people', :filter => 'more_active'})}}, | |
1105 | + {s_('people|More Popular') => {:href => url_for({:controller => 'search', :action => 'people', :filter => 'more_popular'})}} | |
1108 | 1106 | ] |
1109 | 1107 | if logged_in? |
1110 | 1108 | links.push(_('My friends') => {:href => url_for({:profile => current_user.login, :controller => 'friends'})}) |
1111 | 1109 | links.push(_('Invite friends') => {:href => url_for({:profile => current_user.login, :controller => 'invite', :action => 'friends'})}) |
1112 | 1110 | end |
1113 | 1111 | |
1114 | - link_to(content_tag(:span, _('People'), :class => 'icon-menu-people'), {:controller => "browse", :action => 'people'}, :id => 'submenu-people') + | |
1112 | + link_to(content_tag(:span, _('People'), :class => 'icon-menu-people'), {:controller => "search", :action => 'people', :category_path => ''}, :id => 'submenu-people') + | |
1115 | 1113 | link_to(content_tag(:span, _('People Menu')), '#', :onclick => "toggleSubmenu(this,'',#{links.to_json}); return false", :class => 'menu-submenu-trigger up', :id => 'submenu-people-trigger') |
1116 | 1114 | end |
1117 | 1115 | |
1118 | - def browse_communities_menu | |
1116 | + def search_communities_menu | |
1119 | 1117 | links = [ |
1120 | - {s_('communities|More Recent') => {:href => url_for({:controller => 'browse', :action => 'communities', :filter => 'more_recent'})}}, | |
1121 | - {s_('communities|More Active') => {:href => url_for({:controller => 'browse', :action => 'communities', :filter => 'more_active'})}}, | |
1122 | - {s_('communities|More Popular') => {:href => url_for({:controller => 'browse', :action => 'communities', :filter => 'more_popular'})}} | |
1118 | + {s_('communities|More Recent') => {:href => url_for({:controller => 'search', :action => 'communities', :filter => 'more_recent'})}}, | |
1119 | + {s_('communities|More Active') => {:href => url_for({:controller => 'search', :action => 'communities', :filter => 'more_active'})}}, | |
1120 | + {s_('communities|More Popular') => {:href => url_for({:controller => 'search', :action => 'communities', :filter => 'more_popular'})}} | |
1123 | 1121 | ] |
1124 | 1122 | if logged_in? |
1125 | 1123 | links.push(_('My communities') => {:href => url_for({:profile => current_user.login, :controller => 'memberships'})}) |
1126 | 1124 | links.push(_('New community') => {:href => url_for({:profile => current_user.login, :controller => 'memberships', :action => 'new_community'})}) |
1127 | 1125 | end |
1128 | 1126 | |
1129 | - link_to(content_tag(:span, _('Communities'), :class => 'icon-menu-community'), {:controller => "browse", :action => 'communities'}, :id => 'submenu-communities') + | |
1127 | + link_to(content_tag(:span, _('Communities'), :class => 'icon-menu-community'), {:controller => "search", :action => 'communities'}, :id => 'submenu-communities') + | |
1130 | 1128 | link_to(content_tag(:span, _('Communities Menu')), '#', :onclick => "toggleSubmenu(this,'',#{links.to_json}); return false", :class => 'menu-submenu-trigger up', :id => 'submenu-communities-trigger') |
1131 | 1129 | end |
1132 | 1130 | |
... | ... | @@ -1330,6 +1328,10 @@ module ApplicationHelper |
1330 | 1328 | end |
1331 | 1329 | end |
1332 | 1330 | |
1331 | + def jquery_token_input_messages_json(hintText = _('Type in an keyword'), noResultsText = _('No results'), searchingText = _('Searching...')) | |
1332 | + "hintText: '#{hintText}', noResultsText: '#{noResultsText}', searchingText: '#{searchingText}'" | |
1333 | + end | |
1334 | + | |
1333 | 1335 | def delete_article_message(article) |
1334 | 1336 | if article.folder? |
1335 | 1337 | _("Are you sure that you want to remove the folder \"#{article.name}\"? Note that all the items inside it will also be removed!") | ... | ... |
app/helpers/display_helper.rb
... | ... | @@ -26,15 +26,19 @@ module DisplayHelper |
26 | 26 | product.enterprise.enabled? ? product.enterprise.public_profile_url.merge(:controller => 'manage_products', :action => 'show', :id => product) : product.enterprise.url |
27 | 27 | end |
28 | 28 | |
29 | - def link_to_category(category, full = true) | |
29 | + def link_to_tag(tag, html_options = {}) | |
30 | + link_to tag.name, {:controller => 'search', :action => 'tag', :tag => tag.name}, html_options | |
31 | + end | |
32 | + | |
33 | + def link_to_category(category, full = true, html_options = {}) | |
30 | 34 | return _('Uncategorized product') unless category |
31 | 35 | name = full ? category.full_name(' → ') : category.name |
32 | - link_to name, Noosfero.url_options.merge({:controller => 'search', :action => 'category_index', :category_path => category.path.split('/'),:host => category.environment.default_hostname }) | |
36 | + link_to name, Noosfero.url_options.merge({:controller => 'search', :action => 'category_index', :category_path => category.path.split('/'),:host => category.environment.default_hostname }), html_options | |
33 | 37 | end |
34 | 38 | |
35 | 39 | def link_to_product_category(category) |
36 | 40 | if category |
37 | - link_to(category.name, :controller => 'search', :action => 'assets', :asset => 'products', :product_category => category.id, :host => category.environment.default_hostname) | |
41 | + link_to(category.name, :controller => 'search', :action => 'products', :category_path => category.explode_path) | |
38 | 42 | else |
39 | 43 | _('Uncategorized product') |
40 | 44 | end | ... | ... |
app/helpers/lightbox_helper.rb
... | ... | @@ -22,10 +22,7 @@ module LightboxHelper |
22 | 22 | def lightbox_options(options, lightbox_type = 'lbOn') |
23 | 23 | the_class = lightbox_type |
24 | 24 | the_class << " #{options[:class]}" if options.has_key?(:class) |
25 | - options.merge( | |
26 | - :class => the_class, | |
27 | - :onclick => 'alert("%s"); return false' % _('Please, try again when the page loading completes.') | |
28 | - ) | |
25 | + options.merge(:class => the_class) | |
29 | 26 | end |
30 | 27 | |
31 | 28 | def lightbox? | ... | ... |
app/helpers/product_category_viewer_helper.rb
app/helpers/search_helper.rb
1 | 1 | module SearchHelper |
2 | 2 | |
3 | + MAP_SEARCH_LIMIT = 2000 | |
4 | + LIST_SEARCH_LIMIT = 20 | |
5 | + BLOCKS_SEARCH_LIMIT = 18 | |
6 | + MULTIPLE_SEARCH_LIMIT = 8 | |
7 | + DistFilt = 200 | |
8 | + DistBoost = 50 | |
9 | + SortOptions = { | |
10 | + :products => ActiveSupport::OrderedHash[ :none, {:label => _('Relevance')}, | |
11 | + :more_recent, {:label => _('More Recent'), :solr_opts => {:sort => 'updated_at desc, score desc'}}, | |
12 | + :name, {:label => _('Name'), :solr_opts => {:sort => 'name_sortable asc'}}, | |
13 | + :closest, {:label => _('Closest to me'), :if => proc{ logged_in? && (profile=current_user.person).lat && profile.lng }, | |
14 | + :solr_opts => {:sort => "geodist() asc", | |
15 | + :latitude => proc{ current_user.person.lat }, :longitude => proc{ current_user.person.lng }}}, | |
16 | + ], | |
17 | + :events => ActiveSupport::OrderedHash[ :none, {:label => _('Relevance')}, | |
18 | + :name, {:label => _('Name'), :solr_opts => {:sort => 'name_sortable asc'}}, | |
19 | + ], | |
20 | + :articles => ActiveSupport::OrderedHash[ :none, {:label => _('Relevance')}, | |
21 | + :name, {:label => _('Name'), :solr_opts => {:sort => 'name_sortable asc'}}, | |
22 | + :name, {:label => _('Most recent'), :solr_opts => {:sort => 'updated_at desc, score desc'}}, | |
23 | + ], | |
24 | + :enterprises => ActiveSupport::OrderedHash[ :none, {:label => _('Relevance')}, | |
25 | + :name, {:label => _('Name'), :solr_opts => {:sort => 'name_sortable asc'}}, | |
26 | + ], | |
27 | + :people => ActiveSupport::OrderedHash[ :none, {:label => _('Relevance')}, | |
28 | + :name, {:label => _('Name'), :solr_opts => {:sort => 'name_sortable asc'}}, | |
29 | + ], | |
30 | + :communities => ActiveSupport::OrderedHash[ :none, {:label => _('Relevance')}, | |
31 | + :name, {:label => _('Name'), :solr_opts => {:sort => 'name_sortable asc'}}, | |
32 | + ], | |
33 | + } | |
34 | + | |
3 | 35 | # FIXME remove it after search_controler refactored |
4 | 36 | include EventsHelper |
5 | 37 | |
6 | - STOP_WORDS = { | |
7 | - 'pt_BR' => Ferret::Analysis::FULL_PORTUGUESE_STOP_WORDS, | |
8 | - 'en' => Ferret::Analysis::FULL_ENGLISH_STOP_WORDS, | |
9 | - } | |
10 | - | |
11 | - def relevance_for(hit) | |
12 | - n = (hit.ferret_score if hit.respond_to?(:ferret_score)) | |
13 | - n ||= 1.0 | |
14 | - (n * 100.0).round | |
38 | + def search_page_title(title, category = nil) | |
39 | + title = "<h1>" + title | |
40 | + title += '<small>' + category.name + '</small>' if category | |
41 | + title + "</h1>" | |
15 | 42 | end |
16 | 43 | |
17 | - def remove_stop_words(query) | |
18 | - (query.downcase.scan(/"[^"]*"?|'[^']*'?|[^'"\s]+/) - (STOP_WORDS[locale] || [])).join(' ') | |
44 | + def category_context(category, url) | |
45 | + content_tag('div', category.full_name + _(', ') + | |
46 | + link_to(_('search in all categories'), | |
47 | + url.merge(:category_path => [], :action => (params[:action] == 'category_index' ? 'index' : params[:action]) )), | |
48 | + :align => 'center', :class => 'search-category-context') if category | |
19 | 49 | end |
20 | 50 | |
21 | - def display_results(use_map = true) | |
22 | - | |
23 | - unless use_map && GoogleMaps.enabled?(environment.default_hostname) | |
24 | - return render(:partial => 'display_results') | |
51 | + def display_results(use_map = false) | |
52 | + if params[:display] == 'map' && use_map | |
53 | + partial = 'google_maps' | |
54 | + klass = 'map' | |
55 | + else | |
56 | + partial = 'display_results' | |
57 | + klass = 'list' | |
25 | 58 | end |
26 | 59 | |
27 | - data = | |
28 | - if params[:display] == 'map' | |
29 | - { | |
30 | - :partial => 'google_maps', | |
31 | - :toggle => button(:search, _('Display in list'), params.merge(:display => 'list'), :class => "map-toggle-button" ), | |
32 | - :class => 'map' , | |
33 | - } | |
60 | + content_tag('div', render(:partial => partial), :class => "map-or-list-search-results #{klass}") | |
61 | + end | |
62 | + | |
63 | + def display_map_list_button | |
64 | + button(:search, params[:display] == 'map' ? _('Display in list') : _('Display in map'), | |
65 | + params.merge(:display => (params[:display] == 'map' ? 'list' : 'map')), | |
66 | + :class => "map-toggle-button" ) | |
67 | + end | |
68 | + | |
69 | + def city_with_state(city) | |
70 | + if city and city.kind_of?(City) | |
71 | + s = city.parent | |
72 | + if s and s.kind_of?(State) and s.acronym | |
73 | + city.name + ', ' + s.acronym | |
34 | 74 | else |
35 | - { | |
36 | - :partial => 'display_results', | |
37 | - :toggle => button(:search, _('Display in map'), params.merge(:display => 'map'), :class => "map-toggle-button" ), | |
38 | - :class => 'list' , | |
39 | - } | |
75 | + city.name | |
40 | 76 | end |
77 | + else | |
78 | + nil | |
79 | + end | |
80 | + end | |
41 | 81 | |
42 | - content_tag('div', data[:toggle] + (render :partial => data[:partial]), :class => "map-or-list-search-results #{data[:class]}") | |
82 | + def facets_menu(asset, _facets) | |
83 | + @asset_class = asset_class(asset) | |
84 | + @facets = _facets | |
85 | + render(:partial => 'facets_menu') | |
43 | 86 | end |
44 | 87 | |
45 | - def display_item_map_info(item) | |
46 | - if item.kind_of?(Profile) | |
47 | - display_profile_info(item) | |
48 | - elsif item.kind_of?(Product) | |
49 | - display_product_info(item) | |
50 | - end | |
88 | + def facets_unselect_menu(asset) | |
89 | + @asset_class = asset_class(asset) | |
90 | + render(:partial => 'facets_unselect_menu') | |
51 | 91 | end |
52 | 92 | |
53 | - def display_profile_info(profile) | |
54 | - data = '' | |
55 | - unless profile.contact_email.nil? | |
56 | - data << content_tag('strong', _('E-Mail: ')) + profile.contact_email + '<br/>' | |
57 | - end | |
58 | - unless profile.contact_phone.nil? | |
59 | - data << content_tag('strong', _('Phone(s): ')) + profile.contact_phone + '<br/>' | |
60 | - end | |
61 | - unless profile.region.nil? | |
62 | - data << content_tag('strong', _('Location: ')) + profile.region.name + '<br/>' | |
63 | - end | |
64 | - unless profile.address.nil? | |
65 | - data << content_tag('strong', _('Address: ')) + profile.address + '<br/>' | |
66 | - end | |
67 | - unless profile.products.empty? | |
68 | - data << content_tag('strong', _('Products/Services: ')) + profile.products.map{|i| link_to(i.name, :controller => 'manage_products', :profile => profile.identifier, :action => 'show', :id => i.id)}.join(', ') + '<br/>' | |
69 | - end | |
70 | - if profile.respond_to?(:distance) and !profile.distance.nil? | |
71 | - data << content_tag('strong', _('Distance: ')) + "%.2f%" % profile.distance + '<br/>' | |
72 | - end | |
73 | - content_tag('table', | |
74 | - content_tag('tr', | |
75 | - content_tag('td', content_tag('div', profile_image(profile, :thumb), :class => 'profile-info-picture')) + | |
76 | - content_tag('td', content_tag('strong', link_to(profile.name, url_for(profile.url))) + '<br/>' + data | |
77 | - ) | |
78 | - ), | |
79 | - :class => 'profile-info' | |
80 | - ) | |
93 | + def facet_javascript(input_id, facet, array) | |
94 | + array = [] if array.nil? | |
95 | + hintText = _('Type in an option') | |
96 | + text_field_tag('facet['+input_id+']', '', :id => input_id) + | |
97 | + javascript_tag("jQuery.TokenList(jQuery('##{input_id}'), #{array.to_json}, | |
98 | + {searchDelay: 0, permanentDropdown: true, theme: 'facet', dontAdd: true, preventDuplicates: true, | |
99 | + #{jquery_token_input_messages_json(hintText)}});") | |
81 | 100 | end |
82 | 101 | |
83 | - def display_product_info(product) | |
84 | - data = '' | |
85 | - unless product.price.nil? | |
86 | - data << content_tag('strong', _('Price: ')) + product.price + '<br/>' | |
87 | - end | |
88 | - unless product.enterprise.nil? | |
89 | - data << content_tag('strong', _('Provider: ')) + link_to_profile(product.enterprise.name, product.enterprise.identifier) | |
90 | - end | |
91 | - unless product.product_category.nil? | |
92 | - data << content_tag('strong', _('Category: ')) + link_to(product.product_category.name, :controller => 'search', :action => 'assets', :asset => 'products', :product_category => product.product_category.id) | |
102 | + def facet_link_html(facet, params, value, label, count) | |
103 | + params = params ? params.dup : {} | |
104 | + has_extra = label.kind_of?(Array) | |
105 | + link_label = has_extra ? label[0] : label | |
106 | + id = facet[:solr_field].to_s | |
107 | + params[:facet] ||= {} | |
108 | + params[:facet][id] ||= {} | |
109 | + params[:page] = {} if params[:page] | |
110 | + | |
111 | + selected = facet[:label_id].nil? ? params[:facet][id] == value : params[:facet][id][facet[:label_id]].to_a.include?(value) | |
112 | + | |
113 | + if count > 0 | |
114 | + url = params.merge(:facet => params[:facet].merge( | |
115 | + id => facet[:label_id].nil? ? value : params[:facet][id].merge( facet[:label_id] => params[:facet][id][facet[:label_id]].to_a.push(value) ) | |
116 | + )) | |
117 | + else | |
118 | + # preserve others filters and change this filter | |
119 | + url = params.merge(:facet => params[:facet].merge( | |
120 | + id => facet[:label_id].nil? ? value : { facet[:label_id] => value } | |
121 | + )) | |
93 | 122 | end |
94 | - content_tag('table', | |
95 | - content_tag('tr', | |
96 | - content_tag('td', content_tag('div', image_tag(product.image ? product.image.public_filename(:thumb) : '/images/icons-app/product-default-pic-portrait.png'), :class => 'profile-info-picture')) + | |
97 | - content_tag('td', content_tag('strong', link_to(product.name, :controller => 'catalog', :profile => product.enterprise.identifier, :action => 'show', :id => product)) + '<br/>' + data) | |
98 | - ), :class => 'profile-info') | |
123 | + | |
124 | + content_tag 'div', link_to(link_label, url, :class => 'facet-result-link-label') + | |
125 | + content_tag('span', (has_extra ? label[1] : ''), :class => 'facet-result-extra-label') + | |
126 | + (count > 0 ? content_tag('span', " (#{count})", :class => 'facet-result-count') : ''), | |
127 | + :class => 'facet-menu-item' + (selected ? ' facet-result-link-selected' : '') | |
99 | 128 | end |
100 | 129 | |
101 | - def product_categories_menu(asset, product_category, object_ids = nil) | |
102 | - cats = ProductCategory.menu_categories(@product_category, environment) | |
103 | - cats += cats.select { |c| c.children_count > 0 }.map(&:children).flatten | |
104 | - product_categories_ids = cats.map(&:id) | |
105 | - | |
106 | - counts = @noosfero_finder.product_categories_count(asset, product_categories_ids, object_ids) | |
107 | - | |
108 | - product_categories_menu = ProductCategory.menu_categories(product_category, environment).map do |cat| | |
109 | - hits = counts[cat.id] | |
110 | - childs = [] | |
111 | - if hits | |
112 | - if cat.children_count > 0 | |
113 | - childs = cat.children.map do |child| | |
114 | - child_hits = counts[child.id] | |
115 | - [child, child_hits] | |
116 | - end.select{|child, child_hits| child_hits } | |
117 | - else | |
118 | - childs = [] | |
130 | + def facet_selecteds_html_for(environment, klass, params) | |
131 | + def name_with_extra(klass, facet, value) | |
132 | + name = klass.facet_result_name(facet, value) | |
133 | + name = name[0] + name[1] if name.kind_of?(Array) | |
134 | + name | |
135 | + end | |
136 | + | |
137 | + ret = [] | |
138 | + params = params.dup | |
139 | + params[:facet].each do |id, value| | |
140 | + facet = klass.facet_by_id(id.to_sym) | |
141 | + if value.kind_of?(Hash) | |
142 | + label_hash = facet[:label].call(environment) | |
143 | + value.each do |label_id, value| | |
144 | + facet[:label_id] = label_id | |
145 | + facet[:label] = label_hash[label_id] | |
146 | + value.to_a.each do |value| | |
147 | + ret << [facet[:label], name_with_extra(klass, facet, value), | |
148 | + params.merge(:facet => params[:facet].merge(id => params[:facet][id].merge(label_id => params[:facet][id][label_id].to_a.reject{ |v| v == value })))] | |
149 | + end | |
119 | 150 | end |
151 | + else | |
152 | + ret << [klass.facet_label(facet), name_with_extra(klass, facet, value), | |
153 | + params.merge(:facet => params[:facet].reject{ |k,v| k == id })] | |
120 | 154 | end |
121 | - [cat, hits, childs] | |
122 | - end.select{|cat, hits| hits } | |
155 | + end | |
123 | 156 | |
124 | - render(:partial => 'product_categories_menu', :object => product_categories_menu) | |
157 | + ret.map do |label, name, url| | |
158 | + content_tag('div', content_tag('span', label, :class => 'facet-selected-label') + | |
159 | + content_tag('span', name, :class => 'facet-selected-name') + | |
160 | + link_to('', url, :class => 'facet-selected-remove'), :class => 'facet-selected') | |
161 | + end.join | |
162 | + end | |
163 | + | |
164 | + def order_by(asset) | |
165 | + options = SortOptions[asset].map do |name, options| | |
166 | + next if options[:if] and ! instance_eval(&options[:if]) | |
167 | + [_(options[:label]), name.to_s] | |
168 | + end.compact | |
169 | + | |
170 | + content_tag('div', _('Sort results by ') + | |
171 | + select_tag(asset.to_s + '[order]', options_for_select(options, params[:order_by] || 'none'), | |
172 | + {:onchange => "window.location = jQuery.param.querystring(window.location.href, { 'order_by' : this.options[this.selectedIndex].value})"}), | |
173 | + :class => "search-ordering") | |
174 | + end | |
175 | + | |
176 | + def label_total_found(asset, total_found) | |
177 | + labels = { | |
178 | + :products => _("%s products offers found"), | |
179 | + :articles => _("%s articles found"), | |
180 | + :events => _("%s events found"), | |
181 | + :people => _("%s people found"), | |
182 | + :enterprises => _("%s enterprises found"), | |
183 | + :communities => _("%s communities found"), | |
184 | + } | |
185 | + content_tag('span', labels[asset] % total_found, | |
186 | + :class => "total-pages-found") if labels[asset] | |
187 | + end | |
188 | + | |
189 | + def asset_class(asset) | |
190 | + asset.to_s.singularize.camelize.constantize | |
191 | + end | |
192 | + | |
193 | + def asset_table(asset) | |
194 | + asset_class(asset).table_name | |
125 | 195 | end |
126 | 196 | |
127 | 197 | end | ... | ... |
app/models/article.rb
... | ... | @@ -2,6 +2,12 @@ require 'hpricot' |
2 | 2 | |
3 | 3 | class Article < ActiveRecord::Base |
4 | 4 | |
5 | + # use for internationalizable human type names in search facets | |
6 | + # reimplement on subclasses | |
7 | + def self.type_name | |
8 | + _('Content') | |
9 | + end | |
10 | + | |
5 | 11 | track_actions :create_article, :after_create, :keep_params => [:name, :url], :if => Proc.new { |a| a.is_trackable? && !a.image? }, :custom_target => :action_tracker_target |
6 | 12 | track_actions :update_article, :before_update, :keep_params => [:name, :url], :if => Proc.new { |a| a.is_trackable? && (a.body_changed? || a.name_changed?) }, :custom_target => :action_tracker_target |
7 | 13 | track_actions :remove_article, :before_destroy, :keep_params => [:name], :if => Proc.new { |a| a.is_trackable? }, :custom_target => :action_tracker_target |
... | ... | @@ -22,6 +28,9 @@ class Article < ActiveRecord::Base |
22 | 28 | has_many :article_categorizations, :conditions => [ 'articles_categories.virtual = ?', false ] |
23 | 29 | has_many :categories, :through => :article_categorizations |
24 | 30 | |
31 | + has_many :article_categorizations_including_virtual, :class_name => 'ArticleCategorization' | |
32 | + has_many :categories_including_virtual, :through => :article_categorizations_including_virtual, :source => :category | |
33 | + | |
25 | 34 | acts_as_having_settings :field => :setting |
26 | 35 | |
27 | 36 | settings_items :display_hits, :type => :boolean, :default => true |
... | ... | @@ -108,6 +117,7 @@ class Article < ActiveRecord::Base |
108 | 117 | ids.uniq.each do |item| |
109 | 118 | add_category(Category.find(item)) unless item.to_i.zero? |
110 | 119 | end |
120 | + self.categories(true) | |
111 | 121 | end |
112 | 122 | |
113 | 123 | after_create :create_pending_categorizations |
... | ... | @@ -125,8 +135,6 @@ class Article < ActiveRecord::Base |
125 | 135 | |
126 | 136 | acts_as_versioned |
127 | 137 | |
128 | - acts_as_searchable :additional_fields => [ :comment_data ] | |
129 | - | |
130 | 138 | def comment_data |
131 | 139 | comments.map {|item| [item.title, item.body].join(' ') }.join(' ') |
132 | 140 | end |
... | ... | @@ -141,13 +149,31 @@ class Article < ActiveRecord::Base |
141 | 149 | {:conditions => [ 'parent_id is null and profile_id = ?', profile.id ]} |
142 | 150 | } |
143 | 151 | |
152 | + named_scope :public, | |
153 | + :conditions => [ "advertise = ? AND published = ? AND profiles.visible = ? AND profiles.public_profile = ?", true, true, true, true ] | |
154 | + | |
155 | + named_scope :more_recent, | |
156 | + :conditions => [ "advertise = ? AND published = ? AND profiles.visible = ? AND profiles.public_profile = ? AND | |
157 | + ((articles.type != ?) OR articles.type is NULL)", | |
158 | + true, true, true, true, 'RssFeed' | |
159 | + ], | |
160 | + :order => 'articles.published_at desc, articles.id desc' | |
161 | + | |
162 | + # retrives the most commented articles, sorted by the comment count (largest | |
163 | + # first) | |
164 | + def self.most_commented(limit) | |
165 | + paginate(:order => 'comments_count DESC', :page => 1, :per_page => limit) | |
166 | + end | |
167 | + | |
168 | + named_scope :more_popular, :order => 'hits DESC' | |
169 | + | |
144 | 170 | # retrieves the latest +limit+ articles, sorted from the most recent to the |
145 | 171 | # oldest. |
146 | 172 | # |
147 | 173 | # Only includes articles where advertise == true |
148 | - def self.recent(limit, extra_conditions = {}) | |
174 | + def self.recent(limit = nil, extra_conditions = {}) | |
149 | 175 | # FIXME this method is a horrible hack |
150 | - options = { :limit => limit, | |
176 | + options = { :page => 1, :per_page => limit, | |
151 | 177 | :conditions => [ |
152 | 178 | "advertise = ? AND |
153 | 179 | published = ? AND |
... | ... | @@ -165,20 +191,14 @@ class Article < ActiveRecord::Base |
165 | 191 | options.delete(:include) |
166 | 192 | end |
167 | 193 | if extra_conditions == {} |
168 | - self.find(:all, options) | |
194 | + self.paginate(options) | |
169 | 195 | else |
170 | 196 | with_scope :find => {:conditions => extra_conditions} do |
171 | - self.find(:all, options) | |
197 | + self.paginate(options) | |
172 | 198 | end |
173 | 199 | end |
174 | 200 | end |
175 | 201 | |
176 | - # retrives the most commented articles, sorted by the comment count (largest | |
177 | - # first) | |
178 | - def self.most_commented(limit) | |
179 | - find(:all, :order => 'comments_count DESC', :limit => limit) | |
180 | - end | |
181 | - | |
182 | 202 | # produces the HTML code that is to be displayed as this article's contents. |
183 | 203 | # |
184 | 204 | # The implementation in this class just provides the +body+ attribute as the |
... | ... | @@ -409,7 +429,7 @@ class Article < ActiveRecord::Base |
409 | 429 | end |
410 | 430 | |
411 | 431 | def comments_updated |
412 | - ferret_update | |
432 | + solr_save | |
413 | 433 | end |
414 | 434 | |
415 | 435 | def accept_category?(cat) |
... | ... | @@ -561,6 +581,92 @@ class Article < ActiveRecord::Base |
561 | 581 | |
562 | 582 | private |
563 | 583 | |
584 | + # FIXME: workaround for development env. | |
585 | + # Subclasses aren't (re)loaded, and acts_as_solr | |
586 | + # depends on subclasses method to search | |
587 | + # see http://stackoverflow.com/questions/4138957/activerecordsubclassnotfound-error-when-using-sti-in-rails/4139245 | |
588 | + UploadedFile | |
589 | + TextArticle | |
590 | + TinyMceArticle | |
591 | + TextileArticle | |
592 | + Folder | |
593 | + EnterpriseHomepage | |
594 | + Gallery | |
595 | + Blog | |
596 | + Forum | |
597 | + Event | |
598 | + | |
599 | + def self.f_type_proc(klass) | |
600 | + klass.constantize.type_name | |
601 | + end | |
602 | + def self.f_profile_type_proc(klass) | |
603 | + klass.constantize.type_name | |
604 | + end | |
605 | + | |
606 | + def f_type | |
607 | + #join common types | |
608 | + case self.class.name | |
609 | + when 'TinyMceArticle', 'TextileArticle' | |
610 | + TextArticle.name | |
611 | + else | |
612 | + self.class.name | |
613 | + end | |
614 | + end | |
615 | + def f_profile_type | |
616 | + self.profile.class.name | |
617 | + end | |
618 | + def f_published_at | |
619 | + self.published_at | |
620 | + end | |
621 | + def f_category | |
622 | + self.categories.collect(&:name) | |
623 | + end | |
624 | + | |
625 | + delegate :region, :region_id, :environment, :environment_id, :to => :profile | |
626 | + def name_sortable # give a different name for solr | |
627 | + name | |
628 | + end | |
629 | + def public | |
630 | + self.public? | |
631 | + end | |
632 | + def category_filter | |
633 | + categories_including_virtual_ids | |
634 | + end | |
635 | + public | |
636 | + | |
637 | + acts_as_faceted :fields => { | |
638 | + :f_type => {:label => _('Type'), :proc => proc{|klass| f_type_proc(klass)}}, | |
639 | + :f_published_at => {:type => :date, :label => _('Published date'), :queries => {'[* TO NOW-1YEARS/DAY]' => _("Older than one year"), | |
640 | + '[NOW-1YEARS TO NOW/DAY]' => _("Last year"), '[NOW-1MONTHS TO NOW/DAY]' => _("Last month"), '[NOW-7DAYS TO NOW/DAY]' => _("Last week"), '[NOW-1DAYS TO NOW/DAY]' => _("Last day")}, | |
641 | + :queries_order => ['[NOW-1DAYS TO NOW/DAY]', '[NOW-7DAYS TO NOW/DAY]', '[NOW-1MONTHS TO NOW/DAY]', '[NOW-1YEARS TO NOW/DAY]', '[* TO NOW-1YEARS/DAY]']}, | |
642 | + :f_profile_type => {:label => _('Profile'), :proc => proc{|klass| f_profile_type_proc(klass)}}, | |
643 | + :f_category => {:label => _('Categories')}, | |
644 | + }, :category_query => proc { |c| "category_filter:\"#{c.id}\"" }, | |
645 | + :order => [:f_type, :f_published_at, :f_profile_type, :f_category] | |
646 | + | |
647 | + acts_as_searchable :fields => facets_fields_for_solr + [ | |
648 | + # searched fields | |
649 | + {:name => {:type => :text, :boost => 2.0}}, | |
650 | + {:slug => :text}, {:body => :text}, | |
651 | + {:abstract => :text}, {:filename => :text}, | |
652 | + # filtered fields | |
653 | + {:public => :boolean}, {:environment_id => :integer}, | |
654 | + {:profile_id => :integer}, :language, | |
655 | + {:category_filter => :integer}, | |
656 | + # ordered/query-boosted fields | |
657 | + {:name_sortable => :string}, :last_changed_by_id, :published_at, :is_image, | |
658 | + :updated_at, :created_at, | |
659 | + ], :include => [ | |
660 | + {:profile => {:fields => [:name, :identifier, :address, :nickname, :region_id, :lat, :lng]}}, | |
661 | + {:comments => {:fields => [:title, :body, :author_name, :author_email]}}, | |
662 | + {:categories => {:fields => [:name, :path, :slug, :lat, :lng, :acronym, :abbreviation]}}, | |
663 | + ], :facets => facets_option_for_solr, | |
664 | + :boost => proc { |a| 10 if a.profile.enabled }, | |
665 | + :if => proc{ |a| ! ['RssFeed'].include?(a.class.name) } | |
666 | + handle_asynchronously :solr_save | |
667 | + | |
668 | + private | |
669 | + | |
564 | 670 | def sanitize_tag_list |
565 | 671 | sanitizer = HTML::FullSanitizer.new |
566 | 672 | self.tag_list.names.map!{|i| strip_tag_name sanitizer.sanitize(i) } | ... | ... |
app/models/blog.rb
app/models/category.rb
... | ... | @@ -15,13 +15,13 @@ class Category < ActiveRecord::Base |
15 | 15 | |
16 | 16 | acts_as_filesystem |
17 | 17 | |
18 | - has_many :article_categorizations | |
18 | + has_many :article_categorizations, :dependent => :destroy | |
19 | 19 | has_many :articles, :through => :article_categorizations |
20 | 20 | has_many :comments, :through => :articles |
21 | 21 | |
22 | 22 | has_many :events, :through => :article_categorizations, :class_name => 'Event', :source => :article |
23 | 23 | |
24 | - has_many :profile_categorizations | |
24 | + has_many :profile_categorizations, :dependent => :destroy | |
25 | 25 | has_many :enterprises, :through => :profile_categorizations, :source => :profile, :class_name => 'Enterprise' |
26 | 26 | has_many :people, :through => :profile_categorizations, :source => :profile, :class_name => 'Person' |
27 | 27 | has_many :communities, :through => :profile_categorizations, :source => :profile, :class_name => 'Community' |
... | ... | @@ -36,18 +36,38 @@ class Category < ActiveRecord::Base |
36 | 36 | { :conditions => [ "type IN (?) OR type IS NULL", types.reject{ |t| t.blank? } ] } |
37 | 37 | } |
38 | 38 | |
39 | + def recent_people(limit = 10) | |
40 | + self.people.paginate(:order => 'created_at DESC, id DESC', :page => 1, :per_page => limit) | |
41 | + end | |
42 | + | |
43 | + def recent_enterprises(limit = 10) | |
44 | + self.enterprises.paginate(:order => 'created_at DESC, id DESC', :page => 1, :per_page => limit) | |
45 | + end | |
46 | + | |
47 | + def recent_communities(limit = 10) | |
48 | + self.communities.paginate(:order => 'created_at DESC, id DESC', :page => 1, :per_page => limit) | |
49 | + end | |
50 | + | |
51 | + def recent_products(limit = 10) | |
52 | + self.products.paginate(:order => 'created_at DESC, id DESC', :page => 1, :per_page => limit) | |
53 | + end | |
54 | + | |
39 | 55 | def recent_articles(limit = 10) |
40 | 56 | self.articles.recent(limit) |
41 | 57 | end |
42 | 58 | |
43 | 59 | def recent_comments(limit = 10) |
44 | - comments.find(:all, :order => 'created_at DESC, comments.id DESC', :limit => limit) | |
60 | + comments.paginate(:all, :order => 'created_at DESC, comments.id DESC', :page => 1, :per_page => limit) | |
45 | 61 | end |
46 | 62 | |
47 | 63 | def most_commented_articles(limit = 10) |
48 | 64 | self.articles.most_commented(limit) |
49 | 65 | end |
50 | 66 | |
67 | + def upcoming_events(limit = 10) | |
68 | + self.events.paginate(:conditions => [ 'start_date >= ?', Date.today ], :order => 'start_date', :page => 1, :per_page => limit) | |
69 | + end | |
70 | + | |
51 | 71 | def display_in_menu? |
52 | 72 | display_in_menu |
53 | 73 | end |
... | ... | @@ -69,4 +89,23 @@ class Category < ActiveRecord::Base |
69 | 89 | self.children.find(:all, :conditions => {:display_in_menu => true}).empty? |
70 | 90 | end |
71 | 91 | |
92 | + private | |
93 | + def name_sortable # give a different name for solr | |
94 | + name | |
95 | + end | |
96 | + public | |
97 | + | |
98 | + acts_as_searchable :fields => [ | |
99 | + # searched fields | |
100 | + {:name => {:type => :text, :boost => 2.0}}, | |
101 | + {:path => :text}, {:slug => :text}, | |
102 | + {:abbreviation => :text}, {:acronym => :text}, | |
103 | + # filtered fields | |
104 | + :parent_id, | |
105 | + # ordered/query-boosted fields | |
106 | + {:name_sortable => :string}, | |
107 | + ] | |
108 | + after_save_reindex [:articles, :profiles], :with => :delayed_job | |
109 | + handle_asynchronously :solr_save | |
110 | + | |
72 | 111 | end | ... | ... |
app/models/category_finder.rb
... | ... | @@ -1,144 +0,0 @@ |
1 | -class CategoryFinder | |
2 | - | |
3 | - def initialize(cat) | |
4 | - @category = cat | |
5 | - @category_id = @category.id | |
6 | - end | |
7 | - | |
8 | - attr_reader :category_id | |
9 | - | |
10 | - def find(asset, query='', options={}) | |
11 | - @region = Region.find_by_id(options.delete(:region)) if options.has_key?(:region) | |
12 | - if @region && options[:within] | |
13 | - options[:origin] = [@region.lat, @region.lng] | |
14 | - else | |
15 | - options.delete(:within) | |
16 | - end | |
17 | - | |
18 | - date_range = options.delete(:date_range) | |
19 | - | |
20 | - options = {:page => 1, :per_page => options.delete(:limit)}.merge(options) | |
21 | - | |
22 | - if asset == :events | |
23 | - finder_method = 'find' | |
24 | - options.delete(:page) | |
25 | - options.delete(:per_page) | |
26 | - else | |
27 | - finder_method = 'paginate' | |
28 | - end | |
29 | - | |
30 | - if query.blank? | |
31 | - asset_class(asset).send(finder_method, :all, options_for_find(asset_class(asset), {:order => "#{asset_table(asset)}.name"}.merge(options), date_range)) | |
32 | - else | |
33 | - ferret_options = {:page => options.delete(:page), :per_page => options.delete(:per_page)} | |
34 | - asset_class(asset).find_by_contents(query, ferret_options, options_for_find(asset_class(asset), options, date_range)) | |
35 | - end | |
36 | - end | |
37 | - | |
38 | - def recent(asset, limit = nil) | |
39 | - find(asset, nil, :limit => limit, :order => 'created_at DESC, id DESC') | |
40 | - end | |
41 | - | |
42 | - def most_commented_articles(limit=10, options={}) | |
43 | - options = {:page => 1, :per_page => limit, :order => 'comments_count DESC'}.merge(options) | |
44 | - Article.paginate(:all, options_for_find(Article, options)) | |
45 | - end | |
46 | - | |
47 | - def current_events(year, month, options={}) | |
48 | - options.delete(:page) | |
49 | - options.delete(:per_page) | |
50 | - | |
51 | - range = Event.date_range(year, month) | |
52 | - | |
53 | - Event.find(:all, {:include => :categories, :conditions => { 'categories.id' => category_id, :start_date => range }}.merge(options)) | |
54 | - end | |
55 | - | |
56 | - def upcoming_events(options = {}) | |
57 | - options.delete(:page) | |
58 | - options.delete(:per_page) | |
59 | - | |
60 | - Event.find(:all, {:include => :categories, :conditions => [ 'categories.id = ? and start_date >= ?', category_id, Date.today ], :order => 'start_date' }.merge(options)) | |
61 | - end | |
62 | - | |
63 | - def product_categories_count(asset, product_categories_ids, objects_ids=nil) | |
64 | - conditions = [ "product_categorizations.category_id in (?) and #{ProfileCategorization.table_name}.category_id = ?", product_categories_ids, category_id] | |
65 | - | |
66 | - if asset == :products | |
67 | - if objects_ids | |
68 | - conditions[0] += ' and product_categorizations.product_id in (?)' | |
69 | - conditions << objects_ids | |
70 | - end | |
71 | - ProductCategory.find( | |
72 | - :all, | |
73 | - :select => 'categories.id, count(*) as total', | |
74 | - :joins => "inner join product_categorizations on (product_categorizations.category_id = categories.id) inner join products on (products.id = product_categorizations.product_id) inner join #{ProfileCategorization.table_name} on (#{ProfileCategorization.table_name}.profile_id = products.enterprise_id)", | |
75 | - :group => 'categories.id', | |
76 | - :conditions => conditions | |
77 | - ) | |
78 | - elsif asset == :enterprises | |
79 | - if objects_ids | |
80 | - conditions[0] += ' and products.enterprise_id in (?)' | |
81 | - conditions << objects_ids | |
82 | - end | |
83 | - ProductCategory.find( | |
84 | - :all, | |
85 | - :select => 'categories.id, count(distinct products.enterprise_id) as total', | |
86 | - :joins => "inner join product_categorizations on (product_categorizations.category_id = categories.id) inner join products on (products.id = product_categorizations.product_id) inner join #{ProfileCategorization.table_name} on (#{ProfileCategorization.table_name}.profile_id = products.enterprise_id)", | |
87 | - :group => 'categories.id', | |
88 | - :conditions => conditions | |
89 | - ) | |
90 | - else | |
91 | - raise ArgumentError, 'only products and enterprises supported' | |
92 | - end.inject({}) do |results,pc| | |
93 | - results[pc.id]= pc.total.to_i | |
94 | - results | |
95 | - end | |
96 | - end | |
97 | - | |
98 | - protected | |
99 | - | |
100 | - def options_for_find(klass, options={}, date_range = nil) | |
101 | - if defined? options[:product_category] | |
102 | - prod_cat = options.delete(:product_category) | |
103 | - end | |
104 | - | |
105 | - case klass.name | |
106 | - when 'Comment' | |
107 | - {:joins => 'inner join articles_categories on articles_categories.article_id = comments.article_id', :conditions => ['articles_categories.category_id = (?)', category_id]}.merge!(options) | |
108 | - when 'Product' | |
109 | - if prod_cat | |
110 | - {:joins => 'inner join categories_profiles on products.enterprise_id = categories_profiles.profile_id inner join product_categorizations on (product_categorizations.product_id = products.id)', :conditions => ['categories_profiles.category_id = (?) and product_categorizations.category_id = (?)', category_id, prod_cat.id]}.merge!(options) | |
111 | - else | |
112 | - {:joins => 'inner join categories_profiles on products.enterprise_id = categories_profiles.profile_id', :conditions => ['categories_profiles.category_id = (?)', category_id]}.merge!(options) | |
113 | - end | |
114 | - when 'Article', 'TextArticle' | |
115 | - {:joins => 'inner join articles_categories on (articles_categories.article_id = articles.id)', :conditions => ['articles_categories.category_id = (?)', category_id]}.merge!(options) | |
116 | - when 'Event' | |
117 | - conditions = | |
118 | - if date_range | |
119 | - ['articles_categories.category_id = (:category_id) and (start_date BETWEEN :start_day AND :end_day OR end_date BETWEEN :start_day AND :end_day)', {:category_id => category_id, :start_day => date_range.first, :end_day => date_range.last} ] | |
120 | - else | |
121 | - ['articles_categories.category_id = (?) ', category_id ] | |
122 | - end | |
123 | - {:joins => 'inner join articles_categories on (articles_categories.article_id = articles.id)', :conditions => conditions}.merge!(options) | |
124 | - when 'Enterprise' | |
125 | - if prod_cat | |
126 | - {:joins => 'inner join categories_profiles on (categories_profiles.profile_id = profiles.id) inner join products on (products.enterprise_id = profiles.id) inner join product_categorizations on (product_categorizations.product_id = products.id)', :conditions => ['categories_profiles.category_id = (?) and product_categorizations.category_id = (?)', category_id, prod_cat.id]}.merge!(options) | |
127 | - else | |
128 | - {:joins => 'inner join categories_profiles on (categories_profiles.profile_id = profiles.id)', :conditions => ['categories_profiles.category_id = (?)', category_id]}.merge!(options) | |
129 | - end | |
130 | - when 'Person', 'Community' | |
131 | - {:joins => 'inner join categories_profiles on (categories_profiles.profile_id = profiles.id)', :conditions => ['categories_profiles.category_id = (?)', category_id]}.merge!(options) | |
132 | - else | |
133 | - raise "unreconized class #{klass.name}" | |
134 | - end | |
135 | - end | |
136 | - | |
137 | - def asset_class(asset) | |
138 | - asset.to_s.singularize.camelize.constantize | |
139 | - end | |
140 | - | |
141 | - def asset_table(asset) | |
142 | - asset_class(asset).table_name | |
143 | - end | |
144 | -end |
app/models/certifier.rb
... | ... | @@ -2,12 +2,20 @@ class Certifier < ActiveRecord::Base |
2 | 2 | |
3 | 3 | belongs_to :environment |
4 | 4 | |
5 | - has_many :qualifier_certifiers | |
5 | + has_many :qualifier_certifiers, :dependent => :destroy | |
6 | 6 | has_many :qualifiers, :through => :qualifier_certifiers |
7 | 7 | |
8 | + has_many :product_qualifiers | |
9 | + has_many :products, :through => :product_qualifiers, :source => :product | |
10 | + | |
8 | 11 | validates_presence_of :environment_id |
9 | 12 | validates_presence_of :name |
10 | 13 | |
14 | + def destroy | |
15 | + product_qualifiers.each { |pq| pq.update_attributes! :certifier => nil } | |
16 | + super | |
17 | + end | |
18 | + | |
11 | 19 | def link |
12 | 20 | self[:link] || '' |
13 | 21 | end |
... | ... | @@ -16,4 +24,6 @@ class Certifier < ActiveRecord::Base |
16 | 24 | self.name.downcase.transliterate <=> b.name.downcase.transliterate |
17 | 25 | end |
18 | 26 | |
27 | + after_save_reindex [:products], :with => :delayed_job | |
28 | + | |
19 | 29 | end | ... | ... |
app/models/communities_block.rb
... | ... | @@ -21,7 +21,7 @@ class CommunitiesBlock < ProfileListBlock |
21 | 21 | end |
22 | 22 | when Environment |
23 | 23 | lambda do |
24 | - link_to s_('communities|View all'), :controller => 'browse', :action => 'communities' | |
24 | + link_to s_('communities|View all'), :controller => 'search', :action => 'communities' | |
25 | 25 | end |
26 | 26 | else |
27 | 27 | '' | ... | ... |
app/models/community.rb
1 | 1 | class Community < Organization |
2 | + | |
3 | + def self.type_name | |
4 | + _('Community') | |
5 | + end | |
6 | + | |
2 | 7 | N_('Community') |
3 | 8 | N_('Language') |
4 | 9 | |
5 | 10 | settings_items :language |
6 | 11 | settings_items :zip_code, :city, :state, :country |
7 | 12 | |
13 | + extend SetProfileRegionFromCityState::ClassMethods | |
14 | + set_profile_region_from_city_state | |
15 | + | |
8 | 16 | before_create do |community| |
9 | 17 | community.moderated_articles = true if community.environment.enabled?('organizations_are_moderated_by_default') |
10 | 18 | end | ... | ... |
app/models/domain.rb
... | ... | @@ -8,9 +8,9 @@ class Domain < ActiveRecord::Base |
8 | 8 | # validations |
9 | 9 | ############# |
10 | 10 | |
11 | - # <tt>name</tt> must be a sequence of word characters (a to z, plus 0 to 9, | |
12 | - # plus '_'). Letters must be lowercase | |
13 | - validates_format_of :name, :with => /^([a-z0-9_-]+\.)+[a-z0-9_-]+$/, :message => N_('%{fn} must be composed only of lowercase latters (a to z), numbers (0 to 9), "_" and "-"').fix_i18n | |
11 | + # <tt>name</tt> must be sequences of alphanumeric characters (a to z, | |
12 | + # 0 to 9), plus '_' or '-', separated by dots. Letters must be lowercase. | |
13 | + validates_format_of :name, :with => /^([a-z0-9_-]+\.)+[a-z0-9_-]+$/, :message => N_('%{fn} must be composed of sequences of lowercase letters (a to z), numbers (0 to 9), "_" and "-", separated by dots.').fix_i18n | |
14 | 14 | |
15 | 15 | # checks validations that could not be expressed using Rails' predefined |
16 | 16 | # validations. In particular: | ... | ... |
app/models/enterprise.rb
... | ... | @@ -2,6 +2,10 @@ |
2 | 2 | # only enterprises can offer products and services. |
3 | 3 | class Enterprise < Organization |
4 | 4 | |
5 | + def self.type_name | |
6 | + _('Enterprise') | |
7 | + end | |
8 | + | |
5 | 9 | N_('Enterprise') |
6 | 10 | |
7 | 11 | has_many :products, :dependent => :destroy, :order => 'name ASC' |
... | ... | @@ -10,12 +14,19 @@ class Enterprise < Organization |
10 | 14 | |
11 | 15 | has_and_belongs_to_many :fans, :class_name => 'Person', :join_table => 'favorite_enteprises_people' |
12 | 16 | |
17 | + after_save_reindex [:products], :with => :delayed_job | |
13 | 18 | extra_data_for_index :product_categories |
19 | + def product_categories | |
20 | + products.map{|p| p.category_full_name}.compact | |
21 | + end | |
14 | 22 | |
15 | 23 | N_('Organization website'); N_('Historic and current context'); N_('Activities short description'); N_('City'); N_('State'); N_('Country'); N_('ZIP code') |
16 | 24 | |
17 | 25 | settings_items :organization_website, :historic_and_current_context, :activities_short_description, :zip_code, :city, :state, :country |
18 | 26 | |
27 | + extend SetProfileRegionFromCityState::ClassMethods | |
28 | + set_profile_region_from_city_state | |
29 | + | |
19 | 30 | before_save do |enterprise| |
20 | 31 | enterprise.organization_website = enterprise.maybe_add_http(enterprise.organization_website) |
21 | 32 | end |
... | ... | @@ -67,22 +78,6 @@ class Enterprise < Organization |
67 | 78 | environment ? environment.signup_enterprise_fields : [] |
68 | 79 | end |
69 | 80 | |
70 | - def product_categories | |
71 | - products.map{|p| p.category_full_name}.compact | |
72 | - end | |
73 | - | |
74 | - def product_updated | |
75 | - ferret_update | |
76 | - end | |
77 | - | |
78 | - after_save do |e| | |
79 | - e.delay.update_products_position | |
80 | - end | |
81 | - | |
82 | - def update_products_position | |
83 | - products.each{ |p| p.enterprise_updated(self) } | |
84 | - end | |
85 | - | |
86 | 81 | def closed? |
87 | 82 | true |
88 | 83 | end |
... | ... | @@ -167,6 +162,10 @@ class Enterprise < Organization |
167 | 162 | end |
168 | 163 | end |
169 | 164 | |
165 | + def control_panel_settings_button | |
166 | + {:title => __('Enterprise Info and settings'), :icon => 'edit-profile-enterprise'} | |
167 | + end | |
168 | + | |
170 | 169 | settings_items :enable_contact_us, :type => :boolean, :default => true |
171 | 170 | |
172 | 171 | def enable_contact? | ... | ... |
app/models/enterprise_homepage.rb
app/models/environment.rb
... | ... | @@ -248,6 +248,10 @@ class Environment < ActiveRecord::Base |
248 | 248 | |
249 | 249 | settings_items :enabled_plugins, :type => Array, :default => [] |
250 | 250 | |
251 | + settings_items :search_hints, :type => Hash, :default => {} | |
252 | + | |
253 | + settings_items :top_level_category_as_facet_ids, :type => Array, :default => [] | |
254 | + | |
251 | 255 | def news_amount_by_folder=(amount) |
252 | 256 | settings[:news_amount_by_folder] = amount.to_i |
253 | 257 | end |
... | ... | @@ -354,11 +358,11 @@ class Environment < ActiveRecord::Base |
354 | 358 | end |
355 | 359 | |
356 | 360 | def terminology |
357 | - if self.settings[:terminology] | |
358 | - self.settings[:terminology].constantize.instance | |
359 | - else | |
361 | + #if self.settings[:terminology] | |
362 | + #self.settings[:terminology].constantize.instance | |
363 | + #else | |
360 | 364 | Noosfero.terminology |
361 | - end | |
365 | + #end | |
362 | 366 | end |
363 | 367 | |
364 | 368 | def terminology=(value) | ... | ... |
app/models/environment_finder.rb
... | ... | @@ -1,107 +0,0 @@ |
1 | -class EnvironmentFinder | |
2 | - | |
3 | - def initialize env | |
4 | - @environment = env | |
5 | - end | |
6 | - | |
7 | - def find(asset, query = nil, options={}, finder_method = 'paginate') | |
8 | - @region = Region.find_by_id(options.delete(:region)) if options.has_key?(:region) | |
9 | - if @region && options[:within] | |
10 | - options[:origin] = [@region.lat, @region.lng] | |
11 | - else | |
12 | - options.delete(:within) | |
13 | - end | |
14 | - | |
15 | - product_category = options.delete(:product_category) | |
16 | - | |
17 | - date_range = options.delete(:date_range) | |
18 | - | |
19 | - # FIXME this test is in more than one place | |
20 | - if finder_method == 'paginate' | |
21 | - options = {:page => 1, :per_page => options.delete(:limit)}.merge(options) | |
22 | - end | |
23 | - | |
24 | - if query.blank? | |
25 | - # FIXME this test is in more than one place | |
26 | - if finder_method == 'paginate' | |
27 | - options = {:order => "#{asset_table(asset)}.name"}.merge(options) | |
28 | - end | |
29 | - if product_category && asset == :products | |
30 | - @environment.send(asset).send(finder_method, :all, options.merge(:include => 'product_categorizations', :conditions => ['product_categorizations.category_id = (?)', product_category.id])) | |
31 | - elsif product_category && asset == :enterprises | |
32 | - @environment.send(asset).send(finder_method, :all, options.merge( :order => 'profiles.name', :joins => 'inner join products on (products.enterprise_id = profiles.id) inner join product_categorizations on (product_categorizations.product_id = products.id)', :conditions => ['product_categorizations.category_id = (?)', product_category.id])) | |
33 | - else | |
34 | - if asset == :events | |
35 | - # Ignore pagination for asset events | |
36 | - options.delete(:per_page) | |
37 | - options.delete(:page) | |
38 | - if date_range | |
39 | - @environment.send(asset).send('find', :all, options.merge(:conditions => [ | |
40 | - 'start_date BETWEEN :start_day AND :end_day OR end_date BETWEEN :start_day AND :end_day', | |
41 | - {:start_day => date_range.first, :end_day => date_range.last} | |
42 | - ])) | |
43 | - else | |
44 | - @environment.send(asset).send('find', :all, options) | |
45 | - end | |
46 | - else | |
47 | - @environment.send(asset).send(finder_method, :all, options) | |
48 | - end | |
49 | - end | |
50 | - else | |
51 | - ferret_options = {:page => options.delete(:page), :per_page => options.delete(:per_page)} | |
52 | - if product_category && asset == :products | |
53 | - # SECURITY no risk of SQL injection, since product_category_ids comes from trusted source | |
54 | - @environment.send(asset).find_by_contents(query, ferret_options, options.merge({:include => 'product_categorizations', :conditions => 'product_categorizations.category_id = (%s)' % product_category.id })) | |
55 | - elsif product_category && asset == :enterprises | |
56 | - @environment.send(asset).find_by_contents(query, ferret_options, options.merge(:joins => 'inner join products on products.enterprise_id = profiles.id inner join product_categorizations on (product_categorizations.product_id = products.id)', :conditions => "product_categorizations.category_id = (#{product_category.id})")) | |
57 | - else | |
58 | - @environment.send(asset).find_by_contents(query, ferret_options, options) | |
59 | - end | |
60 | - end | |
61 | - end | |
62 | - | |
63 | - def recent(asset, limit = nil) | |
64 | - find(asset, nil, :limit => limit) | |
65 | - end | |
66 | - | |
67 | - def product_categories_count(asset, product_categories_ids, objects_ids=nil) | |
68 | - conditions = ['product_categorizations.category_id in (?)', product_categories_ids] | |
69 | - | |
70 | - if asset == :products | |
71 | - if objects_ids | |
72 | - conditions[0] += ' and product_categorizations.product_id in (?)' | |
73 | - conditions << objects_ids | |
74 | - end | |
75 | - ProductCategory.find(:all, :select => 'categories.id, count(*) as total', :joins => 'inner join product_categorizations on (product_categorizations.category_id = categories.id)', :group => 'categories.id', :conditions => conditions ) | |
76 | - elsif asset == :enterprises | |
77 | - if objects_ids | |
78 | - conditions[0] += ' and products.enterprise_id in (?)' | |
79 | - conditions << objects_ids | |
80 | - end | |
81 | - ProductCategory.find( | |
82 | - :all, | |
83 | - :select => 'categories.id, count(distinct products.enterprise_id) as total', | |
84 | - :joins => 'inner join product_categorizations on (product_categorizations.category_id = categories.id) inner join products on (products.id = product_categorizations.product_id)', | |
85 | - :group => 'categories.id', | |
86 | - :conditions => conditions | |
87 | - ) | |
88 | - else | |
89 | - raise ArgumentError, 'only products and enterprises supported' | |
90 | - end.inject({}) do |results,pc| | |
91 | - results[pc.id]= pc.total.to_i | |
92 | - results | |
93 | - end | |
94 | - | |
95 | - end | |
96 | - | |
97 | - protected | |
98 | - | |
99 | - def asset_class(asset) | |
100 | - asset.to_s.singularize.camelize.constantize | |
101 | - end | |
102 | - | |
103 | - def asset_table(asset) | |
104 | - asset_class(asset).table_name | |
105 | - end | |
106 | - | |
107 | -end |
app/models/event.rb
app/models/folder.rb
app/models/forum.rb
app/models/gallery.rb
app/models/google_maps.rb
1 | 1 | class GoogleMaps |
2 | 2 | |
3 | - extend ActionView::Helpers::TagHelper | |
4 | - | |
5 | - class << self | |
6 | - | |
7 | - include ApplicationHelper | |
8 | - | |
9 | - def enabled?(domain) | |
10 | - domain = Domain.find_by_name(domain) | |
11 | - domain ? !domain.google_maps_key.nil? : false | |
12 | - end | |
13 | - | |
14 | - def key(domainname) | |
15 | - domain = Domain.find_by_name(domainname) | |
16 | - domain && domain.google_maps_key || '' | |
17 | - end | |
18 | - | |
19 | - def initial_zoom | |
20 | - NOOSFERO_CONF['googlemaps_initial_zoom'] || 4 | |
21 | - end | |
22 | - | |
23 | - def api_url(domain) | |
24 | - "http://maps.google.com/maps?file=api&v=2&key=#{key(domain)}" | |
25 | - end | |
26 | - | |
3 | + def self.initial_zoom | |
4 | + NOOSFERO_CONF['googlemaps_initial_zoom'] || 4 | |
27 | 5 | end |
6 | + | |
28 | 7 | end | ... | ... |
app/models/image.rb
app/models/location_block.rb
... | ... | @@ -17,10 +17,10 @@ class LocationBlock < Block |
17 | 17 | if profile.lat |
18 | 18 | block_title(title) + |
19 | 19 | content_tag('div', |
20 | - '<img src="http://maps.google.com/staticmap?center=' + profile.lat.to_s() + | |
20 | + '<img src="http://maps.google.com/maps/api/staticmap?center=' + profile.lat.to_s() + | |
21 | 21 | ',' + profile.lng.to_s() + '&zoom=' + zoom.to_s() + |
22 | 22 | '&size=190x250&maptype=' + map_type + '&markers=' + profile.lat.to_s() + ',' + |
23 | - profile.lng.to_s() + ',green&key=' + GoogleMaps::key(profile.default_hostname) + '&sensor=false"/>', | |
23 | + profile.lng.to_s() + ',green' + '&sensor=false"/>', | |
24 | 24 | :class => 'the-localization-map' ) |
25 | 25 | else |
26 | 26 | content_tag('i', _('This profile has no geographical position registered.')) | ... | ... |
... | ... | @@ -0,0 +1,76 @@ |
1 | +class NationalRegion < ActiveRecord::Base | |
2 | + | |
3 | + def self.search_city(city_name, like = false, state = nil) | |
4 | + | |
5 | + operator = "=" | |
6 | + find_return = :first | |
7 | + adtional_contions = ""; | |
8 | + | |
9 | + if like | |
10 | + operator = "like" | |
11 | + find_return = :all | |
12 | + end | |
13 | + | |
14 | + if state | |
15 | + adtional_contions = " AND nr.name = :state " | |
16 | + end | |
17 | + | |
18 | + | |
19 | + conditions = ["national_regions.name #{operator} :name AND | |
20 | + national_regions.national_region_type_id = :type" + adtional_contions, | |
21 | + {:name => city_name , | |
22 | + :type => NationalRegionType::CITY, | |
23 | + :state => state}]; | |
24 | + | |
25 | + region = NationalRegion.find(find_return, | |
26 | + :select => "national_regions.name as city, nr.name as state, national_regions.national_region_code", | |
27 | + :conditions => conditions, | |
28 | + :joins => "LEFT JOIN national_regions as nr ON national_regions.parent_national_region_code = nr.national_region_code", | |
29 | + :limit => 10 | |
30 | + ) | |
31 | + return region | |
32 | + end | |
33 | + | |
34 | + def self.search_state(state_name, like = false) | |
35 | + operator = "=" | |
36 | + find_return = :first | |
37 | + | |
38 | + if like | |
39 | + operator = "like" | |
40 | + find_return = :all | |
41 | + end | |
42 | + | |
43 | + conditions = ["national_regions.name #{operator} :name AND | |
44 | + national_regions.national_region_type_id = :type", | |
45 | + {:name => state_name, | |
46 | + :type => NationalRegionType::STATE}]; | |
47 | + | |
48 | + region = NationalRegion.find(find_return, | |
49 | + :select => "national_regions.name as state, national_regions.national_region_code", | |
50 | + :conditions => conditions, | |
51 | + :limit => 10 | |
52 | + ) | |
53 | + return region | |
54 | + end | |
55 | + | |
56 | + def self.validate!(city, state, country) | |
57 | + | |
58 | + country_region = NationalRegion.find_by_national_region_code(country, | |
59 | + :conditions => ["national_region_type_id = :type", | |
60 | + {:type => NationalRegionType::COUNTRY}]) | |
61 | + | |
62 | + if(country_region) | |
63 | + | |
64 | + nregion = NationalRegion.search_city(city, false, state); | |
65 | + | |
66 | + if nregion == nil | |
67 | + raise _('Invalid city or state name.') | |
68 | + end | |
69 | + | |
70 | + end | |
71 | + | |
72 | + return nregion | |
73 | + | |
74 | + end | |
75 | + | |
76 | +end | ... | ... |
app/models/people_block.rb
app/models/person.rb
1 | 1 | # A person is the profile of an user holding all relationships with the rest of the system |
2 | 2 | class Person < Profile |
3 | 3 | |
4 | + def self.type_name | |
5 | + _('Person') | |
6 | + end | |
7 | + | |
4 | 8 | acts_as_trackable :after_add => Proc.new {|p,t| notify_activity(t)} |
5 | 9 | acts_as_accessor |
6 | 10 | |
... | ... | @@ -173,6 +177,9 @@ class Person < Profile |
173 | 177 | N_('Contact information'); N_('City'); N_('State'); N_('Country'); N_('Sex'); N_('Zip code') |
174 | 178 | settings_items :photo, :contact_information, :sex, :city, :state, :country, :zip_code |
175 | 179 | |
180 | + extend SetProfileRegionFromCityState::ClassMethods | |
181 | + set_profile_region_from_city_state | |
182 | + | |
176 | 183 | def self.conditions_for_profiles(conditions, person) |
177 | 184 | new_conditions = sanitize_sql(['role_assignments.accessor_id = ?', person]) |
178 | 185 | new_conditions << ' AND ' + sanitize_sql(conditions) unless conditions.blank? | ... | ... |
app/models/product.rb
1 | 1 | class Product < ActiveRecord::Base |
2 | 2 | belongs_to :enterprise |
3 | + has_one :region, :through => :enterprise | |
4 | + validates_presence_of :enterprise | |
5 | + | |
3 | 6 | belongs_to :product_category |
4 | - has_many :product_categorizations | |
5 | - has_many :product_qualifiers | |
6 | - has_many :qualifiers, :through => :product_qualifiers | |
7 | + | |
7 | 8 | has_many :inputs, :dependent => :destroy, :order => 'position' |
8 | 9 | has_many :price_details, :dependent => :destroy |
9 | 10 | has_many :production_costs, :through => :price_details |
10 | 11 | |
12 | + has_many :product_qualifiers, :dependent => :destroy | |
13 | + has_many :qualifiers, :through => :product_qualifiers | |
14 | + has_many :certifiers, :through => :product_qualifiers | |
15 | + | |
11 | 16 | validates_uniqueness_of :name, :scope => :enterprise_id, :allow_nil => true |
12 | 17 | validates_presence_of :product_category_id |
13 | 18 | validates_associated :product_category |
... | ... | @@ -15,35 +20,20 @@ class Product < ActiveRecord::Base |
15 | 20 | validates_numericality_of :price, :allow_nil => true |
16 | 21 | validates_numericality_of :discount, :allow_nil => true |
17 | 22 | |
18 | - after_update :save_image | |
23 | + named_scope :more_recent, :order => "updated_at DESC" | |
19 | 24 | |
20 | - before_create do |p| | |
21 | - if p.enterprise | |
22 | - p['lat'] = p.enterprise.lat | |
23 | - p['lng'] = p.enterprise.lng | |
24 | - end | |
25 | - end | |
25 | + after_update :save_image | |
26 | 26 | |
27 | - after_save do |p| | |
28 | - p.enterprise.product_updated if p.enterprise | |
27 | + def lat | |
28 | + self.enterprise.lat | |
29 | 29 | end |
30 | - | |
31 | - after_save do |p| | |
32 | - if (p.product_category && !ProductCategorization.find(:first, :conditions => {:category_id => p.product_category.id, :product_id => p.id})) || (!p.product_category) | |
33 | - ProductCategorization.remove_all_for(p) | |
34 | - if p.product_category | |
35 | - ProductCategorization.add_category_to_product(p.product_category, p) | |
36 | - end | |
37 | - end | |
30 | + def lng | |
31 | + self.enterprise.lng | |
38 | 32 | end |
39 | 33 | |
40 | - acts_as_searchable :fields => [ :name, :description, :category_full_name ] | |
41 | - | |
42 | 34 | xss_terminate :only => [ :name ], :on => 'validation' |
43 | 35 | xss_terminate :only => [ :description ], :with => 'white_list', :on => 'validation' |
44 | 36 | |
45 | - acts_as_mappable | |
46 | - | |
47 | 37 | belongs_to :unit |
48 | 38 | |
49 | 39 | include FloatHelper |
... | ... | @@ -89,18 +79,12 @@ class Product < ActiveRecord::Base |
89 | 79 | self.find(:all, :order => 'id desc', :limit => limit) |
90 | 80 | end |
91 | 81 | |
92 | - def enterprise_updated(e) | |
93 | - self.lat = e.lat | |
94 | - self.lng = e.lng | |
95 | - save! | |
96 | - end | |
97 | - | |
98 | 82 | def url |
99 | 83 | enterprise.public_profile_url.merge(:controller => 'manage_products', :action => 'show', :id => id) |
100 | 84 | end |
101 | 85 | |
102 | 86 | def public? |
103 | - enterprise.public_profile | |
87 | + enterprise.public? | |
104 | 88 | end |
105 | 89 | |
106 | 90 | def formatted_value(method) |
... | ... | @@ -128,7 +112,6 @@ class Product < ActiveRecord::Base |
128 | 112 | end |
129 | 113 | end |
130 | 114 | |
131 | - # Note: will probably be completely overhauled for AI1413 | |
132 | 115 | def inputs_prices? |
133 | 116 | return false if self.inputs.count <= 0 |
134 | 117 | self.inputs.each do |input| |
... | ... | @@ -213,4 +196,100 @@ class Product < ActiveRecord::Base |
213 | 196 | url_for({:host => enterprise.default_hostname, :controller => 'manage_products', :action => 'display_inputs_cost', :profile => enterprise.identifier, :id => self.id }.merge(Noosfero.url_options)) |
214 | 197 | end |
215 | 198 | |
199 | + def percentage_from_solidarity_economy | |
200 | + se_i = t_i = 0 | |
201 | + self.inputs.each{ |i| t_i += 1; se_i += 1 if i.is_from_solidarity_economy } | |
202 | + p = case (se_i.to_f/t_i)*100 | |
203 | + when 0..24.999 then [0, _("")]; | |
204 | + when 25..49.999 then [25, _("25%")]; | |
205 | + when 50..74.999 then [50, _("50%")]; | |
206 | + when 75..99.999 then [75, _("75%")]; | |
207 | + when 100 then [100, _("100%")]; | |
208 | + end | |
209 | + end | |
210 | + | |
211 | + private | |
212 | + def f_category | |
213 | + self.product_category.name | |
214 | + end | |
215 | + def f_region | |
216 | + self.enterprise.region.id if self.enterprise.region | |
217 | + end | |
218 | + def self.f_region_proc(id) | |
219 | + c = Region.find(id) | |
220 | + s = c.parent | |
221 | + if c and c.kind_of?(City) and s and s.kind_of?(State) and s.acronym | |
222 | + [c.name, ', ' + s.acronym] | |
223 | + else | |
224 | + c.name | |
225 | + end | |
226 | + end | |
227 | + def self.f_qualifier_proc(ids) | |
228 | + array = ids.split ' ' | |
229 | + qualifier = Qualifier.find_by_id array[0] | |
230 | + certifier = Certifier.find_by_id array[1] | |
231 | + certifier ? [qualifier.name, _(' cert. ') + certifier.name] : qualifier.name | |
232 | + end | |
233 | + def f_qualifier | |
234 | + product_qualifiers.map do |pq| | |
235 | + "#{pq.qualifier_id} #{pq.certifier_id}" | |
236 | + end | |
237 | + end | |
238 | + | |
239 | + alias_method :name_sortable, :name | |
240 | + delegate :region, :region_id, :environment, :environment_id, :to => :enterprise | |
241 | + def name_sortable # give a different name for solr | |
242 | + name | |
243 | + end | |
244 | + def public | |
245 | + self.public? | |
246 | + end | |
247 | + def price_sortable | |
248 | + (price.nil? or price.zero?) ? nil : price | |
249 | + end | |
250 | + def category_filter | |
251 | + enterprise.categories_including_virtual_ids << product_category_id | |
252 | + end | |
253 | + public | |
254 | + | |
255 | + acts_as_faceted :fields => { | |
256 | + :f_category => {:label => _('Related products')}, | |
257 | + :f_region => {:label => _('City'), :proc => proc { |id| f_region_proc(id) }}, | |
258 | + :f_qualifier => {:label => _('Qualifiers'), :proc => proc { |id| f_qualifier_proc(id) }}, | |
259 | + }, :category_query => proc { |c| "category_filter:#{c.id}" }, | |
260 | + :order => [:f_category, :f_region, :f_qualifier] | |
261 | + | |
262 | + Boosts = [ | |
263 | + [:image, 0.4, proc{ |p| p.image ? 1 : 0}], | |
264 | + [:qualifiers, 0.3, proc{ |p| p.product_qualifiers.count > 0 ? 1 : 0}], | |
265 | + [:open_price, 0.3, proc{ |p| p.price_described? ? 1 : 0}], | |
266 | + [:solidarity, 0.3, proc{ |p| p.inputs.count > 0 ? p.percentage_from_solidarity_economy[0]/100 : 0 }], | |
267 | + [:available, 0.2, proc{ |p| p.available ? 1 : 0}], | |
268 | + [:price, 0.2, proc{ |p| (!p.price.nil? and p.price > 0) ? 1 : 0}], | |
269 | + [:new_product, 0.2, proc{ |p| (p.updated_at.to_i - p.created_at.to_i) < 24*3600 ? 1 : 0}], | |
270 | + [:description, 0.15, proc{ |p| (!p.description.nil? and !p.description.empty?) ? 1 : 0}], | |
271 | + [:enabled, 0.05, proc{ |p| p.enterprise.enabled ? 1 : 0}], | |
272 | + ] | |
273 | + | |
274 | + acts_as_searchable :fields => facets_fields_for_solr + [ | |
275 | + # searched fields | |
276 | + {:name => {:type => :text, :boost => 2.0}}, | |
277 | + {:description => :text}, | |
278 | + # filtered fields | |
279 | + {:public => :boolean}, {:environment_id => :integer}, | |
280 | + {:category_filter => :integer}, | |
281 | + # ordered/query-boosted fields | |
282 | + {:price_sortable => :decimal}, {:name_sortable => :string}, | |
283 | + {:lat => :float}, {:lng => :float}, | |
284 | + :updated_at, :created_at, | |
285 | + ], :include => [ | |
286 | + {:product_category => {:fields => [:name, :path, :slug, :lat, :lng, :acronym, :abbreviation]}}, | |
287 | + {:region => {:fields => [:name, :path, :slug, :lat, :lng]}}, | |
288 | + {:enterprise => {:fields => [:name, :identifier, :address, :nickname, :lat, :lng]}}, | |
289 | + {:qualifiers => {:fields => [:name]}}, | |
290 | + {:certifiers => {:fields => [:name]}}, | |
291 | + ], :facets => facets_option_for_solr, | |
292 | + :boost => proc{ |p| boost = 1; Boosts.each{ |b| boost = boost * (1 - ((1 - b[2].call(p)) * b[1])) }; boost} | |
293 | + handle_asynchronously :solr_save | |
294 | + | |
216 | 295 | end | ... | ... |
app/models/product_categorization.rb
... | ... | @@ -1,13 +0,0 @@ |
1 | -class ProductCategorization < ActiveRecord::Base | |
2 | - belongs_to :product_category, :foreign_key => 'category_id' | |
3 | - belongs_to :product | |
4 | - | |
5 | - extend Categorization | |
6 | - | |
7 | - class << self | |
8 | - alias :add_category_to_product :add_category_to_object | |
9 | - def object_id_column | |
10 | - :product_id | |
11 | - end | |
12 | - end | |
13 | -end |
app/models/product_category.rb
1 | 1 | class ProductCategory < Category |
2 | + # FIXME: do not allow category with products or inputs to be destroyed | |
2 | 3 | has_many :products |
3 | 4 | has_many :inputs |
4 | 5 | |
... | ... | @@ -9,4 +10,7 @@ class ProductCategory < Category |
9 | 10 | def self.menu_categories(top_category, env) |
10 | 11 | top_category ? top_category.children : top_level_for(env).select{|c|c.kind_of?(ProductCategory)} |
11 | 12 | end |
13 | + | |
14 | + after_save_reindex [:products], :with => :delayed_job | |
15 | + | |
12 | 16 | end | ... | ... |
app/models/profile.rb
... | ... | @@ -3,6 +3,12 @@ |
3 | 3 | # which by default is the one returned by Environment:default. |
4 | 4 | class Profile < ActiveRecord::Base |
5 | 5 | |
6 | + # use for internationalizable human type names in search facets | |
7 | + # reimplement on subclasses | |
8 | + def self.type_name | |
9 | + _('Profile') | |
10 | + end | |
11 | + | |
6 | 12 | module Roles |
7 | 13 | def self.admin(env_id) |
8 | 14 | find_role('admin', env_id) |
... | ... | @@ -74,8 +80,6 @@ class Profile < ActiveRecord::Base |
74 | 80 | |
75 | 81 | acts_as_having_boxes |
76 | 82 | |
77 | - acts_as_searchable :additional_fields => [ :extra_data_for_index ] | |
78 | - | |
79 | 83 | acts_as_taggable |
80 | 84 | |
81 | 85 | def self.qualified_column_names |
... | ... | @@ -125,8 +129,6 @@ class Profile < ActiveRecord::Base |
125 | 129 | |
126 | 130 | validates_length_of :description, :maximum => 550, :allow_nil => true |
127 | 131 | |
128 | - acts_as_mappable :default_units => :kms | |
129 | - | |
130 | 132 | # Valid identifiers must match this format. |
131 | 133 | IDENTIFIER_FORMAT = /^#{Noosfero.identifier_format}$/ |
132 | 134 | |
... | ... | @@ -181,8 +183,20 @@ class Profile < ActiveRecord::Base |
181 | 183 | has_many :profile_categorizations, :conditions => [ 'categories_profiles.virtual = ?', false ] |
182 | 184 | has_many :categories, :through => :profile_categorizations |
183 | 185 | |
186 | + has_many :profile_categorizations_including_virtual, :class_name => 'ProfileCategorization' | |
187 | + has_many :categories_including_virtual, :through => :profile_categorizations_including_virtual, :source => :category | |
188 | + | |
184 | 189 | has_many :abuse_complaints, :foreign_key => 'requestor_id' |
185 | 190 | |
191 | + def top_level_categorization | |
192 | + ret = {} | |
193 | + self.profile_categorizations.each do |c| | |
194 | + p = c.category.top_ancestor | |
195 | + ret[p] = (ret[p] || []) + [c.category] | |
196 | + end | |
197 | + ret | |
198 | + end | |
199 | + | |
186 | 200 | def interests |
187 | 201 | categories.select {|item| !item.is_a?(Region)} |
188 | 202 | end |
... | ... | @@ -822,18 +836,89 @@ private :generate_url, :url_options |
822 | 836 | name |
823 | 837 | end |
824 | 838 | |
825 | - protected | |
826 | - | |
827 | - def followed_by?(person) | |
828 | - person.is_member_of?(self) | |
839 | + private | |
840 | + def self.f_categories_label_proc(environment) | |
841 | + ids = environment.top_level_category_as_facet_ids | |
842 | + r = Category.find(ids) | |
843 | + map = {} | |
844 | + ids.map{ |id| map[id.to_s] = r.detect{|c| c.id == id}.name } | |
845 | + map | |
846 | + end | |
847 | + def self.f_categories_proc(facet, id) | |
848 | + id = id.to_i | |
849 | + return if id.zero? | |
850 | + c = Category.find(id) | |
851 | + c.name if c.top_ancestor.id == facet[:label_id].to_i or facet[:label_id] == 0 | |
852 | + end | |
853 | + def f_categories | |
854 | + category_ids | |
855 | + end | |
856 | + def f_region | |
857 | + self.region_id | |
858 | + end | |
859 | + def self.f_region_proc(id) | |
860 | + c = Region.find(id) | |
861 | + s = c.parent | |
862 | + if c and c.kind_of?(City) and s and s.kind_of?(State) and s.acronym | |
863 | + [c.name, ', ' + s.acronym] | |
864 | + else | |
865 | + c.name | |
829 | 866 | end |
867 | + end | |
830 | 868 | |
831 | - def display_private_info_to?(user) | |
832 | - if user.nil? | |
833 | - false | |
834 | - else | |
835 | - (user == self) || (user.is_admin?(self.environment)) || user.is_admin?(self) || user.memberships.include?(self) | |
836 | - end | |
869 | + def name_sortable # give a different name for solr | |
870 | + name | |
871 | + end | |
872 | + def public | |
873 | + self.public? | |
874 | + end | |
875 | + def category_filter | |
876 | + categories_including_virtual_ids | |
877 | + end | |
878 | + public | |
879 | + | |
880 | + acts_as_faceted :fields => { | |
881 | + :f_region => {:label => _('City'), :proc => proc { |id| f_region_proc(id) }}, | |
882 | + :f_categories => {:multi => true, :proc => proc {|facet, id| f_categories_proc(facet, id)}, | |
883 | + :label => proc { |env| f_categories_label_proc(env) }, :label_abbrev => proc{ |env| f_categories_label_abbrev_proc(env) }}, | |
884 | + }, :category_query => proc { |c| "category_filter:#{c.id}" }, | |
885 | + :order => [:f_region, :f_categories] | |
886 | + | |
887 | + acts_as_searchable :fields => facets_fields_for_solr + [:extra_data_for_index, | |
888 | + # searched fields | |
889 | + {:name => {:type => :text, :boost => 2.0}}, | |
890 | + {:identifier => :text}, {:address => :text}, {:nickname => :text}, | |
891 | + # filtered fields | |
892 | + {:public => :boolean}, {:environment_id => :integer}, | |
893 | + {:category_filter => :integer}, | |
894 | + # ordered/query-boosted fields | |
895 | + {:name_sortable => :string}, {:user_id => :integer}, | |
896 | + :enabled, :active, :validated, :public_profile, | |
897 | + {:lat => :float}, {:lng => :float}, | |
898 | + :updated_at, :created_at, | |
899 | + ], | |
900 | + :include => [ | |
901 | + {:region => {:fields => [:name, :path, :slug, :lat, :lng]}}, | |
902 | + {:categories => {:fields => [:name, :path, :slug, :lat, :lng, :acronym, :abbreviation]}}, | |
903 | + ], :facets => facets_option_for_solr, | |
904 | + :boost => proc{ |p| 10 if p.enabled } | |
905 | + after_save_reindex [:articles], :with => :delayed_job | |
906 | + handle_asynchronously :solr_save | |
907 | + | |
908 | + def control_panel_settings_button | |
909 | + {:title => _('Profile Info and settings'), :icon => 'edit-profile'} | |
910 | + end | |
911 | + | |
912 | + def followed_by?(person) | |
913 | + person.is_member_of?(self) | |
914 | + end | |
915 | + | |
916 | + def display_private_info_to?(user) | |
917 | + if user.nil? | |
918 | + false | |
919 | + else | |
920 | + (user == self) || (user.is_admin?(self.environment)) || user.is_admin?(self) || user.memberships.include?(self) | |
837 | 921 | end |
922 | + end | |
838 | 923 | |
839 | 924 | end | ... | ... |
app/models/qualifier.rb
... | ... | @@ -2,16 +2,19 @@ class Qualifier < ActiveRecord::Base |
2 | 2 | |
3 | 3 | belongs_to :environment |
4 | 4 | |
5 | - has_many :qualifier_certifiers | |
5 | + has_many :qualifier_certifiers, :dependent => :destroy | |
6 | 6 | has_many :certifiers, :through => :qualifier_certifiers |
7 | 7 | |
8 | + has_many :product_qualifiers, :dependent => :destroy | |
9 | + has_many :products, :through => :product_qualifiers, :source => :product | |
10 | + | |
8 | 11 | validates_presence_of :environment_id |
9 | 12 | validates_presence_of :name |
10 | 13 | |
11 | - has_many :product_qualifiers, :dependent => :destroy | |
12 | - | |
13 | 14 | def <=>(b) |
14 | 15 | self.name.downcase.transliterate <=> b.name.downcase.transliterate |
15 | 16 | end |
16 | 17 | |
18 | + after_save_reindex [:products], :with => :delayed_job | |
19 | + | |
17 | 20 | end | ... | ... |
app/models/qualifier_certifier.rb
app/models/raw_html_article.rb
app/models/region.rb
... | ... | @@ -5,10 +5,9 @@ class Region < Category |
5 | 5 | require_dependency 'enterprise' # enterprises can also be validators |
6 | 6 | |
7 | 7 | # searches for organizations that could become validators for this region. |
8 | - # <tt>search</tt> is passed as is to ferret's find_by_contents on Organizatio | |
9 | - # find_by_contents on Organization class. | |
8 | + # <tt>search</tt> is passed as is to find_by_contents on Organization. | |
10 | 9 | def search_possible_validators(search) |
11 | - Organization.find_by_contents(search).reject {|item| self.validator_ids.include?(item.id) } | |
10 | + Organization.find_by_contents(search)[:results].reject {|item| self.validator_ids.include?(item.id) } | |
12 | 11 | end |
13 | 12 | |
14 | 13 | def has_validator? | ... | ... |
app/models/rss_feed.rb
app/models/text_article.rb
app/models/textile_article.rb
app/models/tiny_mce_article.rb
app/models/uploaded_file.rb
... | ... | @@ -4,6 +4,10 @@ |
4 | 4 | # of the file itself is kept. (FIXME?) |
5 | 5 | class UploadedFile < Article |
6 | 6 | |
7 | + def self.type_name | |
8 | + _('File') | |
9 | + end | |
10 | + | |
7 | 11 | track_actions :upload_image, :after_create, :keep_params => ["view_url", "thumbnail_path", "parent.url", "parent.name"], :if => Proc.new { |a| a.published? && a.image? && !a.parent.nil? && a.parent.gallery? } |
8 | 12 | |
9 | 13 | include ShortFilename | ... | ... |
app/views/account/signup.rhtml
... | ... | @@ -5,7 +5,7 @@ |
5 | 5 | <p><%= _("Firstly, some tips for getting started:") %></p> |
6 | 6 | <h4><%= _("Confirm your account!") %></h4> |
7 | 7 | <p><%= _("You should receive a welcome email from us shortly. Please take a second to follow the link within to confirm your account.") %></p> |
8 | - <p><%= _("You won't appear as %s until your account is confirmed.") % link_to(_('user'), {:controller => :browse, :action => :people, :filter => 'more_recent'}, :target => '_blank') %></p> | |
8 | + <p><%= _("You won't appear as %s until your account is confirmed.") % link_to(_('user'), {:controller => :search, :action => :people, :filter => 'more_recent'}, :target => '_blank') %></p> | |
9 | 9 | <h4><%= _("What to do next?") %></h4> |
10 | 10 | <p><%= _("%s. Upload an avatar and let your friends find you easily :)") % link_to(_('Customize your profile'), {:controller => 'doc', :section => 'user', :topic => 'editing-person-info'}, :target => '_blank') %></p> |
11 | 11 | <p><%= _("Learn the guidelines. Read the %s for more details on how to use this social network!") % link_to(_('Documentation'), {:controller => 'doc'}, :target => '_blank') %></p> | ... | ... |
app/views/browse/_article.rhtml
... | ... | @@ -1,11 +0,0 @@ |
1 | -<li class="<%= 'browse-results-type-content ' + icon_for_article(result) %>"> | |
2 | - <strong><%= link_to(result.title, result.view_url) %></strong> | |
3 | - <div class="item_meta"> | |
4 | - <span class="item_by"> | |
5 | - <%= _('by %s') % link_to(result.author.name, result.author.url) %> | |
6 | - </span> | |
7 | - <span class="extra-info"> | |
8 | - <%= (@filter == 'more_recent' ? result.send(@filter + '_label') + show_date(result.created_at) : result.send(@filter + '_label')) %> | |
9 | - </span> | |
10 | - </div> | |
11 | -</li> |
app/views/browse/_display_results.rhtml
... | ... | @@ -1,19 +0,0 @@ |
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 => {:result => 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 | - |
app/views/browse/_person.rhtml
app/views/browse/_profile.rhtml
... | ... | @@ -1 +0,0 @@ |
1 | -<%= profile_image_link result, :portrait, 'li', @filter == 'more_recent' ? result.send(@filter + '_label') + show_date(result.created_at) : result.send(@filter + '_label') %> |
app/views/browse/_search_form.rhtml
... | ... | @@ -1,10 +0,0 @@ |
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 %> |
app/views/browse/communities.rhtml
app/views/browse/contents.rhtml
app/views/browse/people.rhtml
app/views/events/events.rhtml
1 | -<h1 id='agenda-title'> | |
2 | - <div id='agenda-toolbar'> | |
3 | - <%= button :back, _('Back to %s') % profile.name, profile.url %> | |
4 | - <% if user && user.has_permission?('post_content', profile) %> | |
5 | - <%= button :new, _('New event'), myprofile_url(:controller => 'cms', :action => 'new', :type => 'Event') %> | |
6 | - <% end %> | |
7 | - </div> | |
8 | - <%= _("%s's events") % profile.name %> | |
9 | -</h1> | |
1 | +<h1 id='agenda-title'><%= _("%s's events") % profile.name %></h1> | |
2 | + | |
3 | +<div id='agenda-toolbar'> | |
4 | + <%= button :back, _('Back to %s') % profile.name, profile.url %> | |
5 | + <% if user && user.has_permission?('post_content', profile) %> | |
6 | + <%= button :new, _('New event'), myprofile_url(:controller => 'cms', :action => 'new', :type => 'Event') %> | |
7 | + <% end %> | |
8 | +</div> | |
9 | + | |
10 | +<div style="clear: both"></div> | |
10 | 11 | |
11 | 12 | <%= render :partial => 'agenda' %> | ... | ... |
app/views/layouts/_javascript.rhtml
1 | -<%= javascript_include_tag :defaults, 'jquery-latest.js', 'jquery.noconflict.js', 'jquery.cycle.all.min.js', 'thickbox.js', 'lightbox', 'jquery-ui-1.8.2.custom.min', 'jquery.scrollTo', 'jquery.form.js', 'jquery.cookie', 'reflection', 'add-and-join', 'jquery.tokeninput', 'report-abuse','colorbox', 'jquery-validation/jquery.validate', 'catalog', 'manage-products', :cache => 'cache-general' %> | |
1 | +<%= javascript_include_tag :defaults, 'jquery-latest.js', | |
2 | +'jquery.noconflict.js', 'jquery.cycle.all.min.js', 'thickbox.js', 'lightbox', | |
3 | +'jquery-ui-1.8.2.custom.min', 'jquery.scrollTo', 'jquery.form.js', | |
4 | +'jquery.cookie', 'reflection', 'add-and-join', 'jquery.tokeninput', | |
5 | +'jquery.ba-bbq.min.js', 'report-abuse','colorbox', 'jquery-validation/jquery.validate', 'catalog', | |
6 | +'manage-products', :cache => 'cache-general' %> | |
2 | 7 | <% language = FastGettext.locale %> |
3 | -<%= javascript_include_tag 'jquery-validation/localization/messages_'+language, 'jquery-validation/localization/methods_'+language %> | |
8 | +<%= javascript_include_tag 'jquery-validation/localization/messages_'+language, | |
9 | + 'jquery-validation/localization/methods_'+language %> | ... | ... |
app/views/layouts/application-ng.rhtml
... | ... | @@ -61,16 +61,10 @@ |
61 | 61 | <%= render :file => 'account/login', :locals => { :is_thickbox => true } %> |
62 | 62 | </div> |
63 | 63 | </span> |
64 | - <form action="/search" class="search_form clean" method="get" id="top-search"> | |
65 | - <input name="query" size="15" value="<%=_('Search...')%>" | |
66 | - onfocus="this.form.className='focused'; | |
67 | - if(this.value=='<%=_('Search...')%>'){this.value=''}" | |
68 | - onblur="this.form.className=''; | |
69 | - if(/^\s*$/.test(this.value)){ | |
70 | - this.value='<%=_('Search...')%>'; | |
71 | - this.form.className='clean' | |
72 | - }" /> | |
64 | + <form action="/search" class="search_form" method="get" class="clean"> | |
65 | + <input name="query" size="15" title="<%=_('Search...')%>" onfocus="this.form.className='focused';" onblur="this.form.className=''" /> | |
73 | 66 | <div><%=_('Press <strong>Enter</strong> to send the search query.')%></div> |
67 | + <%= javascript_tag 'jQuery("#user form input").hint();' %> | |
74 | 68 | </form> |
75 | 69 | </div><!-- end id="user" --> |
76 | 70 | ... | ... |
app/views/manage_products/_display_image.rhtml
1 | 1 | <div id='display-product-image'> |
2 | - <%= image_tag (@product.reload.default_image('thumb')), :class => 'product-pic' %> | |
2 | + <%= image_tag (@product.reload.default_image('big')), :class => 'product-pic' %> | |
3 | 3 | </div> |
4 | 4 | |
5 | +<% if @product.image %> | |
6 | + <%= link_to content_tag(:span, _('Zoom in')), @product.image.public_filename, | |
7 | + :class => 'zoomify-image' %> | |
8 | +<% end %> | |
9 | +<%= add_zoom_to_images %> | |
10 | + | |
5 | 11 | <%= edit_product_link_to_remote(@product, 'image', _('Change image')) %> | ... | ... |
app/views/manage_products/show.rhtml
... | ... | @@ -0,0 +1,28 @@ |
1 | +<div id="balloon"> | |
2 | + <table class='profile-info'> | |
3 | + <tr> | |
4 | + <td><div class='profile-info-picture'><%= profile_image(@profile, :thumb) %></div></td> | |
5 | + <td> | |
6 | + <strong><%= link_to(@profile.name, url_for(@profile.url)) %></strong><br/> | |
7 | + <% unless @profile.contact_email.nil? %> | |
8 | + <strong><%= _('E-Mail: ') + @profile.contact_email %></strong><br/> | |
9 | + <% end %> | |
10 | + <% unless @profile.contact_phone.nil? %> | |
11 | + <strong><%= _('Phone(s): ') + @profile.contact_phone %></strong><br/> | |
12 | + <% end %> | |
13 | + <% unless @profile.region.nil? %> | |
14 | + <strong><%= _('Location: ') + @profile.region.name %></strong><br/> | |
15 | + <% end %> | |
16 | + <% unless @profile.address.nil? %> | |
17 | + <strong><%= _('Address: ') + @profile.address %></strong><br/> | |
18 | + <% end %> | |
19 | + <% unless @profile.products.empty? %> | |
20 | + <strong><%= _('Products/Services: ') + @profile.products.map{|i| link_to(i.name, :controller => 'manage_products', :profile => @profile.identifier, :action => 'show', :id => i.id)}.join(', ') %></strong><br/> | |
21 | + <% end %> | |
22 | + <% if @profile.respond_to?(:distance) and !@profile.distance.nil? %> | |
23 | + <strong><%= _('Distance: ') + "%.2f%" % @profile.distance %></strong><br/> | |
24 | + <% end %> | |
25 | + </td> | |
26 | + </tr> | |
27 | + </table> | |
28 | +</div> | ... | ... |
... | ... | @@ -0,0 +1,252 @@ |
1 | + | |
2 | +var geocoder; | |
3 | +var map; | |
4 | +var marker; | |
5 | +var center; | |
6 | +var move = true; | |
7 | +var previousCenter; | |
8 | + | |
9 | +function getAddress(latlng) { | |
10 | + $('location-fields').addClassName("loading"); | |
11 | + | |
12 | + if (latlng != null) { | |
13 | + geocoder.geocode( {'latLng': latlng}, showAddress); | |
14 | + } | |
15 | +} | |
16 | + | |
17 | +function codeAddress() { | |
18 | + $('location-fields').addClassName("loading"); | |
19 | + | |
20 | + var country_option = $('profile_data_country').value; | |
21 | + var address = $('profile_data_address').value + "-" + $('profile_data_zip_code').value + "," + $('profile_data_city').value+ "-" + $('profile_data_state').value + "," + country_option; | |
22 | + | |
23 | + if (geocoder) { | |
24 | + geocoder.geocode( { 'address': address}, function(results, status) { | |
25 | + if (status == google.maps.GeocoderStatus.OK) { | |
26 | + map.setCenter(results[0].geometry.location); | |
27 | + marker.setPosition(results[0].geometry.location); | |
28 | + getAddress(marker.getPosition()); | |
29 | + | |
30 | + $('profile_data_lat').value = results[0].geometry.location.lat(); | |
31 | + $('profile_data_lng').value = results[0].geometry.location.lng(); | |
32 | + $('location-fields').removeClassName("loading"); | |
33 | + enable_save(); | |
34 | + } else { | |
35 | + $('location-fields').removeClassName("loading"); | |
36 | + alert('<%=_("Address not found, reason:")%>' + translate_status(status)); | |
37 | + } | |
38 | + }); | |
39 | + } | |
40 | + | |
41 | + map.setZoom(11); | |
42 | + | |
43 | + return false; | |
44 | +} | |
45 | + | |
46 | +function translate_status(status) | |
47 | +{ | |
48 | + var translated_status = ''; | |
49 | + | |
50 | + if (google.maps.GeocoderStatus.INVALID_REQUEST == status) | |
51 | + translated_status = '<%= _('Invalid address') %>'; | |
52 | + else if (google.maps.GeocoderStatus.REQUEST_DENIED == status) | |
53 | + translated_status = '<%= _('Request denied') %>'; | |
54 | + else if (google.maps.GeocoderStatus.OVER_QUERY_LIMIT == status) | |
55 | + translated_status = '<%= _('Over query limit') %>'; | |
56 | + else if (google.maps.GeocoderStatus.ZERO_RESULTS == status) | |
57 | + translated_status = "<%= _('Address do not exist') %>"; | |
58 | + | |
59 | + return translated_status; | |
60 | +} | |
61 | + | |
62 | +function getAddressData() { | |
63 | + var text = ''; | |
64 | + var fields = [ | |
65 | + 'profile_data_country', | |
66 | + 'profile_data_state', | |
67 | + 'profile_data_city', | |
68 | + 'profile_data_address', | |
69 | + 'profile_data_zip_code' | |
70 | + ]; | |
71 | + for (var i = 0; i < fields.length; i++) { | |
72 | + var field = fields[i]; | |
73 | + if ($(field)) { | |
74 | + text += $(field).value + " "; | |
75 | + } | |
76 | + } | |
77 | + return text; | |
78 | +} | |
79 | + | |
80 | +function showAddress(results, status) { | |
81 | + | |
82 | + if (status == google.maps.GeocoderStatus.OK) { | |
83 | + map.setCenter(results[0].geometry.location); | |
84 | + updateFields(results[0]); | |
85 | + | |
86 | + } else { | |
87 | + alert("<%=_("Address not found, reason:")%>" + translate_status(status)); | |
88 | + } | |
89 | + | |
90 | +} | |
91 | + | |
92 | +function updateFields(place) { | |
93 | + var position = marker.getPosition(); | |
94 | + $('profile_data_lat').value = position.lat(); | |
95 | + $('profile_data_lng').value = position.lng(); | |
96 | + $('location-fields').removeClassName("loading"); | |
97 | + | |
98 | + form = jQuery('#location-form')[0]; | |
99 | + form.lat = marker.getPosition().lat(); | |
100 | + form.lng = marker.getPosition().lng(); | |
101 | + | |
102 | + var components_len = place.address_components.size(); | |
103 | + | |
104 | + if(components_len < 2) | |
105 | + { | |
106 | + return false; | |
107 | + } | |
108 | + | |
109 | + var components = place.address_components; | |
110 | + var address = ""; | |
111 | + var zip_code = ""; | |
112 | + var city = ""; | |
113 | + var state = ""; | |
114 | + var country_code = ""; | |
115 | + var i = 0; | |
116 | + | |
117 | + for( i =0 ; i < components_len; i ++) | |
118 | + { | |
119 | + | |
120 | + if (components[i].types[0] == 'country') | |
121 | + country_code = components[i].short_name; | |
122 | + else if (components[i].types[0] == 'administrative_area_level_1') | |
123 | + state = components[i].long_name; | |
124 | + else if (components[i].types[0] == 'locality') | |
125 | + city = components[i].long_name; | |
126 | + else if (components[i].types[0] == 'sublocality') | |
127 | + address = components[i].long_name + "-" + address; | |
128 | + else if (components[i].types[0] == "route") | |
129 | + address = components[i].long_name + address; | |
130 | + else if (components[i].types[0] == "street_number") | |
131 | + address = address + "," + components[i].short_name ; | |
132 | + else if (components[i].types[0] == 'postal_code') | |
133 | + zip_code = components[i].short_name; | |
134 | + } | |
135 | + | |
136 | + $('profile_data_country').value = country_code; | |
137 | + $('profile_data_state').value = state; | |
138 | + $('profile_data_address').value = address; | |
139 | + $('profile_data_city').value = city; | |
140 | + $('profile_data_zip_code').value = zip_code; | |
141 | +} | |
142 | + | |
143 | + | |
144 | +function initialize_map() { | |
145 | + geocoder = new google.maps.Geocoder(); | |
146 | + | |
147 | + var lat = <%= profile.lat || 'false' %>; | |
148 | + var lng = <%= profile.lng || 'false' %>; | |
149 | + | |
150 | + if ( !(lat && lng) ) { | |
151 | + lat = -15.7605361485013; | |
152 | + lng = -47.933349609375; | |
153 | + } | |
154 | + | |
155 | + var latlng = new google.maps.LatLng(lat,lng); | |
156 | + | |
157 | + var myOptions = { | |
158 | + zoom: 8, | |
159 | + center: latlng, | |
160 | + mapTypeId: google.maps.MapTypeId.ROADMAP | |
161 | + } | |
162 | + | |
163 | + center = latlng; | |
164 | + | |
165 | + map = new google.maps.Map(document.getElementById("location-map"), myOptions); | |
166 | + | |
167 | + continueLoadMapV3() | |
168 | +} | |
169 | + | |
170 | +function continueLoadMapV3() { | |
171 | + | |
172 | + marker = new google.maps.Marker({ | |
173 | + position: center, | |
174 | + map: map, | |
175 | + draggable: true | |
176 | + }); | |
177 | + | |
178 | + google.maps.event.addListener(marker, "dragend", function() { | |
179 | + move = false; | |
180 | + getAddress(marker.getPosition()); | |
181 | + enable_save(); | |
182 | + }); | |
183 | + | |
184 | +} | |
185 | + | |
186 | +window.onload = initialize_map; | |
187 | + | |
188 | +var delay_autocomplete = 500; | |
189 | + | |
190 | +jQuery.noConflict(); | |
191 | +jQuery(document).ready(function (){ | |
192 | + | |
193 | + jQuery.widget( "custom.catcomplete",jQuery.ui.autocomplete, { | |
194 | + _renderMenu: function( ul, items ) { | |
195 | + var self = this, | |
196 | + currentCategory = ""; | |
197 | + jQuery.each( items, function( index, item ) { | |
198 | + if ( item.category != currentCategory ) { | |
199 | + ul.append( "<li class='ui-autocomplete-category'>" + item.category + "</li>" ); | |
200 | + currentCategory = item.category; | |
201 | + } | |
202 | + self._renderItem( ul, item ); | |
203 | + }); | |
204 | + } | |
205 | + }); | |
206 | + | |
207 | + | |
208 | + jQuery("#profile_data_city").catcomplete({ | |
209 | + source: "../maps/search_city", | |
210 | + minLength: 3, | |
211 | + delay: delay_autocomplete, | |
212 | + select: function( event, ui ) { $('profile_data_state').value =( ui.item ? ui.item.category : this.value ); } | |
213 | + }); | |
214 | + | |
215 | + jQuery("#profile_data_state").autocomplete({ | |
216 | + source: "../maps/search_state", | |
217 | + minLength: 3, | |
218 | + delay: delay_autocomplete | |
219 | + }); | |
220 | + | |
221 | + jQuery("#profile_data_city").keyup(function(){ | |
222 | + | |
223 | + disable_save(); | |
224 | + | |
225 | + }); | |
226 | + | |
227 | + jQuery("#profile_data_state").keyup(function(){ | |
228 | + | |
229 | + disable_save(); | |
230 | + | |
231 | + }); | |
232 | + | |
233 | + jQuery("#profile_data_country").change(function(){ | |
234 | + | |
235 | + disable_save(); | |
236 | + | |
237 | + }); | |
238 | + | |
239 | +}); | |
240 | + | |
241 | +function disable_save() | |
242 | +{ | |
243 | + jQuery('input[type="submit"]').attr("disabled", "true"); | |
244 | + jQuery('input[type="submit"]').val('<%=_("Localize before save")%>'); | |
245 | + jQuery('input[type="submit"]').addClass('disabled'); | |
246 | +} | |
247 | +function enable_save() | |
248 | +{ | |
249 | + jQuery('input[type="submit"]').removeAttr("disabled"); | |
250 | + jQuery('input[type="submit"]').val('<%=_("Save")%>'); | |
251 | + jQuery('input[type="submit"]').removeClass('disabled'); | |
252 | +} | ... | ... |
app/views/maps/_google_map.rhtml
... | ... | @@ -1,136 +0,0 @@ |
1 | -<%= content_tag('script', '', :src => GoogleMaps.api_url(profile.default_hostname), :type => 'text/javascript') %> | |
2 | - | |
3 | -<script type="text/javascript" > | |
4 | - var geocoder; | |
5 | - var map; | |
6 | - var marker; | |
7 | - var center; | |
8 | - var move = true; | |
9 | - var previousCenter; | |
10 | - | |
11 | - function getAddress(overlay, latlng) { | |
12 | - $('location-fields').addClassName("loading"); | |
13 | - if (latlng != null) { | |
14 | - geocoder.getLocations(latlng, showAddress); | |
15 | - } | |
16 | - } | |
17 | - | |
18 | - function getAddressData() { | |
19 | - var text = ''; | |
20 | - var fields = [ | |
21 | - 'profile_data_country', | |
22 | - 'profile_data_state', | |
23 | - 'profile_data_city', | |
24 | - 'profile_data_address', | |
25 | - 'profile_data_zip_code' | |
26 | - ]; | |
27 | - for (var i = 0; i < fields.length; i++) { | |
28 | - var field = fields[i]; | |
29 | - if ($(field)) { | |
30 | - text += $(field).value + " "; | |
31 | - } | |
32 | - } | |
33 | - return text; | |
34 | - } | |
35 | - | |
36 | - function showAddress(response) { | |
37 | - var message; | |
38 | - place = geoCodeAddress(response); | |
39 | - if ( place ) { | |
40 | - if ( move ) { | |
41 | - center = new GLatLng(place.Point.coordinates[1],place.Point.coordinates[0]); | |
42 | - marker.setLatLng(center); | |
43 | - } else { | |
44 | - move = true; | |
45 | - } | |
46 | - message = showMessage(place); | |
47 | - updateFields(place); | |
48 | - } else { | |
49 | - message = showNotFoundMessage(); | |
50 | - } | |
51 | - map.addOverlay(marker); | |
52 | - map.setCenter(marker.getLatLng()); | |
53 | - marker.openInfoWindowHtml(message, {maxWidth:300}); | |
54 | - } | |
55 | - | |
56 | - function geoCodeAddress(response) { | |
57 | - if (!response || (response && response.Status.code != '200')) { | |
58 | - return false; | |
59 | - } else { | |
60 | - place = response.Placemark[0]; | |
61 | - return place; | |
62 | - } | |
63 | - } | |
64 | - | |
65 | - function showMessage(place) { | |
66 | - var message = '<b><%= _('Address:') %></b> ' + place.address + '<br>' + | |
67 | - '<b><%= _('Coordinates:') %></b> ' + place.Point.coordinates[0] + "," + place.Point.coordinates[1] + '<br>' + | |
68 | - '<b><%= _('Country code:') %></b> ' + place.AddressDetails.Country.CountryNameCode + '<br>'; | |
69 | - return message; | |
70 | - } | |
71 | - | |
72 | - function showNotFoundMessage() { | |
73 | - var message = '<%= _('Address not found') %>' + '<br>' + | |
74 | - '<b><%= _('Coordinates:') %></b> ' + marker.getLatLng().lng() + "," + marker.getLatLng().lat(); | |
75 | - return message; | |
76 | - } | |
77 | - | |
78 | - function updateFields(response) { | |
79 | - var position = marker.getLatLng(); | |
80 | - $('profile_data_lat').value = position.lat(); | |
81 | - $('profile_data_lng').value = position.lng(); | |
82 | - $('location-fields').removeClassName("loading"); | |
83 | - } | |
84 | - | |
85 | - function loadMap() { | |
86 | - if (GBrowserIsCompatible()) { | |
87 | - map = new GMap2(document.getElementById("location-map")); | |
88 | - geocoder = new GClientGeocoder(); | |
89 | - var lat = <%= profile.lat || 'false' %>; | |
90 | - var lng = <%= profile.lng || 'false' %>; | |
91 | - if ( lat && lng ) { | |
92 | - center = new GLatLng( lat, lng ); | |
93 | - continueLoadMap(); | |
94 | - } else { | |
95 | - geocoder.getLocations('<%= profile.geolocation %>', loadAddress); | |
96 | - } | |
97 | - } | |
98 | - } | |
99 | - | |
100 | - function loadAddress(response) { | |
101 | - place = geoCodeAddress(response); | |
102 | - if ( move ) { | |
103 | - center = new GLatLng(place.Point.coordinates[1],place.Point.coordinates[0]); | |
104 | - } | |
105 | - continueLoadMap(); | |
106 | - } | |
107 | - | |
108 | - function continueLoadMap() { | |
109 | - marker = new GMarker(center, {draggable: true}); | |
110 | - map.setCenter(center, 4); | |
111 | - | |
112 | - map.addControl(new GLargeMapControl()); | |
113 | - map.addControl(new GScaleControl()); | |
114 | - map.addControl(new GMapTypeControl()); | |
115 | - | |
116 | - GEvent.addListener(marker, "dragstart", function() { | |
117 | - previousCenter = marker.getLatLng(); | |
118 | - map.closeInfoWindow(); | |
119 | - }); | |
120 | - | |
121 | - GEvent.addListener(marker, "dragend", function() { | |
122 | - move = false; | |
123 | - getAddress(overlay, marker.getLatLng()); | |
124 | - }); | |
125 | - | |
126 | - GEvent.addListener(marker, "click", function() { | |
127 | - move = false; | |
128 | - getAddress(overlay, marker.getLatLng()); | |
129 | - }); | |
130 | - | |
131 | - map.addOverlay(marker); | |
132 | - } | |
133 | - | |
134 | - window.onload = loadMap; | |
135 | - window.unload = GUnload(); | |
136 | -</script> |
app/views/maps/edit_location.rhtml
1 | 1 | <h1><%= _('Location') %></h1> |
2 | +<div class="error"> | |
3 | + <%= flash[:error] %> | |
4 | +</div> | |
2 | 5 | |
3 | -<% form_for :profile_data, :url => {:action => 'edit_location'} do |f| %> | |
6 | +<% form_for :profile_data, :url => {:action => 'edit_location'}, :html => {:id => 'location-form'} do |f| %> | |
4 | 7 | |
5 | 8 | <div id='location-fields'> |
6 | - <%= optional_field(profile, 'country', select_country(_('Country'), 'profile_data', 'country', {:class => 'type-select'})) %> | |
7 | - <%= optional_field(profile, 'state', labelled_form_field(_('State'), f.text_field(:state))) %> | |
8 | - <%= optional_field(profile, 'city', labelled_form_field(_('City'), f.text_field(:city))) %> | |
9 | - <%= optional_field(profile, 'zip_code', labelled_form_field(_('ZIP code'), text_field(:profile_data, :zip_code))) %> | |
10 | - <%= optional_field(profile, 'address', labelled_form_field(_('Address (street and number)'), text_field(:profile_data, :address))) %> | |
9 | + <%= select_country _('Country'), 'profile_data', 'country', {:class => 'type-select'} %> | |
10 | + <%= labelled_form_field _('State'), f.text_field(:state) %> | |
11 | + <%= labelled_form_field _('City'), f.text_field(:city) %> | |
12 | + <%= labelled_form_field _('ZIP code'), text_field(:profile_data, :zip_code) %> | |
13 | + <%= labelled_form_field _('Address (street and number)'), text_field(:profile_data, :address) %> | |
11 | 14 | <% button_bar do %> |
12 | - <%= button_to_function :search, _('Locate in the map'), "getAddress(null, getAddressData())", :title => _("Locate the address informed above in the map below (note that you'll probably need to adjust the marker to get a precise position)") %> | |
15 | + <%= button_to_function :search, _('Locate in the map'), "codeAddress()", :title => _("Locate the address informed above in the map below (note that you'll probably need to adjust the marker to get a precise position)") %> | |
13 | 16 | <%= submit_button 'save', _('Save') %> |
14 | 17 | <%= button(:back, _('Back to control panel'), :controller => 'profile_editor') %> |
15 | 18 | <% end %> |
16 | 19 | </div> |
17 | 20 | |
21 | + <p><%= _('Drag the balloon to find the exact location.') %> </p> | |
18 | 22 | |
19 | 23 | <div style='overflow: hidden'> |
20 | 24 | <p><div id="location-map"></div></p> |
21 | 25 | </div> |
22 | 26 | |
23 | - <%= f.hidden_field(:lat) %> | |
24 | - <%= f.hidden_field(:lng) %> | |
25 | - | |
26 | - | |
27 | - | |
28 | - <% button_bar do %> | |
29 | - <%= submit_button 'save', _('Save') %> | |
30 | - <%= button(:back, _('Back to control panel'), :controller => 'profile_editor') %> | |
31 | - <% end %> | |
32 | - | |
27 | + <%= f.hidden_field :lat %> | |
28 | + <%= f.hidden_field :lng %> | |
29 | + | |
33 | 30 | <% end %> |
34 | 31 | |
35 | -<%= render :partial => 'google_map'%> | |
32 | +<%= content_tag('script', '', :src => "http://maps.googleapis.com/maps/api/js?sensor=false", :type => 'text/javascript') %> | |
33 | +<%= content_tag('script', '', :src => url_for(:controller => :maps, :action => :google_map), :type => 'text/javascript') %> | |
34 | + | ... | ... |
app/views/search/_article.rhtml
1 | -<li class="<%= icon_for_article(article) %>"> | |
2 | - <strong><%= link_to(article.title, article.view_url) %></strong> | |
3 | - <div class="item_meta"> | |
4 | - <% if article.last_changed_by %> | |
5 | - <span class="cat_item_by"> | |
6 | - <%= _('by %s') % link_to(article.last_changed_by.name, article.last_changed_by.url) %> | |
7 | - </span> | |
8 | - <% end %> | |
9 | - <span class="cat_item_update"><%= _('Last update: %s.') % show_date(article.updated_at) %></span> | |
1 | +<li class="search-article-item article-item"> | |
2 | + <%= link_to(article.title, article.url, :class => "search-result-title") %> | |
3 | + <div class="search-content-first-column"> | |
4 | + <%= render :partial => 'image', :object => article %> | |
10 | 5 | </div> |
6 | + <table class="noborder search-content-second-column"> | |
7 | + <%= render :partial => 'article_common', :object => article %> | |
8 | + </table> | |
9 | + <%= render :partial => 'article_last_change', :object => article %> | |
10 | + | |
11 | + <div style="clear:both"></div> | |
11 | 12 | </li> | ... | ... |
... | ... | @@ -0,0 +1,9 @@ |
1 | +<tr class="search-article-categories"> | |
2 | + <td class="search-field-label"><%= _('Categories') %></td> | |
3 | + <td class="search-article-categories-container <%= "search-field-none" if article_categories.empty? %>"> | |
4 | + <% article_categories.each do |category| %> | |
5 | + <%= link_to_category category, false, :class => "search-article-category" %> | |
6 | + <% end %> | |
7 | + <%= _('None') if article_categories.empty? %> | |
8 | + </td> | |
9 | +</tr> | ... | ... |
... | ... | @@ -0,0 +1,7 @@ |
1 | +<% article = article_common %> | |
2 | +<% show_description = true if show_description.nil? %> | |
3 | + | |
4 | +<%= render :partial => 'article_author', :object => article %> | |
5 | +<%= render :partial => 'article_description', :object => article if show_description %> | |
6 | +<%= render :partial => 'article_tags', :object => article.tags %> | |
7 | +<%= render :partial => 'article_categories', :object => article.categories %> | ... | ... |
... | ... | @@ -0,0 +1,13 @@ |
1 | +<% article = article_description %> | |
2 | + | |
3 | +<tr class="search-article-description"> | |
4 | + <td class="search-field-label"><%= _("Description") %></td> | |
5 | + | |
6 | + <% if !article.body.blank? %> | |
7 | + <% description = strip_tags(article.body.to_s) %> | |
8 | + <% description = excerpt(description, description.first(3), 200).gsub!(/\s{2,}/, ' ') %> | |
9 | + <td class="search-article-body"><%= description %></td> | |
10 | + <% else %> | |
11 | + <td class="search-field-none"><%= _('None') %></td> | |
12 | + <% end %> | |
13 | +</tr> | ... | ... |
... | ... | @@ -0,0 +1,10 @@ |
1 | +<% article = article_last_change %> | |
2 | + | |
3 | +<div class="search-article-author-changes"> | |
4 | + <% if article.last_changed_by and article.last_changed_by != article.profile %> | |
5 | + <span><%= _('by %{name} at %{date}') % {:name => link_to(article.last_changed_by.name, article.last_changed_by.url), | |
6 | + :date => show_date(article.updated_at) } %></span> | |
7 | + <% else %> | |
8 | + <span><%= _('Last update: %s.') % show_date(article.updated_at) %></span> | |
9 | + <% end %> | |
10 | +</div> | ... | ... |
... | ... | @@ -0,0 +1,9 @@ |
1 | +<tr class="search-article-tags"> | |
2 | + <td class="search-field-label"><%= _('Tags') %></td> | |
3 | + <td class="search-article-tags-container <%= "search-field-none" if article_tags.empty? %>"> | |
4 | + <% article_tags.each do |tag| %> | |
5 | + <%= link_to_tag tag, :class => "search-article-tag" %> | |
6 | + <% end %> | |
7 | + <%= _('None') if article_tags.empty? %></td> | |
8 | + </td> | |
9 | +</tr> | ... | ... |
... | ... | @@ -0,0 +1,24 @@ |
1 | +<li class="search-blog article-item"> | |
2 | + <%= link_to blog.title, blog.view_url, :class => 'search-result-title' %> | |
3 | + <div class="search-content-first-column"> | |
4 | + <%= render :partial => 'image', :object => blog %> | |
5 | + </div> | |
6 | + <table class="noborder search-content-second-column"> | |
7 | + <tr class="search-blog-items"> | |
8 | + <td class="search-field-label"><%= _("Last posts") %></td> | |
9 | + | |
10 | + <% r = blog.children.find(:all, :order => :updated_at, :conditions => ['type != ?', 'RssFeed']).last(3) %> | |
11 | + <td class="<%= "search-field-none" if r.empty? %>"> | |
12 | + <% r.each do |a| %> | |
13 | + <%= link_to a.title, a.view_url, :class => 'search-blog-sample-item '+icon_for_article(a) %> | |
14 | + <% end %> | |
15 | + <%= _('None') if r.empty? %> | |
16 | + </td> | |
17 | + </tr> | |
18 | + | |
19 | + <%= render :partial => 'article_common', :object => blog %> | |
20 | + </table> | |
21 | + <%= render :partial => 'article_last_change', :object => blog %> | |
22 | + | |
23 | + <div style="clear: both;"/></div> | |
24 | +</li> | ... | ... |
app/views/search/_display_results.rhtml
1 | -<div id="search-results" class="<%= 'only-one-result-box' if @results.size == 1 %>"> | |
1 | +<div id="search-results" class="<%= @results.size == 1 ? 'only-one-result-box' : 'multiple-results-boxes' %>"> | |
2 | + <% @order.each do |name| %> | |
3 | + <% results = @results[name] %> | |
4 | + <% empty = results.nil? || results.empty? %> | |
2 | 5 | |
3 | -<% | |
4 | - pos2 = :odd # allow to format in a two columns layout | |
5 | - pos3 = 3 # allow to format in a thre columns layout | |
6 | -%> | |
7 | -<% @order.each do |name| %> | |
8 | - <% results = @results[name] %> | |
9 | - <% | |
10 | - pos3 += 1; pos3 = 1 if pos3 > 3 | |
11 | - pos2==:odd ? pos2=:even : pos2=:odd | |
12 | - %> | |
13 | - <% if !results.nil? and !results.empty? %> | |
14 | - <div class="search-results-<%= name %> search-results-box <%= pos2 %> <%= 'col%s_of3' % pos3.to_s %>"> | |
15 | - <% if @controller.action_name != 'assets' %> | |
16 | - <% if @results.size != 1 %> | |
17 | - <h3> | |
18 | - <%= @names[name] %> | |
19 | - </h3> | |
20 | - <% end %> | |
21 | - <%# FIXME: don't hardcode an asset like this %> | |
22 | - <% if name == :most_commented_articles %> | |
23 | - <%= link_to( results.respond_to?(:total_entries) ? _('see all (%d)') % results.total_entries : _('see all...'), | |
24 | - params.merge(:action => 'index', | |
25 | - :asset => 'articles' ), | |
26 | - :class => 'see-more' ) if @results.size > 1 %> | |
6 | + <div class="search-results-<%= name %> search-results-box <%= "search-results-empty" if empty %>"> | |
7 | + <% if not empty %> | |
8 | + <% partial = partial_for_class(results.first.class.class_name.constantize) %> | |
27 | 9 | |
28 | - <% else %> | |
29 | - <%= link_to( results.respond_to?(:total_entries) ? _('see all (%d)') % results.total_entries : _('see all...'), | |
30 | - params.merge(:action => 'index', | |
31 | - :asset => name ), | |
32 | - :class => 'see-more' ) if @results.size > 1 %> | |
10 | + <% if @results.size > 1 %> | |
11 | + <h3><%= @names[name] %></h3> | |
12 | + <% if results.total_entries > SearchController::MULTIPLE_SEARCH_LIMIT %> | |
13 | + <%= link_to(_('see all (%d)') % results.total_entries, params.merge(:action => name), :class => 'see-more' ) %> | |
14 | + <% end %> | |
33 | 15 | <% end %> |
34 | - <% end %> | |
35 | - <% partial = partial_for_class results.first.class %> | |
36 | - <div class="search-results-innerbox search-results-type-<%= partial %> <%= 'common-profile-list-block' if partial == 'profile' %>"> | |
37 | - <div class="search-results-innerbox2"><!-- the innerbox2 is a workarround for MSIE --> | |
16 | + | |
17 | + <div class="search-results-innerbox search-results-type-<%= partial %> <%= 'common-profile-list-block' if partial == 'profile' %>"> | |
38 | 18 | <ul> |
39 | - <% hit_pos = 0 %> | |
40 | 19 | <% results.each do |hit| %> |
41 | - <% next if hit.respond_to?(:visible) && !hit.visible? %> | |
42 | - <%= render :partial => partial_for_class(hit.class), | |
43 | - | |
44 | - :object => hit, | |
45 | - :locals => { :pos => ( hit_pos += 1 ) } %> | |
20 | + <%= render :partial => partial_for_class(hit.class), :object => hit %> | |
46 | 21 | <% end %> |
47 | 22 | </ul> |
48 | - <hr /> | |
49 | - </div><!-- end class="search-results-innerbox2" --> | |
50 | - </div><!-- end class="search-results-innerbox" --> | |
51 | - </div><!-- end class="search-results-<%= name %>" --> | |
52 | - <% else %> | |
53 | - <div class="search-results-<%= name %> search-results-empty search-results-box <%= pos2 %> <%= 'col%s_of3' % pos3.to_s %>"> | |
54 | - <% if @controller.action_name != 'assets' %> | |
55 | - <% if @results.size != 1 %> | |
23 | + </div> | |
24 | + <% else %> | |
25 | + <% if @results.size > 1 %> | |
56 | 26 | <h3><%= @names[name] %></h3> |
57 | 27 | <% end %> |
28 | + <div class="search-results-innerbox search-results-type-empty"> | |
29 | + <div> <%= _('None') %> </div> | |
30 | + </div> | |
58 | 31 | <% end %> |
59 | - <div class="search-results-innerbox search-results-type-empty"> | |
60 | - <div> <%= _('None') %> </div> | |
61 | - <hr /> | |
62 | - </div><!-- end class="search-results-innerbox" --> | |
63 | - </div><!-- end class="search-results-<%= name %>" --> | |
32 | + </div> | |
64 | 33 | <% end %> |
65 | -<% end %> | |
34 | + | |
35 | + <div style="clear:both"></div> | |
66 | 36 | |
67 | -<br style="clear:both" /> | |
68 | -</div><!-- end id="search-results" --> | |
37 | + <%= add_zoom_to_images %> | |
38 | +</div> | |
69 | 39 | ... | ... |
... | ... | @@ -0,0 +1 @@ |
1 | +<%= render :partial => 'text_article', :object => enterprise_homepage %> | ... | ... |
app/views/search/_event.rhtml
1 | -<li class="<%= icon_for_article(event) %>"> | |
2 | - <strong><%= link_to(event.title, event.url) %></strong> | |
3 | - <div class="item_meta"> | |
4 | - <%= show_period(event.start_date, event.end_date) %> | |
1 | +<li class="search-event-item article-item"> | |
2 | + <%= link_to(event.title, event.url, :class => "search-result-title") %> | |
3 | + <div class="search-content-first-column"> | |
4 | + <%= render :partial => 'image', :object => event %> | |
5 | 5 | </div> |
6 | + <table class="noborder search-content-second-column"> | |
7 | + <% if event.start_date %> | |
8 | + <tr class="searc-article-event-date"> | |
9 | + <td class="search-field-label"><%= _('Start date') %></td> | |
10 | + <td class="article-item-date"><%= event.start_date %></td> | |
11 | + </tr> | |
12 | + <% end %> | |
13 | + <% if event.end_date %> | |
14 | + <tr class="searc-article-event-date"> | |
15 | + <td class="search-field-label"><%= _('End date') %></td> | |
16 | + <td class="article-item-date"><%= event.end_date %></td> | |
17 | + </tr> | |
18 | + <% end %> | |
19 | + | |
20 | + <%= render :partial => 'article_common', :object => event %> | |
21 | + </table> | |
22 | + <%= render :partial => 'article_last_change', :object => event %> | |
23 | + | |
24 | + <div style="clear: both"></div> | |
6 | 25 | </li> | ... | ... |
... | ... | @@ -0,0 +1,36 @@ |
1 | +<% less_options_limit = 8 %> | |
2 | + | |
3 | +<div id="facets-menu"> | |
4 | + <% @asset_class.map_facets_for(environment).each do |facet| %> | |
5 | + | |
6 | + <div id="facet-menu-<%= facet[:id].to_s %>" class="facet-menu"> | |
7 | + <div class="facet-menu-label"> | |
8 | + <%= @asset_class.facet_label(facet) %> | |
9 | + </div> | |
10 | + | |
11 | + <% results = @asset_class.map_facet_results(facet, params[:facet], @facets, @all_facets, :limit => less_options_limit) %> | |
12 | + <% facet_count = results.total_entries %> | |
13 | + | |
14 | + <% if facet_count > 0 %> | |
15 | + <div class="facet-menu-options facet-menu-more-options" style="display: none"> | |
16 | + </div> | |
17 | + | |
18 | + <div class="facet-menu-options facet-menu-less-options"> | |
19 | + <% results.each do |id, label, count| %> | |
20 | + <%= facet_link_html(facet, params, id, label, count) %><br /> | |
21 | + <% end %> | |
22 | + </div> <br /> | |
23 | + | |
24 | + <% if facet_count > less_options_limit %> | |
25 | + <%= link_to_function _("Options"), | |
26 | + "facet_options_toggle('#{facet[:id].to_s}', '#{url_for(params.merge(:action => 'facets_browse', :facet_id => facet[:id], :asset => @asset, :escape => false))}'); " + | |
27 | + "jQuery(this).toggleClass('facet-less-options')", :class => "facet-options-toggle" %> | |
28 | + <br /> | |
29 | + <% end %> | |
30 | + | |
31 | + <% else %> | |
32 | + <span class="facet-any-result-found"><%= _("No filter available") %></span> | |
33 | + <% end %> | |
34 | + </div> | |
35 | + <% end %> | |
36 | +</div> | ... | ... |
... | ... | @@ -0,0 +1,24 @@ |
1 | +<li class="search-folder-item article-item"> | |
2 | + <%= link_to folder.title, folder.view_url, :class => 'search-result-title' %> | |
3 | + <div class="search-content-first-column"> | |
4 | + <%= render :partial => 'image', :object => folder %> | |
5 | + </div> | |
6 | + <table class="noborder search-content-second-column"> | |
7 | + <tr class="search-folder-items"> | |
8 | + <td class="search-field-label"><%= _("Last items") %></td> | |
9 | + | |
10 | + <% r = folder.children.last(3) %> | |
11 | + <td class="<%= "search-field-none" if r.empty? %>"> | |
12 | + <% r.each do |a| %> | |
13 | + <%= link_to a.title, a.view_url, :class => 'search-folder-sample-item '+icon_for_article(a) %> | |
14 | + <% end %> | |
15 | + <%= _('None') if r.empty? %> | |
16 | + </td> | |
17 | + </tr> | |
18 | + | |
19 | + <%= render :partial => 'article_common', :object => folder %> | |
20 | + </table> | |
21 | + <%= render :partial => 'article_last_change', :object => folder %> | |
22 | + | |
23 | + <div style="clear:both"></div> | |
24 | +</li> | ... | ... |
... | ... | @@ -0,0 +1,24 @@ |
1 | +<li class="search-forum-item article-item"> | |
2 | + <%= link_to forum.title, forum.view_url, :class => 'search-result-title' %> | |
3 | + <div class="search-content-first-column"> | |
4 | + <%= render :partial => 'image', :object => forum %> | |
5 | + </div> | |
6 | + <table class="noborder search-content-second-column"> | |
7 | + <tr class="search-forum-items"> | |
8 | + <td class="search-field-label"><%= _("Last topics") %></td> | |
9 | + | |
10 | + <% r = forum.children.find(:all, :order => :updated_at, :conditions => ['type != ?', 'RssFeed']).last(3) %> | |
11 | + <td class="<%= "search-field-none" if r.empty? %>"> | |
12 | + <% r.each do |a| %> | |
13 | + <%= link_to a.title, a.view_url, :class => 'search-forum-sample-item '+icon_for_article(a) %> | |
14 | + <% end %> | |
15 | + <%= _('None') if r.empty? %> | |
16 | + </td> | |
17 | + </tr> | |
18 | + | |
19 | + <%= render :partial => 'article_common', :object => forum %> | |
20 | + </table> | |
21 | + <%= render :partial => 'article_last_change', :object => forum %> | |
22 | + | |
23 | + <div style="clear:both"></div> | |
24 | +</li> | ... | ... |
... | ... | @@ -0,0 +1,13 @@ |
1 | +<li class="search-gallery article-item"> | |
2 | + <%= link_to gallery.title, gallery.view_url, :class => 'search-result-title' %> | |
3 | + <div class="search-content-first-column"> | |
4 | + <%= render :partial => 'image', :object => gallery %> | |
5 | + </div> | |
6 | + <table class="noborder search-content-second-column"> | |
7 | + <%= render :partial => 'article_common', :object => gallery %> | |
8 | + </table> | |
9 | + <%= render :partial => 'article_last_change', :object => gallery %> | |
10 | + | |
11 | + <div style="clear: both"></div> | |
12 | +</li> | |
13 | + | ... | ... |
app/views/search/_google_maps.rhtml
1 | -<%= content_tag('script', '', :src => GoogleMaps.api_url(environment.default_hostname), :type => 'text/javascript') %> | |
2 | - | |
3 | - | |
1 | +<div style="clear: both;"/></div> | |
4 | 2 | <div style='text-align: center;'> |
5 | 3 | <div id="map"></div> |
6 | 4 | </div> |
7 | 5 | |
8 | -<script type='text/javascript'> | |
9 | -var points = {}; | |
10 | - | |
11 | -function putMarker(lat, lng, title, summary) { | |
12 | - var point_str = lat + ":" + lng; | |
13 | - | |
14 | - if (points[point_str]) { | |
15 | - lng += (Math.random() - 0.5) * 0.02; | |
16 | - lat += (Math.random() - 0.5) * 0.02; | |
17 | - } else { | |
18 | - points[point_str] = true; | |
19 | - } | |
20 | - | |
21 | - var point = new GLatLng(lat, lng); | |
22 | - var options = { 'title' : title, 'icon' : icon }; | |
23 | - var marker = new GMarker(point, options); | |
24 | - map.addOverlay(marker); | |
25 | - GEvent.addListener(marker, 'click', function() { | |
26 | - map.openInfoWindowHtml(point, summary); | |
27 | - }); | |
28 | - bounds.extend(point); | |
29 | -} | |
30 | - | |
31 | -window.unload = function() { | |
32 | - GUnload(); | |
33 | -}; | |
34 | - | |
35 | -if (GBrowserIsCompatible()) { | |
36 | - var map = new GMap2(document.getElementById("map")); | |
37 | - | |
38 | - new GKeyboardHandler(map); | |
39 | - map.addControl(new GLargeMapControl()); | |
40 | - map.addControl(new GMapTypeControl()); | |
41 | - | |
42 | - centerPoint = new GLatLng(-15.0, -50.1419); | |
43 | - map.setCenter(centerPoint, <%= GoogleMaps.initial_zoom.to_json %>); | |
44 | - var bounds = new GLatLngBounds(); | |
45 | - | |
46 | - var baseIcon = new GIcon(); | |
47 | - baseIcon.iconSize=new GSize(32,32); | |
48 | - baseIcon.shadowSize=new GSize(36,32); | |
49 | - baseIcon.iconAnchor=new GPoint(16,32); | |
50 | - baseIcon.infoWindowAnchor=new GPoint(16,0); | |
51 | - <% | |
52 | - icon = default_or_themed_icon("/images/icons-map/enterprise.png") | |
53 | - icon_shadow = default_or_themed_icon("/images/icons-map/enterprise_shadow.png") | |
54 | - %> | |
55 | - var icon = new GIcon(baseIcon, "<%= icon %>", null, "<%= icon_shadow %>"); | |
6 | +<%= content_tag('script', '', :src => "http://maps.google.com/maps/api/js?sensor=true", :type => 'text/javascript') %> | |
7 | +<%= javascript_include_tag('google_maps') %> | |
56 | 8 | |
57 | 9 | <% |
58 | - @results.each do |name,results| | |
59 | - results.each do |item| | |
60 | - if item.lat && item.lng | |
61 | - %> | |
62 | - putMarker(<%= item.lat.to_json %>, <%= item.lng.to_json %>, <%= item.name.to_json %>, <%= display_item_map_info(item).to_json %>); | |
63 | - <% | |
64 | - end | |
65 | - end | |
66 | - end | |
10 | + icon = default_or_themed_icon("/images/icons-map/enterprise.png") | |
67 | 11 | %> |
68 | -} | |
69 | 12 | |
70 | - map.setZoom(map.getBoundsZoomLevel(bounds)); | |
71 | - map.setCenter(bounds.getCenter()); | |
13 | +<script type='text/javascript'> | |
14 | + mapLoad(<%= GoogleMaps.initial_zoom.to_json %>); | |
15 | + | |
16 | + <% @results.each do |name,results| %> | |
17 | + <% results.each do |item| %> | |
18 | + <% if item.lat && item.lng %> | |
19 | + mapPutMarker(<%= item.lat.to_json %>, <%= item.lng.to_json %>, <%= item.name.to_json %>, '<%= icon %>', | |
20 | + '<%= url_for(:controller => :map_balloon, :action => name.to_s.singularize, :id => item.id) %>'); | |
21 | + <% end %> | |
22 | + <% end %> | |
23 | + <% end %> | |
24 | + | |
25 | + mapCenter(); | |
72 | 26 | </script> | ... | ... |
... | ... | @@ -0,0 +1,52 @@ |
1 | +<div class="search-image-container"> | |
2 | + | |
3 | + <% if image.is_a? UploadedFile and image.filename %> | |
4 | + <% extension = image.filename[(image.filename.rindex('.')+1)..-1].downcase %> | |
5 | + <% if ['jpg', 'jpeg', 'gif', 'png', 'tiff', 'svg'].include? extension %> | |
6 | + <%= link_to '', image.view_url, :class => "search-image-pic", :style => 'background-image: url(%s)'% image.public_filename(:thumb) %> | |
7 | + <% if image.width && image.height %> | |
8 | + <% javascript_tag do %> | |
9 | + image = jQuery('script').last().parent().find('.search-image-pic'); | |
10 | + des_width = parseInt(image.css('width')); | |
11 | + des_height = parseInt(image.css('height')); | |
12 | + | |
13 | + width = <%= image.width %>; | |
14 | + height = <%= image.height %>; | |
15 | + scale_factor = width > height ? des_width/width : des_height/height; | |
16 | + | |
17 | + image.css({'width' : scale_factor*width +'px', 'height' : scale_factor*height+'px'}); | |
18 | + <% end %> | |
19 | + <% end %> | |
20 | + <% elsif ['pdf'].include? extension %> | |
21 | + <%= link_to '', image.view_url, :class => 'search-image-pic icon-application-pdf' %> | |
22 | + <% elsif ['doc', 'docx', 'odt', 'rtf', 'txt', 'html', 'htm'].include? extension %> | |
23 | + <%= link_to '', image.view_url, :class => 'search-image-pic icon-application-vnd-oasis-opendocument-text' %> | |
24 | + <% elsif ['xls', 'xlsx', 'ods', 'csv', 'tsv', 'tab'].include? extension %> | |
25 | + <%= link_to '', image.view_url, :class => 'search-image-pic icon-application-vnd-oasis-opendocument-spreadsheet' %> | |
26 | + <% end %> | |
27 | + <% elsif image.is_a? Gallery %> | |
28 | + <div class="search-gallery-items"> | |
29 | + <% r = image.children.find(:all, :order => :updated_at, :conditions => ['type = ?', 'UploadedFile']).last(3) %> | |
30 | + <% if r.length > 0 %> | |
31 | + <% r.each do |i| %> | |
32 | + <%= link_to '', i.view_url, :class => "search-image-pic", :style => 'background-image: url(%s)'% i.public_filename(:thumb) %> | |
33 | + <% end %> | |
34 | + <% else %> | |
35 | + <div class="search-no-image"><span><%= _('No image') %></span></div> | |
36 | + <% end %> | |
37 | + </div> | |
38 | + <% elsif image.is_a? Product %> | |
39 | + <% if image.image %> | |
40 | + <div class="zoomable-image"> | |
41 | + <%= link_to '', product_path(image), :class => "search-image-pic", | |
42 | + :style => 'background-image: url(%s)'% image.default_image(:thumb) %> | |
43 | + <%= link_to content_tag(:span, _('Zoom in')), image.image.public_filename, | |
44 | + :class => 'zoomify-image' %> | |
45 | + </div> | |
46 | + <% else %> | |
47 | + <div class="search-no-image"><span><%= _('No image') %></span></div> | |
48 | + <% end %> | |
49 | + <% else %> | |
50 | + <div class="search-content-type-icon icon-content-<%=image.class.to_s.underscore.dasherize%>"></div> | |
51 | + <% end %> | |
52 | +</div> | ... | ... |
app/views/search/_product.rhtml
1 | -<%# FIXME add more information %> | |
2 | - | |
3 | -<% | |
4 | -product_item_pos = 0 if ! product_item_pos | |
5 | -product_item_pos += 1 | |
6 | -%> | |
7 | - | |
8 | 1 | <% extra_content = @plugins.dispatch(:asset_product_extras, product, product.enterprise).collect { |content| instance_eval(&content) } %> |
9 | 2 | <% extra_properties = @plugins.dispatch(:asset_product_properties, product)%> |
10 | 3 | |
11 | -<li class="product-item <%= ( pos % 2 == 0 ) ? 'odd' : 'even' %>"> | |
12 | - <%= link_to_product product, :class => 'product-pic', :style => 'background-image:url(%s)' % product.default_image(:minor) %> | |
13 | - <strong> | |
14 | - <%= link_to_product product %> | |
15 | - </strong> | |
16 | - <ul> | |
17 | - <li> <%= _('Price: %s') % (product.price ? product.price : _('Not informed')) %> </li> | |
18 | - <% if product.enterprise && product.display_supplier_on_search? %> | |
19 | - <li> <%= _('Supplier: %s') % link_to_homepage(product.enterprise.name, product.enterprise.identifier) %> </li> | |
20 | - <% end %> | |
4 | +<li class="search-product-item"> | |
21 | 5 | |
22 | - <li> <%= _('Category:') + ' ' + link_to_product_category(product.product_category) %> </li> | |
6 | + <div class="search-product-item-first-column"> | |
7 | + <%= render :partial => 'search/image', :object => product %> | |
23 | 8 | |
24 | - <% extra_properties.each do |property| %> | |
25 | - <li><%= property[:name] + ': ' + instance_eval(&property[:content]) %></li> | |
9 | + <% if product.available %> | |
10 | + <% if product.price && product.price > 0 %> | |
11 | + <% has_discount = product.discount && product.discount > 0 %> | |
12 | + <% if product.price %> | |
13 | + <span class="search-product-price-textid"><%=_("from") if has_discount %></span><%= price_span(product.price, :class => "search-product-price " + (has_discount ? 'with-discount' : '')) %> | |
14 | + <% if has_discount %> | |
15 | + <span class="search-product-price-textid"><%=_("by")%></span><%= price_span(product.price_with_discount, :class => "search-product-price") %> | |
16 | + <% end %> | |
17 | + <% if product.unit %> | |
18 | + <span class="search-product-unit"> <%= _('/') %> <%= product.unit.name %></span> | |
19 | + <% end %> | |
20 | + <% end %> | |
21 | + <div class="search-product-inputs-info"> | |
22 | + <% if p = product.percentage_from_solidarity_economy %> | |
23 | + <div class="search-product-percentage-from-solidarity-economy search-product-ecosol-percentage-icon-<%= p[0].to_s %>" | |
24 | + title="<%=_('Percentage of inputs from solidarity economy')%>"> | |
25 | + <%= p[1] %> | |
26 | + </div> | |
27 | + <% end %> | |
28 | + | |
29 | + <% if product.price_described? %> | |
30 | + <% title = product.inputs.map{ |i| | |
31 | + '<div class="search-product-input-dots-to-price">' + | |
32 | + '<div class="search-product-input-name">' + i.product_category.name + '</div>' + | |
33 | + price_span(i.price_per_unit*i.amount_used, :class => 'search-product-input-price') + | |
34 | + '</div>' }.join('') %> | |
35 | + <% title += product.price_details.map{ |p| | |
36 | + '<div class="search-product-input-dots-to-price">' + | |
37 | + '<div class="search-product-input-name">' + p.production_cost.name + '</div>' + | |
38 | + price_span(p.price, :class => 'search-product-input-price') + | |
39 | + '</div>' }.join('') %> | |
40 | + <%= link_to_function _("Open Price"), '', :title => title, :class => "search-product-price-details" %> | |
41 | + <% end %> | |
42 | + </div> | |
43 | + <% end %> | |
44 | + <% else %> | |
45 | + <span class="product-not-available"><%= _('Not available') %></div> | |
26 | 46 | <% end %> |
27 | - </ul> | |
47 | + | |
48 | + </div> | |
49 | + <div class="search-product-item-second-column"> | |
50 | + <%= link_to_product product, :class => 'search-result-title' %> | |
51 | + <div class="search-product-supplier"> | |
52 | + <span class="search-field-label"><%= _('Supplier') %> </span><%= link_to_homepage(product.enterprise.name, product.enterprise.identifier) %> | |
53 | + </div> | |
54 | + <div class="search-product-description"> | |
55 | + <% if product.description %> | |
56 | + <% desc_stripped = strip_tags(product.description) %> | |
57 | + <span class="search-field-label"><%= _('Description') %> </span><%= excerpt(desc_stripped, desc_stripped.first(3), 300) %> | |
58 | + <% end %> | |
59 | + </div> | |
60 | + </div> | |
61 | + <div class="search-product-item-third-column"> | |
62 | + <div class="search-product-region"> | |
63 | + <% if product.enterprise.region %> | |
64 | + <span class="search-field-label"><%= _('City') %></span> | |
65 | + <br /><%= city_with_state(product.enterprise.region) %> | |
66 | + <% end %> | |
67 | + </div> | |
68 | + <div class="search-product-qualifiers"> | |
69 | + <% if product.product_qualifiers.count > 0 %> | |
70 | + <span class="search-field-label"><%= _('Qualifiers') %></span> | |
71 | + <% product.product_qualifiers.each do |pq| %> | |
72 | + <% if pq.qualifier %> | |
73 | + <span class="search-product-qualifier"><%= pq.qualifier.name + (pq.certifier.nil? ? _(";") : '') %></span> | |
74 | + <% end %> | |
75 | + <% if pq.certifier %> | |
76 | + <span class="search-product-certifier"> <%= _('cert. ') + pq.certifier.name + _(";") %></span> | |
77 | + <% end %> | |
78 | + <% end %> | |
79 | + <% end %> | |
80 | + </div> | |
81 | + </div> | |
28 | 82 | |
29 | 83 | <%= extra_content.join('\n') %> |
84 | + <% extra_properties.each do |property| %> | |
85 | + <div><%= property[:name] + ': ' + instance_eval(&property[:content]) %></div> | |
86 | + <% end %> | |
30 | 87 | |
88 | + <br /><br /> | |
31 | 89 | </li> | ... | ... |
app/views/search/_product_categories_menu.rhtml
... | ... | @@ -1,42 +0,0 @@ |
1 | -<% if @product_category %> | |
2 | - <h3 class="current-cat-path"> | |
3 | - <%= @product_category.hierarchy.map {|cat| ((cat == @product_category) ? content_tag('span', cat.name) : link_to((cat.name), params.merge({:product_category => cat.id}))) }.join(' → ') %> | |
4 | - </h3> | |
5 | -<% end %> | |
6 | - | |
7 | -<% if product_categories_menu %> | |
8 | - | |
9 | -<div id="product-categories-menu"> | |
10 | - <ul> | |
11 | - <% if product_categories_menu.empty? %> | |
12 | - <% if @product_category %> | |
13 | - <li class="cat-empty"> <%= _('There is no sub-categories for %s.') % @product_category.name %> </li> | |
14 | - <% else %> | |
15 | - <li class="cat-empty"> <%= _('There is no categories.') %> </li> | |
16 | - <% end %> | |
17 | - <% end %> | |
18 | - <% product_categories_menu.each do |cat, hits, childs| %> | |
19 | - <li class="cat-parent" > | |
20 | - <%= link_to( | |
21 | - cat.name + " " + content_tag('small', "(#{hits})"), | |
22 | - params.merge({:product_category => cat.id}) | |
23 | - ) %> | |
24 | - <% if !childs.blank? %> | |
25 | - <div> | |
26 | - <ul> | |
27 | - <% childs.each do |child, child_hits| %> | |
28 | - <li class="cat-child"> <%= link_to( | |
29 | - child.name + " " + content_tag('small', "(#{child_hits})"), | |
30 | - params.merge({:product_category => child.id}) | |
31 | - ) %> </li> | |
32 | - <% end %> | |
33 | - </ul> | |
34 | - </div> | |
35 | - <% end %> | |
36 | - </li> | |
37 | - <% end %> | |
38 | - </ul> | |
39 | -</div> | |
40 | - | |
41 | -<% end %> | |
42 | - |
app/views/search/_profile.rhtml
1 | -<%= profile_image_link profile, :portrait %> | |
1 | +<li class="search-profile-item"> | |
2 | + <% if @empty_query or @results.size > 1 or !profile.enterprise? %> | |
3 | + <%= profile_image_link profile, :portrait, 'div' %> | |
4 | + <% else %> | |
5 | + <div class="search-enterprise-item"> | |
6 | + <div class="search-enterprise-item-column-left"> | |
7 | + <%= profile_image_link profile, :portrait, 'div' %> | |
8 | + </div> | |
9 | + <div class="search-enterprise-item-column-right"> | |
10 | + <%= link_to_homepage(profile.name, profile.identifier, :class => "search-result-title") %> | |
11 | + <div class="search-enterprise-description"> | |
12 | + <% if profile.description %> | |
13 | + <% body_stripped = strip_tags(profile.description) %> | |
14 | + <% elsif profile.home_page and profile.home_page.body %> | |
15 | + <% body_stripped = strip_tags(profile.home_page.body) %> | |
16 | + <% end %> | |
17 | + <%= excerpt(body_stripped, body_stripped.first(3), 200) if body_stripped %> | |
18 | + </div> | |
19 | + <div class="search-enterprise-region"> | |
20 | + <span class="search-enterprise-region-label"><%= _("City") %></span> | |
21 | + <% if profile.region %> | |
22 | + <span class="search-enterprise-region-name"><%= city_with_state(profile.region) %></span> | |
23 | + <% end %> | |
24 | + </div> | |
25 | + <% if !profile.description.blank? %> | |
26 | + <div><%= profile.description %></div><br /> | |
27 | + <% end %> | |
28 | + | |
29 | + <div class="search-enterprise-categorization"> | |
30 | + <% profile.top_level_categorization.each do |parent, children| %> | |
31 | + <% if parent.name != "Territórios" %> | |
32 | + <div class="search-enterprise-category-<%=parent.id%> search-enterprise-category"> | |
33 | + <span class="search-enterprise-categorization-parent"><%= parent.name %></span> | |
34 | + <span class="search-enterprise-categorization-children"> | |
35 | + <%= children.collect(&:name).join(', ') %> | |
36 | + </span> | |
37 | + </div> | |
38 | + <% end %> | |
39 | + <% end %> | |
40 | + </div> | |
41 | + </div> | |
42 | + | |
43 | + <hr class="clearfix" /> | |
44 | + </div> | |
45 | + <% end %> | |
46 | +</li> | ... | ... |
... | ... | @@ -0,0 +1,19 @@ |
1 | +<div class="search-results-header <%= "search-no-results" if @results[@asset].nil? or @results[@asset].length == 0 %>"> | |
2 | + <% if !@empty_query %> | |
3 | + <div class="search-results-header-information"> | |
4 | + <%= label_total_found(@asset, @results[@asset].total_entries) %> | |
5 | + <% if params[:display] != 'map' %> | |
6 | + <span class="current-page"><%= _("Showing page %s of %s") % [@results[@asset].current_page, @results[@asset].total_pages] %></span> | |
7 | + <% end %> | |
8 | + </div> | |
9 | + | |
10 | + <div class="search-results-header-facets-order-by"> | |
11 | + <%= facets_unselect_menu(@asset) %> | |
12 | + <%= order_by(@asset) if params[:display] != 'map' %> | |
13 | + </div> | |
14 | + <% else %> | |
15 | + <div id='search-filter-title'><%= @filter_title if @filter_title %></div> | |
16 | + <% end %> | |
17 | + | |
18 | + <div style="clear: both"></div> | |
19 | +</div> | ... | ... |
app/views/search/_search_form.rhtml
1 | 1 | <div class='search-form'> |
2 | -<% simple_search = false unless defined? simple_search %> | |
3 | 2 | |
4 | -<% form_tag( { :controller => 'search', :action => 'index', :asset => nil, :category_path => ( @category ? @category.explode_path : [] ) }, | |
5 | - :method => 'get', :class => 'search_form' ) do %> | |
6 | - <%= '<h3>%s</h3>' % form_title if defined? form_title %> | |
7 | - | |
8 | - <%= hidden_field_tag :display, params[:display] %> | |
9 | - | |
10 | - <%= hidden_field_tag :asset, params[:asset] %> | |
11 | - | |
12 | - <div class="search-field"> | |
13 | - <span class="formfield"> | |
14 | - <%= text_field_tag 'query', @query, :id => ( lightbox? ? 'popup-search-input' : '' ), :size => 50 %> | |
15 | - <%= javascript_tag 'setTimeout("$(\"popup-search-input\").focus()", 10 )' if lightbox? %> | |
16 | - </span> | |
17 | - <%= submit_button(:search, _('Search'), :name => :search_whole_site_no) %> | |
18 | - <% if @category %> | |
19 | - <%= submit_button(:search, _('Search in whole site'), :name => :search_whole_site_yes) %> | |
3 | + <% form_tag( { :controller => 'search', :action => @asset ? @asset : 'index', :asset => nil, :category_path => ( @category ? @category.explode_path : [] ) }, | |
4 | + :method => 'get', :class => 'search_form' ) do %> | |
5 | + | |
6 | + <%= hidden_field_tag :display, params[:display] %> | |
7 | + | |
8 | + <% params_uri = CGI::unescape(request.request_uri) %> | |
9 | + <% if params_uri.index('?') %> | |
10 | + <% params_uri[(params_uri.index('?')+1)..-1].to_s.split("&").each do |part| %> | |
11 | + <% if part.start_with? "facet" %> | |
12 | + <% name_value = part.split("=") %> | |
13 | + <%= hidden_field_tag name_value[0], name_value[1] %> | |
14 | + <% end %> | |
15 | + <% end %> | |
20 | 16 | <% end %> |
21 | - </div> | |
22 | - | |
23 | - <div id='advanced-search-options' style="display: <%= simple_search ? 'none' : 'block' %>"> | |
24 | - <div class="search-options search-within"> | |
25 | - <h4><%= _('Search within:') %></h4> | |
26 | - <br style='clear:left'/> | |
27 | - <div> | |
28 | - <span class="formfield"> | |
29 | - <%= select_city %> | |
30 | - </span> | |
31 | - <span class="formfield"> | |
32 | - <%= labelled_select(_('Distance:'), 'radius', :first, :last, nil, [15, 30, 50, 100, 150, 200, 300, 400, 500, 1000].map{|n|[n, n.to_s + 'km']}) %> | |
33 | - </span> | |
34 | - </div> | |
35 | - </div><!-- fim class="search-options" --> | |
36 | - | |
37 | - <div class="search-options search-for"> | |
38 | - <h4><%= _('Search for:') %></h4> | |
39 | - <ul> | |
40 | - <% @search_in.map { |t,n| [t,getterm(n)] } . | |
41 | - sort_by(&:last).each do |thing, name| %> | |
42 | - <li> | |
43 | - <%= labelled_check_box name, 'find_in[]', thing.to_s, @searching[thing.to_sym] %> | |
44 | - </li> | |
45 | - <% end %> | |
46 | - </ul> | |
47 | - <br style="clear:both" /> | |
48 | - </div><!-- fim class="search-options" --> | |
49 | - </div><!-- end id="advanced-search-options" --> | |
17 | + | |
18 | + <div class="search-field"> | |
19 | + <span class="formfield"> | |
20 | + <%= text_field_tag 'query', @query, :id => 'search-input', :size => 50 %> | |
21 | + <%= javascript_tag "jQuery('#search-input').attr('title', \"#{hint}\").hint()" if defined?(hint) %> | |
22 | + </span> | |
23 | + | |
24 | + <%= submit_button(:search, _('Search')) %> | |
25 | + </div> | |
50 | 26 | |
51 | - <% if simple_search %> | |
52 | - <%= link_to_function(_('More options'), nil, :id => 'advanced_search_link') do |page| | |
53 | - page['advanced_search_link'].hide | |
54 | - page['advanced-search-options'].toggle | |
55 | - end %> | |
27 | + <% end %> | |
28 | + | |
29 | + <% if @empty_query %> | |
30 | + <% hint = environment.search_hints[@asset] %> | |
31 | + <% if hint and !hint.blank? %> | |
32 | + <div class="search-hint"><%= hint %></div> | |
33 | + <% end %> | |
56 | 34 | <% end %> |
57 | 35 | |
58 | - <% if lightbox?; button_bar do %> | |
59 | - <%= lightbox_close_button _('Close') %> | |
60 | - <% end; end %> | |
61 | - | |
62 | -<% end %> | |
63 | - | |
64 | -</div> <!-- id="search-form" --> | |
36 | + <div style="clear: both"></div> | |
37 | +</div> | ... | ... |
... | ... | @@ -0,0 +1,13 @@ |
1 | +<li class="search-text-article-item article-item"> | |
2 | + <%= link_to(text_article.title, text_article.url, :class => "search-result-title") %> | |
3 | + | |
4 | + <div class="search-content-first-column"> | |
5 | + <%= render :partial => 'image', :object => text_article %> | |
6 | + </div> | |
7 | + <table class="noborder search-content-second-column"> | |
8 | + <%= render :partial => 'article_common', :object => text_article %> | |
9 | + </table> | |
10 | + <%= render :partial => 'article_last_change', :object => text_article %> | |
11 | + | |
12 | + <div style="clear: both"></div> | |
13 | +</li> | ... | ... |
... | ... | @@ -0,0 +1,25 @@ |
1 | +<li class="search-uploaded-file-item article-item"> | |
2 | + <%= link_to uploaded_file.filename, uploaded_file.view_url, :class => 'search-result-title' %> | |
3 | + | |
4 | + <div class="search-content-first-column"> | |
5 | + <%= render :partial => 'image', :object => uploaded_file %> | |
6 | + </div> | |
7 | + | |
8 | + <table class="noborder search-content-second-column"> | |
9 | + <%= render :partial => 'article_author', :object => uploaded_file %> | |
10 | + <%= render :partial => 'article_description', :object => uploaded_file %> | |
11 | + | |
12 | + <% if uploaded_file.parent and uploaded_file.parent.published? %> | |
13 | + <tr class="search-uploaded-file-parent"> | |
14 | + <td class="search-field-label"><%= uploaded_file.parent.gallery? ? _("Gallery") : _("Folder") %></td> | |
15 | + <td><%= link_to uploaded_file.parent.name, uploaded_file.parent.url %></td> | |
16 | + </tr> | |
17 | + <% end %> | |
18 | + | |
19 | + <%= render :partial => 'article_tags', :object => uploaded_file.tags %> | |
20 | + <%= render :partial => 'article_categories', :object => uploaded_file.categories %> | |
21 | + </table> | |
22 | + <%= render :partial => 'article_last_change', :object => uploaded_file %> | |
23 | + | |
24 | + <div style="clear:both"></div> | |
25 | +</li> | ... | ... |
app/views/search/articles.rhtml
1 | -<%= search_page_title( _('Articles'), { :query => @query, | |
2 | - :category => @category ? @category.name : nil, | |
3 | - :total_results => @total_results, | |
4 | - :region => @region ? @region.name : nil, | |
5 | - :distance => @radius } ) %> | |
1 | +<%= search_page_title( @titles[:articles], @category ) %> | |
6 | 2 | |
7 | -<%= search_page_link_to_all( { :asset => params[:asset], | |
8 | - :category => @category }) %> | |
3 | +<div id="search-column-left"> | |
4 | + <% if !@empty_query %> | |
5 | + <%= facets_menu(:articles, @facets) %> | |
6 | + <% end %> | |
7 | +</div> | |
9 | 8 | |
10 | -<%= render :partial => 'search_form', :locals => { :form_title => @query.blank? ? _('Search') : _("Refine your search"), :simple_search => true } %> | |
9 | +<div id="search-column-right"> | |
10 | + <%= render :partial => 'search_form', :locals => { :hint => _('Type the title, author or content desired') } %> | |
11 | + <%= render :partial => 'results_header' %> | |
11 | 12 | |
12 | -<%# FIXME ARMENGUE %> | |
13 | -<%= display_results(false) %> | |
13 | + <%= display_results %> | |
14 | + <%= pagination_links @results[:articles] %> | |
15 | +</div> | |
14 | 16 | |
15 | -<%= pagination_links @results.values.first %> | |
16 | - | |
17 | -<br style="clear:both" /> | |
17 | +<div style="clear: both"></div> | ... | ... |
app/views/search/category_index.rhtml
... | ... | @@ -1,23 +0,0 @@ |
1 | -<div id="view-category"> | |
2 | - | |
3 | - <div id="category-image"><%= image_tag(@category.image.public_filename(:thumb), :id => 'category-image') if @category.image %></div> | |
4 | - <h1 id="category-name"><%= @category.name %></h1> | |
5 | - | |
6 | - <%= render :partial => 'display_results' %> | |
7 | - | |
8 | - <div id="category-childs"> | |
9 | - <h2> <%= _('Sub-categories') %> </h2> | |
10 | - <% if @category.children.empty? %> | |
11 | - <strong id="cat-no-child"><%= _('No sub-categories') %></strong> | |
12 | - <% else %> | |
13 | - <ul> | |
14 | - <% @category.children.each do |c| %> | |
15 | - <li> <%= link_to_category c, false %> </li> | |
16 | - <% end %> | |
17 | - </ul> | |
18 | - <% end %> | |
19 | - </div><!-- end id="child-categories" --> | |
20 | - | |
21 | -<br style="clear:both" /> | |
22 | -</div><!-- end id="view-category" --> | |
23 | - |