Commit 7e54e8ab2527fd9c44ade31f8eba54ec8c090fcb

Authored by Braulio Bhavamitra
1 parent afbcb3d1

Redesigned search

- Standardized search for all entities type
- New category search based on a facet view
Showing 43 changed files with 1005 additions and 600 deletions   Show diff stats
app/controllers/public/search_controller.rb
1 class SearchController < PublicController 1 class SearchController < PublicController
2 2
3 MAP_SEARCH_LIMIT = 2000 3 MAP_SEARCH_LIMIT = 2000
4 - SINGLE_SEARCH_LIMIT = 20  
5 - MULTIPLE_SEARCH_LIMIT = 6 4 + LIST_SEARCH_LIMIT = 20
  5 + BLOCKS_SEARCH_LIMIT = 18
  6 + MULTIPLE_SEARCH_LIMIT = 8
6 7
7 helper TagsHelper 8 helper TagsHelper
8 include SearchHelper 9 include SearchHelper
  10 + include ActionView::Helpers::NumberHelper
9 11
10 before_filter :load_category 12 before_filter :load_category
11 before_filter :load_search_assets 13 before_filter :load_search_assets
  14 + before_filter :load_query
12 15
13 no_design_blocks 16 no_design_blocks
14 17
15 - def articles  
16 - @asset = :articles  
17 - @query = params[:query] || ''  
18 - @order ||= [@asset]  
19 - @results ||= {}  
20 - @filter = filter 18 + def facets_browse
  19 + @asset = params[:asset]
  20 + @asset_class = asset_class(@asset)
21 21
22 - pg_options = paginate_options(@asset, limit, params[:per_page])  
23 - if !@query.blank?  
24 - ret = asset_class(@asset).find_by_contents(@query, pg_options, solr_options(@asset, params[:facet], params[:order_by]))  
25 - @results[@asset] = ret[:results]  
26 - @facets = ret[:facets]  
27 - else  
28 - @results[@asset] = asset_class(@asset).send('paginate', :all, pg_options)  
29 - @facets = {} 22 + @facets_only = true
  23 + send(@asset)
  24 +
  25 + @facet = @asset_class.map_facets_for(environment).find { |facet| facet[:id] == params[:facet_id] }
  26 + raise 'Facet not found' if @facet.nil?
  27 +
  28 + render :layout => false
  29 + end
  30 +
  31 + def articles
  32 + @filter = params[:filter] ? filter : nil
  33 + @filter_title = params[:filter] ? filter_description(@asset, @filter) : nil
  34 + if !@empty_query
  35 + full_text_search
  36 + elsif params[:filter]
  37 + @results[@asset] = @environment.articles.more_recent.paginate(paginate_options)
30 end 38 end
31 end 39 end
32 40
33 - alias :contents :articles 41 + def contents
  42 + redirect_to params.merge(:action => :articles)
  43 + end
34 44
35 def people 45 def people
36 - @asset = :people  
37 - @query = params[:query] || ''  
38 - @order ||= [@asset]  
39 - @results ||= {}  
40 - @filter = filter  
41 - @title = self.filter_description(params[:action] + '_' + @filter )  
42 -  
43 - @results[@asset] = @environment.people.visible.send(@filter)  
44 - if !@query.blank?  
45 - ret = @results[@asset].find_by_contents(@query, {}, solr_options(@asset, params[:facet], params[:order_by]))  
46 - @results[@asset] = ret[:results]  
47 - @facets = ret[:facets] 46 + if !@empty_query
  47 + full_text_search
48 else 48 else
  49 + @results[@asset] = @environment.people.visible.send(@filter).paginate(paginate_options)
49 @facets = {} 50 @facets = {}
50 end 51 end
51 - @results[@asset] = @results[@asset].compact.paginate(:per_page => limit, :page => params[:page])  
52 end 52 end
53 53
54 def products 54 def products
55 - @asset = :products  
56 - @query = params[:query] || ''  
57 - @order ||= [@asset]  
58 - @results ||= {}  
59 -  
60 - pg_options = paginate_options(@asset, limit, params[:per_page])  
61 - if !@query.blank?  
62 - ret = asset_class(@asset).find_by_contents(@query, pg_options, solr_options(@asset, params[:facet], params[:order_by]))  
63 - @results[@asset] = ret[:results]  
64 - @facets = ret[:facets]  
65 - else  
66 - @results[@asset] = asset_class(@asset).send('paginate', :all, pg_options)  
67 - @facets = {} 55 + if !@empty_query
  56 + full_text_search
68 end 57 end
69 end 58 end
70 59
71 def enterprises 60 def enterprises
72 - @asset = :enterprises  
73 - @query = params[:query] || ''  
74 - @order ||= [@asset]  
75 - @results ||= {}  
76 -  
77 - pg_options = paginate_options(@asset, limit, params[:per_page])  
78 - if !@query.blank?  
79 - ret = asset_class(@asset).find_by_contents(@query, pg_options, solr_options(@asset, params[:facet], params[:order_by]))  
80 - @results[@asset] = ret[:results]  
81 - @facets = ret[:facets] 61 + if !@empty_query
  62 + full_text_search
82 else 63 else
83 - @results[@asset] = asset_class(@asset).send('paginate', :all, pg_options)  
84 - @facets = {} 64 + @filter_title = _('Enterprises from network')
  65 + @results[@asset] = asset_class(@asset).paginate(paginate_options)
85 end 66 end
86 end 67 end
87 68
88 def communities 69 def communities
89 - @asset = :communities  
90 - @query = params[:query] || ''  
91 - @order ||= [@asset]  
92 - @results ||= {}  
93 - @filter = filter  
94 - @title = self.filter_description(params[:action] + '_' + @filter )  
95 -  
96 - @results[@asset] = @environment.communities.visible.send(@filter)  
97 - if !@query.blank?  
98 - ret = @results[@asset].find_by_contents(@query, {}, solr_options(@asset, params[:facet], params[:order_by]))  
99 - @results[@asset] = ret[:results]  
100 - @facets = ret[:facets] 70 + if !@empty_query
  71 + full_text_search
101 else 72 else
102 - @facets = {} 73 + @results[@asset] = @environment.communities.visible.send(@filter).paginate(paginate_options)
103 end 74 end
104 - @results[@asset] = @results[@asset].compact.paginate(:per_page => limit, :page => params[:page])  
105 end 75 end
106 76
107 def events 77 def events
108 - @asset = :events  
109 - params[:asset] |= [@asset]  
110 - @query = params[:query] || ''  
111 - @order ||= [@asset]  
112 - @results ||= {}  
113 @category_id = @category ? @category.id : nil 78 @category_id = @category ? @category.id : nil
114 79
115 if params[:year] || params[:month] 80 if params[:year] || params[:month]
@@ -129,9 +94,7 @@ class SearchController &lt; PublicController @@ -129,9 +94,7 @@ class SearchController &lt; PublicController
129 @results[@asset] = Event.send('find', :all) 94 @results[@asset] = Event.send('find', :all)
130 end 95 end
131 else 96 else
132 - pg_options = paginate_options(@asset, limit, params[:per_page])  
133 - solr_options = solr_options(@asset, params[:facet], params[:per_page])  
134 - @results[@asset] = Event.find_by_contents(@query, pg_options, solr_options)[:results] 97 + full_text_search
135 end 98 end
136 99
137 @selected_day = nil 100 @selected_day = nil
@@ -157,6 +120,7 @@ class SearchController &lt; PublicController @@ -157,6 +120,7 @@ class SearchController &lt; PublicController
157 @results = {} 120 @results = {}
158 @order = [] 121 @order = []
159 @names = {} 122 @names = {}
  123 + @results_only = true
160 124
161 @enabled_searchs.select { |key,description| @searching[key] }.each do |key, description| 125 @enabled_searchs.select { |key,description| @searching[key] }.each do |key, description|
162 send(key) 126 send(key)
@@ -186,19 +150,17 @@ class SearchController &lt; PublicController @@ -186,19 +150,17 @@ class SearchController &lt; PublicController
186 @names = {} 150 @names = {}
187 limit = MULTIPLE_SEARCH_LIMIT 151 limit = MULTIPLE_SEARCH_LIMIT
188 [ 152 [
189 - [ :people, _('People'), recent('people', limit) ],  
190 - [ :enterprises, __('Enterprises'), recent('enterprises', limit) ],  
191 - [ :products, _('Products'), recent('products', limit) ],  
192 - [ :events, _('Upcoming events'), upcoming_events({:per_page => limit}) ],  
193 - [ :communities, __('Communities'), recent('communities', limit) ],  
194 - [ :most_commented_articles, _('Most commented articles'), most_commented_articles(limit) ],  
195 - [ :articles, _('Articles'), recent('text_articles', limit) ]  
196 - ].each do |key, name, list|  
197 - @order << key  
198 - @results[key] = list  
199 - @names[key] = name 153 + [ :people, _('People'), :recent_people ],
  154 + [ :enterprises, _('Enterprises'), :recent_enterprises ],
  155 + [ :products, _('Products'), :recent_products ],
  156 + [ :events, _('Upcoming events'), :upcoming_events ],
  157 + [ :communities, _('Communities'), :recent_communities ],
  158 + [ :articles, _('Contents'), :recent_articles ]
  159 + ].each do |asset, name, filter|
  160 + @order << asset
  161 + @results[asset] = @category.send(filter, limit)
  162 + @names[asset] = name
200 end 163 end
201 - @facets = {}  
202 end 164 end
203 165
204 def tags 166 def tags
@@ -218,50 +180,33 @@ class SearchController &lt; PublicController @@ -218,50 +180,33 @@ class SearchController &lt; PublicController
218 180
219 def events_by_day 181 def events_by_day
220 @selected_day = build_date(params[:year], params[:month], params[:day]) 182 @selected_day = build_date(params[:year], params[:month], params[:day])
221 - if params[:category_id] and Category.exists?(params[:category_id])  
222 - @events_of_the_day = environment.events.by_day(@selected_day).in_category(Category.find(params[:category_id]))  
223 - else  
224 - @events_of_the_day = environment.events.by_day(@selected_day)  
225 - end 183 + @events_of_the_day = environment.events.by_day(@selected_day)
226 render :partial => 'events/events_by_day' 184 render :partial => 'events/events_by_day'
227 end 185 end
228 186
229 ####################################################### 187 #######################################################
230 protected 188 protected
231 189
232 - def recent(asset, limit = nil)  
233 - options = {:page => 1, :per_page => limit, :order => 'created_at DESC, id DESC'}  
234 -  
235 - if asset == :events  
236 - finder_method = 'find'  
237 - options.delete(:page)  
238 - options.delete(:per_page)  
239 - else  
240 - finder_method = 'paginate'  
241 - end  
242 -  
243 - asset_class(asset).send(finder_method, :all, category_options_for_find(asset_class(asset), {:order => "#{asset_table(asset)}.name"}.merge(options)))  
244 - end  
245 -  
246 - def most_commented_articles(limit=10, options={})  
247 - options = {:page => 1, :per_page => limit, :order => 'comments_count DESC'}.merge(options)  
248 - Article.paginate(:all, category_options_for_find(Article, options))  
249 - end  
250 -  
251 - def upcoming_events(options = {})  
252 - options.delete(:page)  
253 - options.delete(:per_page) 190 + def load_query
  191 + @asset = params[:action].to_sym
  192 + @order ||= [@asset]
  193 + @results ||= {}
  194 + @filter = filter
  195 + @filter_title = filter_description(@asset, @filter)
254 196
255 - Event.find(:all, {:include => :categories, :conditions => [ 'categories.id = ? and start_date >= ?', category_id, Date.today ], :order => 'start_date' }.merge(options)) 197 + @query = params[:query] || ''
  198 + @empty_query = @category.nil? && @query.blank?
256 end 199 end
257 200
258 - def current_events(year, month, options={})  
259 - options.delete(:page)  
260 - options.delete(:per_page)  
261 -  
262 - range = Event.date_range(year, month)  
263 -  
264 - Event.find(:all, {:include => :categories, :conditions => { 'categories.id' => category_id, :start_date => range }}.merge(options)) 201 + def load_category
  202 + unless params[:category_path].blank?
  203 + path = params[:category_path].join('/')
  204 + @category = environment.categories.find_by_path(path)
  205 + if @category.nil?
  206 + render_not_found(path)
  207 + end
  208 + @category_id = @category.id
  209 + end
265 end 210 end
266 211
267 FILTERS = %w( 212 FILTERS = %w(
@@ -277,112 +222,83 @@ class SearchController &lt; PublicController @@ -277,112 +222,83 @@ class SearchController &lt; PublicController
277 end 222 end
278 end 223 end
279 224
280 - def filter_description(str) 225 + def filter_description(asset, filter)
281 { 226 {
282 - 'contents_more_recent' => _('More recent contents'),  
283 - 'contents_more_popular' => _('More popular contents'),  
284 - 'people_more_recent' => _('More recent people'),  
285 - 'people_more_active' => _('More active people'),  
286 - 'people_more_popular' => _('More popular people'),  
287 - 'communities_more_recent' => _('More recent communities'),  
288 - 'communities_more_active' => _('More active communities'),  
289 - 'communities_more_popular' => _('More popular communities'),  
290 - }[str] || str  
291 - end  
292 -  
293 - attr_reader :category  
294 - attr_reader :category_id  
295 -  
296 - def load_category  
297 - unless params[:category_path].blank?  
298 - path = params[:category_path].join('/')  
299 - @category = environment.categories.find_by_path(path)  
300 - if @category.nil?  
301 - render_not_found(path)  
302 - end  
303 - @category_id = @category.id  
304 - end 227 + 'articles_more_recent' => _('More recent contents from network'),
  228 + 'articles_more_popular' => _('More popular contents from network'),
  229 + 'people_more_recent' => _('More recent people from network'),
  230 + 'people_more_active' => _('More active people from network'),
  231 + 'people_more_popular' => _('More popular people from network'),
  232 + 'communities_more_recent' => _('More recent communities from network'),
  233 + 'communities_more_active' => _('More active communities from network'),
  234 + 'communities_more_popular' => _('More popular communities from network'),
  235 + }[asset.to_s + '_' + filter]
305 end 236 end
306 237
307 def load_search_assets 238 def load_search_assets
308 @enabled_searchs = [ 239 @enabled_searchs = [
309 - [ :articles, N_('Articles') ],  
310 - [ :enterprises, N_('Enterprises') ],  
311 - [ :people, N_('People') ],  
312 - [ :communities, N_('Communities') ],  
313 - [ :products, N_('Products') ],  
314 - [ :events, N_('Events') ] 240 + [ :articles, _('Contents') ],
  241 + [ :enterprises, _('Enterprises') ],
  242 + [ :people, _('People') ],
  243 + [ :communities, _('Communities') ],
  244 + [ :products, _('Products and Services') ],
  245 + [ :events, _('Events') ]
315 ].select {|key, name| !environment.enabled?('disable_asset_' + key.to_s) } 246 ].select {|key, name| !environment.enabled?('disable_asset_' + key.to_s) }
316 247
317 @searching = {} 248 @searching = {}
  249 + @titles = {}
318 @enabled_searchs.each do |key, name| 250 @enabled_searchs.each do |key, name|
  251 + @titles[key] = name
319 @searching[key] = params[:action] == 'index' || params[:action] == key.to_s 252 @searching[key] = params[:action] == 'index' || params[:action] == key.to_s
320 end 253 end
321 end 254 end
322 255
323 - def paginate_options(asset, limit, page)  
324 - result = { :per_page => limit, :page => page }  
325 - end  
326 -  
327 - def solr_options(asset, facet, solr_order)  
328 - result = {}  
329 -  
330 - if asset_class(asset).methods.include?('facets')  
331 - result.merge!(:facets => {:zeros => false, :sort => :count, :fields => asset_class(asset).facets.keys,  
332 - :browse => facet ? facet.map{ |k,v| k.to_s+':"'+v.to_s+'"'} : ''})  
333 - end  
334 -  
335 - if solr_order  
336 - result[:order_by] = solr_order  
337 - end  
338 -  
339 - result  
340 - end  
341 -  
342 def limit 256 def limit
343 - searching = @searching.values.select{|v|v} 257 + searching = @searching.values.select{ |v| v }
344 if params[:display] == 'map' 258 if params[:display] == 'map'
345 MAP_SEARCH_LIMIT 259 MAP_SEARCH_LIMIT
  260 + elsif searching.size <= 1
  261 + if [:people, :communities].include? @asset
  262 + BLOCKS_SEARCH_LIMIT
  263 + elsif @asset == :enterprises and @empty_query
  264 + BLOCKS_SEARCH_LIMIT
  265 + else
  266 + LIST_SEARCH_LIMIT
  267 + end
346 else 268 else
347 - (searching.size <= 1) ? SINGLE_SEARCH_LIMIT : MULTIPLE_SEARCH_LIMIT 269 + MULTIPLE_SEARCH_LIMIT
348 end 270 end
349 end 271 end
350 272
351 - def category_options_for_find(klass, options={}, date_range = nil)  
352 - if defined? options[:product_category]  
353 - prod_cat = options.delete(:product_category)  
354 - end  
355 -  
356 - case klass.name  
357 - when 'Comment'  
358 - {:joins => 'inner join articles_categories on articles_categories.article_id = comments.article_id', :conditions => ['articles_categories.category_id = (?)', category_id]}.merge!(options)  
359 - when 'Product'  
360 - if prod_cat  
361 - {: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)  
362 - else  
363 - {:joins => 'inner join categories_profiles on products.enterprise_id = categories_profiles.profile_id', :conditions => ['categories_profiles.category_id = (?)', category_id]}.merge!(options)  
364 - end  
365 - when 'Article', 'TextArticle'  
366 - {:joins => 'inner join articles_categories on (articles_categories.article_id = articles.id)', :conditions => ['articles_categories.category_id = (?)', category_id]}.merge!(options)  
367 - when 'Event'  
368 - conditions =  
369 - if date_range  
370 - ['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} ]  
371 - else  
372 - ['articles_categories.category_id = (?) ', category_id ]  
373 - end  
374 - {:joins => 'inner join articles_categories on (articles_categories.article_id = articles.id)', :conditions => conditions}.merge!(options)  
375 - when 'Enterprise'  
376 - if prod_cat  
377 - {: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)  
378 - else  
379 - {:joins => 'inner join categories_profiles on (categories_profiles.profile_id = profiles.id)', :conditions => ['categories_profiles.category_id = (?)', category_id]}.merge!(options)  
380 - end  
381 - when 'Person', 'Community'  
382 - {:joins => 'inner join categories_profiles on (categories_profiles.profile_id = profiles.id)', :conditions => ['categories_profiles.category_id = (?)', category_id]}.merge!(options)  
383 - else  
384 - raise "unreconized class #{klass.name}" 273 + def paginate_options(page = params[:page])
  274 + { :per_page => limit, :page => page }
  275 + end
  276 +
  277 + def full_text_search(paginate_options = nil)
  278 + paginate_options ||= paginate_options(params[:page])
  279 + solr_options = solr_options(@asset, params[:facet], params[:order_by])
  280 +
  281 + ret = asset_class(@asset).find_by_contents(@query, paginate_options, solr_options)
  282 + @results[@asset] = ret[:results]
  283 + @facets = ret[:facets]
  284 + @all_facets = ret[:all_facets]
  285 + end
  286 +
  287 + def solr_options(asset, facets_selected, solr_order = nil)
  288 + result = {}
  289 +
  290 + asset_class = asset_class(asset)
  291 + if !@results_only and asset_class.methods.include?('facets')
  292 + result.merge! asset_class.facets_find_options(facets_selected)
  293 + result[:all_facets] = true
  294 + result[:limit] = 0 if @facets_only
  295 + result[:facets][:browse] << asset_class.facet_category_query.call(@category) if @category
  296 + puts result[:facets][:browse]
385 end 297 end
  298 +
  299 + result[:order] = solr_order if solr_order
  300 +
  301 + result
386 end 302 end
387 303
388 def asset_class(asset) 304 def asset_class(asset)
app/helpers/display_helper.rb
@@ -8,14 +8,24 @@ module DisplayHelper @@ -8,14 +8,24 @@ module DisplayHelper
8 opts 8 opts
9 end 9 end
10 10
  11 + def price_span(price, options = {})
  12 + content_tag 'span',
  13 + number_to_currency(price, :unit => environment.currency_unit, :delimiter => environment.currency_delimiter, :separator => environment.currency_separator),
  14 + options
  15 + end
  16 +
11 def product_path(product) 17 def product_path(product)
12 product.enterprise.enabled? ? product.enterprise.public_profile_url.merge(:controller => 'manage_products', :action => 'show', :id => product) : product.enterprise.url 18 product.enterprise.enabled? ? product.enterprise.public_profile_url.merge(:controller => 'manage_products', :action => 'show', :id => product) : product.enterprise.url
13 end 19 end
14 20
15 - def link_to_category(category, full = true) 21 + def link_to_tag(tag, html_options = {})
  22 + link_to tag.name, {:controller => 'search', :action => 'tag', :tag => tag.name}, html_options
  23 + end
  24 +
  25 + def link_to_category(category, full = true, html_options = {})
16 return _('Uncategorized product') unless category 26 return _('Uncategorized product') unless category
17 name = full ? category.full_name(' &rarr; ') : category.name 27 name = full ? category.full_name(' &rarr; ') : category.name
18 - link_to name, Noosfero.url_options.merge({:controller => 'search', :action => 'category_index', :category_path => category.path.split('/'),:host => category.environment.default_hostname }) 28 + link_to name, Noosfero.url_options.merge({:controller => 'search', :action => 'category_index', :category_path => category.path.split('/'),:host => category.environment.default_hostname }), html_options
19 end 29 end
20 30
21 def link_to_product_category(category) 31 def link_to_product_category(category)
app/helpers/search_helper.rb
@@ -9,54 +9,31 @@ module SearchHelper @@ -9,54 +9,31 @@ module SearchHelper
9 (n * 100.0).round 9 (n * 100.0).round
10 end 10 end
11 11
12 - def display_results(use_map = true)  
13 -  
14 - unless use_map && GoogleMaps.enabled?(environment.default_hostname)  
15 - return render(:partial => 'display_results') 12 + def display_results(use_map = false)
  13 + if params[:display] == 'map' && use_map && GoogleMaps.enabled?(environment.default_hostname)
  14 + partial = 'google_maps'
  15 + klass = 'map'
  16 + else
  17 + partial = 'display_results'
  18 + klass = 'list'
16 end 19 end
17 20
18 - data =  
19 - if params[:display] == 'map'  
20 - {  
21 - :partial => 'google_maps',  
22 - :toggle => button(:search, _('Display in list'), params.merge(:display => 'list'), :class => "map-toggle-button" ),  
23 - :class => 'map' ,  
24 - }  
25 - else  
26 - {  
27 - :partial => 'display_results',  
28 - :toggle => button(:search, _('Display in map'), params.merge(:display => 'map'), :class => "map-toggle-button" ),  
29 - :class => 'list' ,  
30 - }  
31 - end  
32 -  
33 - content_tag('div', data[:toggle] + (render :partial => data[:partial]), :class => "map-or-list-search-results #{data[:class]}") 21 + content_tag('div', render(:partial => partial), :class => "map-or-list-search-results #{klass}")
34 end 22 end
35 23
36 - def product_categories_menu(asset, product_category, object_ids = nil)  
37 - cats = ProductCategory.menu_categories(@product_category, environment)  
38 - cats += cats.select { |c| c.children_count > 0 }.map(&:children).flatten  
39 - product_categories_ids = cats.map(&:id)  
40 -  
41 - counts = @noosfero_finder.product_categories_count(asset, product_categories_ids, object_ids)  
42 -  
43 - product_categories_menu = ProductCategory.menu_categories(product_category, environment).map do |cat|  
44 - hits = counts[cat.id]  
45 - childs = []  
46 - if hits  
47 - if cat.children_count > 0  
48 - childs = cat.children.map do |child|  
49 - child_hits = counts[child.id]  
50 - [child, child_hits]  
51 - end.select{|child, child_hits| child_hits }  
52 - else  
53 - childs = []  
54 - end  
55 - end  
56 - [cat, hits, childs]  
57 - end.select{|cat, hits| hits } 24 + def display_map_list_button
  25 + button(:search, params[:display] == 'map' ? _('Display in list') : _('Display in map'),
  26 + params.merge(:display => (params[:display] == 'map' ? 'list' : 'map')),
  27 + :class => "map-toggle-button" )
  28 + end
58 29
59 - render(:partial => 'product_categories_menu', :object => product_categories_menu) 30 + def city_with_state(city)
  31 + s = city.parent
  32 + if city and city.kind_of?(City) and s and s.kind_of?(State) and s.acronym
  33 + city.name + ', ' + s.acronym
  34 + else
  35 + city.name
  36 + end
60 end 37 end
61 38
62 def facets_menu(asset, _facets) 39 def facets_menu(asset, _facets)
@@ -148,15 +125,15 @@ module SearchHelper @@ -148,15 +125,15 @@ module SearchHelper
148 125
149 def order_by(asset) 126 def order_by(asset)
150 options = { 127 options = {
151 - :products => [[_('Best match'), ''], [_('Name'), 'name_sort asc'], [_('Lower price'), 'price asc'], [_('Higher price'), 'price desc']],  
152 - :events => [[_('Best match'), ''], [_('Name'), 'name_sort asc']],  
153 - :articles => [[_('Best match'), ''], [_('Name'), 'name_sort asc'], [_('Most recent'), 'updated_at desc']],  
154 - :enterprises => [[_('Best match'), ''], [_('Name'), 'name_sort asc']],  
155 - :people => [[_('Best match'), ''], [_('Name'), 'name_sort asc']],  
156 - :communities => [[_('Best match'), ''], [_('Name'), 'name_sort asc']], 128 + :products => [[_('Relevance'), ''], [_('Name'), 'name_or_category_sort asc'], [_('Lower price'), 'price_sort asc'], [_('Higher price'), 'price_sort desc']],
  129 + :events => [[_('Relevance'), ''], [_('Name'), 'name_sort asc']],
  130 + :articles => [[_('Relevance'), ''], [_('Name'), 'name_sort asc'], [_('Most recent'), 'updated_at desc']],
  131 + :enterprises => [[_('Relevance'), ''], [_('Name'), 'name_sort asc']],
  132 + :people => [[_('Relevance'), ''], [_('Name'), 'name_sort asc']],
  133 + :communities => [[_('Relevance'), ''], [_('Name'), 'name_sort asc']],
157 } 134 }
158 135
159 - content_tag('div', _('Order by ') + 136 + content_tag('div', _('Sort results by ') +
160 select_tag(asset.to_s + '[order]', options_for_select(options[asset], params[:order_by]), 137 select_tag(asset.to_s + '[order]', options_for_select(options[asset], params[:order_by]),
161 {:onchange => "window.location=jQuery.param.querystring(window.location.href, { 'order_by' : this.options[this.selectedIndex].value})"}), 138 {:onchange => "window.location=jQuery.param.querystring(window.location.href, { 'order_by' : this.options[this.selectedIndex].value})"}),
162 :class => "search-ordering") 139 :class => "search-ordering")
@@ -178,4 +155,5 @@ module SearchHelper @@ -178,4 +155,5 @@ module SearchHelper
178 '' 155 ''
179 end 156 end
180 end 157 end
  158 +
181 end 159 end
app/models/article.rb
@@ -139,11 +139,18 @@ class Article &lt; ActiveRecord::Base @@ -139,11 +139,18 @@ class Article &lt; ActiveRecord::Base
139 {:conditions => [ 'parent_id is null and profile_id = ?', profile.id ]} 139 {:conditions => [ 'parent_id is null and profile_id = ?', profile.id ]}
140 } 140 }
141 141
  142 + named_scope :more_recent,
  143 + :conditions => [ "advertise = ? AND published = ? AND profiles.visible = ? AND profiles.public_profile = ? AND
  144 + ((articles.type != ?) OR articles.type is NULL)",
  145 + true, true, true, true, 'RssFeed'
  146 + ],
  147 + :order => 'articles.published_at desc, articles.id desc'
  148 +
142 # retrieves the latest +limit+ articles, sorted from the most recent to the 149 # retrieves the latest +limit+ articles, sorted from the most recent to the
143 # oldest. 150 # oldest.
144 # 151 #
145 # Only includes articles where advertise == true 152 # Only includes articles where advertise == true
146 - def self.recent(limit, extra_conditions = {}) 153 + def self.recent(limit = nil, extra_conditions = {})
147 # FIXME this method is a horrible hack 154 # FIXME this method is a horrible hack
148 options = { :limit => limit, 155 options = { :limit => limit,
149 :conditions => [ 156 :conditions => [
@@ -558,17 +565,53 @@ class Article &lt; ActiveRecord::Base @@ -558,17 +565,53 @@ class Article &lt; ActiveRecord::Base
558 end 565 end
559 566
560 private 567 private
  568 +
  569 + def self.f_type_proc(klass)
  570 + klass.constantize
  571 + h = {
  572 + 'UploadedFile' => _("Uploaded File"),
  573 + 'TextArticle' => _("Text"),
  574 + 'Folder' => _("Folder"),
  575 + 'Event' => _("Event"),
  576 + 'EnterpriseHomepage' => ("Homepage"),
  577 + 'Gallery' => ("Gallery"),
  578 + 'Blog' => ("Blog"),
  579 + 'Forum' => ("Forum")
  580 + }
  581 + h[klass]
  582 + end
  583 + def self.f_profile_type_proc(klass)
  584 + h = {
  585 + 'Enterprise' => _("Enterprise"),
  586 + 'Community' => _("Community"),
  587 + 'Person' => ("Person"),
  588 + 'BscPlugin::Bsc' => ("BSC")
  589 + }
  590 + h[klass]
  591 + end
  592 +
  593 + UploadedFile
  594 + TextArticle
  595 + TinyMceArticle
  596 + TextileArticle
  597 + Folder
  598 + EnterpriseHomepage
  599 + Gallery
  600 + Blog
  601 + Forum
  602 + Event
  603 + #excludes RssFeed
  604 +
561 def f_type 605 def f_type
562 - self.class.short_description 606 + case self.class.to_s
  607 + when 'TinyMceArticle', 'TextileArticle'
  608 + 'TextArticle'
  609 + else
  610 + self.class.to_s
  611 + end
563 end 612 end
564 - def f_publish_date  
565 - today = Date.today  
566 - range = ''  
567 - range = _('Last year') if (today-1.year..today).include?(self.published_at)  
568 - range = _('Last month') if (today-1.month..today).include?(self.published_at)  
569 - range = _('Last week') if (today-1.week..today).include?(self.published_at)  
570 - range = _('Last day') if (today-1.day..today).include?(self.published_at)  
571 - range 613 + def f_published_at
  614 + self.published_at
572 end 615 end
573 def f_profile_type 616 def f_profile_type
574 self.profile.class.to_s 617 self.profile.class.to_s
@@ -579,16 +622,21 @@ class Article &lt; ActiveRecord::Base @@ -579,16 +622,21 @@ class Article &lt; ActiveRecord::Base
579 public 622 public
580 623
581 acts_as_faceted :fields => { 624 acts_as_faceted :fields => {
582 - :f_type => {:label => _('Type')},  
583 - :f_publish_date => {:label => _('Published')},  
584 - :f_profile_type => {:label => _('Type of profile')},  
585 - :f_category => {:label => _('Categories')}},  
586 - :order => [:f_type, :f_publish_date, :f_profile_type, :f_category]  
587 -  
588 - acts_as_searchable :additional_fields => [ :comment_data, {:name => {:type => :string, :as => :name_sort, :boost => 5.0}} ] + facets.keys.map{|i| {i => :facet}}, 625 + :f_type => {:label => _('Type'), :proc => proc{|klass| f_type_proc(klass)}},
  626 + :f_published_at => {:type => :date, :label => _('Published date'), :queries => {'[* TO NOW-1YEARS/DAY]' => _("Older than one year"),
  627 + '[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")},
  628 + :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]']},
  629 + :f_profile_type => {:label => _('Profile'), :proc => proc{|klass| f_profile_type_proc(klass)}},
  630 + :f_category => {:label => _('Categories')}},
  631 + :category_query => proc { |c| "f_category:\"#{c.name}\"" },
  632 + :order => [:f_type, :f_published_at, :f_profile_type, :f_category]
  633 +
  634 + acts_as_searchable :additional_fields => [ {:name => {:type => :string, :as => :name_sort, :boost => 5.0}} ] + facets_fields_for_solr,
  635 + :exclude_fields => [:setting],
589 :include => [:profile], 636 :include => [:profile],
590 - :facets => facets.keys,  
591 - :if => proc{|a| ! ['Feed'].include?(a.type)} 637 + :facets => facets_option_for_solr,
  638 + :boost => proc {|a| 10 if a.profile.enabled},
  639 + :if => proc{|a| ! ['RssFeed'].include?(a.class.name)}
592 640
593 private 641 private
594 642
app/models/category.rb
@@ -36,18 +36,38 @@ class Category &lt; ActiveRecord::Base @@ -36,18 +36,38 @@ class Category &lt; ActiveRecord::Base
36 { :conditions => [ "type IN (?) OR type IS NULL", types.reject{ |t| t.blank? } ] } 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 def recent_articles(limit = 10) 55 def recent_articles(limit = 10)
40 self.articles.recent(limit) 56 self.articles.recent(limit)
41 end 57 end
42 58
43 def recent_comments(limit = 10) 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 end 61 end
46 62
47 def most_commented_articles(limit = 10) 63 def most_commented_articles(limit = 10)
48 self.articles.most_commented(limit) 64 self.articles.most_commented(limit)
49 end 65 end
50 66
  67 + def upcoming_events(limit = 10)
  68 + self.events.find(:all, :conditions => [ 'start_date >= ?', Date.today ], :order => 'start_date')
  69 + end
  70 +
51 def display_in_menu? 71 def display_in_menu?
52 display_in_menu 72 display_in_menu
53 end 73 end
@@ -64,10 +84,6 @@ class Category &lt; ActiveRecord::Base @@ -64,10 +84,6 @@ class Category &lt; ActiveRecord::Base
64 results 84 results
65 end 85 end
66 86
67 - def root_parent  
68 - parent_id.nil? ? self : Category.find_by_id(parent_id).root_parent  
69 - end  
70 -  
71 def is_leaf_displayable_in_menu? 87 def is_leaf_displayable_in_menu?
72 return false if self.display_in_menu == false 88 return false if self.display_in_menu == false
73 self.children.find(:all, :conditions => {:display_in_menu => true}).empty? 89 self.children.find(:all, :conditions => {:display_in_menu => true}).empty?
app/models/environment.rb
@@ -247,8 +247,9 @@ class Environment &lt; ActiveRecord::Base @@ -247,8 +247,9 @@ class Environment &lt; ActiveRecord::Base
247 247
248 settings_items :enabled_plugins, :type => Array, :default => [] 248 settings_items :enabled_plugins, :type => Array, :default => []
249 249
250 - settings_items :search_products_hint, :type => String, :default => ''  
251 - settings_items :search_contents_hint, :type => String, :default => '' 250 + settings_items :search_hints, :type => Hash, :default => {}
  251 +
  252 + settings_items :top_level_category_as_facet_ids, :type => Array, :default => []
252 253
253 def news_amount_by_folder=(amount) 254 def news_amount_by_folder=(amount)
254 settings[:news_amount_by_folder] = amount.to_i 255 settings[:news_amount_by_folder] = amount.to_i
app/views/layouts/application-ng.rhtml
@@ -66,7 +66,7 @@ @@ -66,7 +66,7 @@
66 </div> 66 </div>
67 </span> 67 </span>
68 <form action="/search" class="search_form" method="get" class="clean"> 68 <form action="/search" class="search_form" method="get" class="clean">
69 - <input name="query" size="15" title="<%=_('Search...')%>" /> 69 + <input name="query" size="15" title="<%=_('Search...')%>" onfocus="this.form.className='focused';" onblur="this.form.className=''" />
70 <div><%=_('Press <strong>Enter</strong> to send the search query.')%></div> 70 <div><%=_('Press <strong>Enter</strong> to send the search query.')%></div>
71 <%= javascript_tag 'jQuery("#user form input").hint();' %> 71 <%= javascript_tag 'jQuery("#user form input").hint();' %>
72 </form> 72 </form>
app/views/search/_article.rhtml
1 -<li class="article-item <%= icon_for_article(article) %>">  
2 - <strong><%= link_to(article.title, article.url) %></strong>  
3 - <div class="article-item-meta">  
4 - <% if article.body %>  
5 - <% body_stripped = strip_tags(article.body.to_s) %>  
6 - <br /><span class="article-item-body"><%= excerpt(body_stripped, body_stripped.first(3), 200) %></span><br />  
7 - <% end %>  
8 -  
9 - <br /><span><%= _('Tags: ') + article.tags.join(', ') if !article.tags.empty? %></span>  
10 -  
11 - <br /><span><%=_('Author: ') %><%= link_to(article.profile.name, profile_path(:profile => article.profile)) %></span>  
12 -  
13 - <br />  
14 - <% if article.last_changed_by %>  
15 - <span class="cat_item_by"><%= _('by %s') % link_to(article.last_changed_by.name, article.last_changed_by.url) %></span>  
16 - <% end %>  
17 - <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 %>
  5 + </div>
  6 + <div class="search-content-second-column">
18 7
19 - <br />  
20 </div> 8 </div>
  9 + <br class="clear"/>
21 </li> 10 </li>
app/views/search/_article_author.rhtml 0 → 100644
@@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
  1 +<% article = article_author %>
  2 +
  3 +<div class="search-article-author">
  4 + <div class="search-article-author-name">
  5 + <span class="search-field-label"><%= _("Author") %></span>
  6 + <%= link_to_profile article.profile.name, article.profile.identifier %>
  7 + </div>
  8 +</div>
app/views/search/_article_categories.rhtml 0 → 100644
@@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
  1 +<div class="search-article-categories">
  2 + <span class="search-field-label"><%= _('Categories') %></span>
  3 + <span class="search-article-categories-container">
  4 + <% article_categories.each do |category| %>
  5 + <%= link_to_category category, false, :class => "search-article-category" %>
  6 + <% end %>
  7 + <span class="search-field-none"><%= _('None') if article_categories.empty? %></span>
  8 + </span>
  9 +</div>
app/views/search/_article_common.rhtml 0 → 100644
@@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
  1 +<% article = article_common %>
  2 +
  3 +<%= render :partial => 'article_author', :object => article %>
  4 +<%= render :partial => 'article_description', :object => article %>
  5 +<%= render :partial => 'article_tags', :object => article.tags %>
  6 +<%= render :partial => 'article_categories', :object => article.categories %>
  7 +<%= render :partial => 'article_last_change', :object => article %>
app/views/search/_article_description.rhtml 0 → 100644
@@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
  1 +<% article = article_description %>
  2 +
  3 +<div class="search-article-description">
  4 + <span class="search-field-label"><%= _("Description") %></span>
  5 + <% if !article.body.blank? %>
  6 + <% body_stripped = strip_tags(article.body.to_s) %>
  7 + <span class="article-item-body"><%= excerpt(body_stripped, body_stripped.first(3), 200) %></span>
  8 + <% else %>
  9 + <span class="search-field-none"><%= _('None') %></span>
  10 + <% end %>
  11 +</div>
app/views/search/_article_last_change.rhtml 0 → 100644
@@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
  1 +<% article = article_last_change %>
  2 +
  3 +<div class="search-article-author-changes">
  4 + <% if article.last_changed_by && article.last_changed_by != article.profile %>
  5 + <span><%= _('by %s') % link_to(article.last_changed_by.name, article.last_changed_by.url) %>&nbsp<%= _(' at %s.') % show_date(article.updated_at) %></span>
  6 + <% else %>
  7 + <span><%= _('Last update: %s.') % show_date(article.updated_at) %></span>
  8 + <% end %>
  9 +</div>
app/views/search/_article_tags.rhtml 0 → 100644
@@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
  1 +<div class="search-article-tags">
  2 + <span class="search-field-label"><%= _('Tags') %></span>
  3 + <span class="search-article-tags-container">
  4 + <% article_tags.each do |tag| %>
  5 + <%= link_to_tag tag, :class => "search-article-tag" %>
  6 + <% end %>
  7 + <span class="search-field-none"><%= _('None') if article_tags.empty? %></span>
  8 + </span>
  9 +</div>
app/views/search/_blog.rhtml 0 → 100644
@@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
  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 + <div class="search-content-second-column">
  7 + <div class="search-blog-items">
  8 + <span class="search-field-label"><%= _("Last posts") %></span>
  9 + <% r = blog.children.find(:all, :order => :updated_at, :conditions => ['type != ?', 'RssFeed']).last(3) %>
  10 + <% r.each do |a| %>
  11 + <%= link_to a.title, a.view_url, :class => 'search-blog-sample-item '+icon_for_article(a) %>
  12 + <% end %>
  13 + <span class="search-field-none"><%= _('None') if r.empty? %></span>
  14 + </div>
  15 +
  16 + <%= render :partial => 'article_author', :object => blog %>
  17 + <%= render :partial => 'article_tags', :object => blog.tags %>
  18 + <%= render :partial => 'article_categories', :object => blog.categories %>
  19 + <%= render :partial => 'article_last_change', :object => blog %>
  20 + </div>
  21 +
  22 + <br class="clear"/>
  23 +</li>
app/views/search/_display_results.rhtml
@@ -4,45 +4,31 @@ @@ -4,45 +4,31 @@
4 <% results = @results[name] %> 4 <% results = @results[name] %>
5 <% if !results.nil? and !results.empty? %> 5 <% if !results.nil? and !results.empty? %>
6 <div class="search-results-<%= name %> search-results-box"> 6 <div class="search-results-<%= name %> search-results-box">
7 - <% if @controller.action_name != 'assets' %>  
8 - <% if @results.size != 1 %>  
9 - <h3>  
10 - <%= @names[name] %>  
11 - </h3>  
12 - <% end %>  
13 - <%# FIXME: don't hardcode an asset like this %>  
14 - <% if name == :most_commented_articles %>  
15 - <%= link_to( results.respond_to?(:total_entries) ? _('see all (%d)') % results.total_entries : _('see all...'),  
16 - params.merge(:action => 'index',  
17 - :asset => 'articles' ),  
18 - :class => 'see-more' ) if @results.size > 1 %>  
19 7
20 - <% else %>  
21 - <%= link_to( results.respond_to?(:total_entries) ? _('see all (%d)') % results.total_entries : _('see all...'),  
22 - params.merge(:action => 'index',  
23 - :asset => name ),  
24 - :class => 'see-more' ) if @results.size > 1 %>  
25 - <% end %> 8 + <% if @results.size > 1 %>
  9 + <h3><%= @names[name] %></h3>
  10 + <%= link_to(results.respond_to?(:total_entries) ? _('see all (%d)') % results.total_entries : _('see all...'),
  11 + params.merge(:action => name), :class => 'see-more' ) %>
26 <% end %> 12 <% end %>
27 - <% partial = partial_for_class results.first.class %> 13 +
  14 + <% partial = partial_for_class(results.first.class.class_name.constantize) %>
28 <div class="search-results-innerbox search-results-type-<%= partial %> <%= 'common-profile-list-block' if partial == 'profile' %>"> 15 <div class="search-results-innerbox search-results-type-<%= partial %> <%= 'common-profile-list-block' if partial == 'profile' %>">
29 <div class="search-results-innerbox2"><!-- the innerbox2 is a workarround for MSIE --> 16 <div class="search-results-innerbox2"><!-- the innerbox2 is a workarround for MSIE -->
30 <ul> 17 <ul>
31 - <% results.each do |hit| %>  
32 - <% next if hit.respond_to?(:visible) && !hit.visible? %>  
33 - <%= render :partial => partial_for_class(hit.class), :object => hit %>  
34 - <% end %> 18 + <% results.each do |hit| %>
  19 + <% next if hit.respond_to?(:visible) && !hit.visible? %>
  20 + <%= render :partial => partial_for_class(hit.class), :object => hit %>
  21 + <% end %>
35 </ul> 22 </ul>
36 <hr /> 23 <hr />
37 </div><!-- end class="search-results-innerbox2" --> 24 </div><!-- end class="search-results-innerbox2" -->
38 </div><!-- end class="search-results-innerbox" --> 25 </div><!-- end class="search-results-innerbox" -->
  26 +
39 </div><!-- end class="search-results-<%= name %>" --> 27 </div><!-- end class="search-results-<%= name %>" -->
40 <% else %> 28 <% else %>
41 <div class="search-results-<%= name %> search-results-empty search-results-box"> 29 <div class="search-results-<%= name %> search-results-empty search-results-box">
42 - <% if @controller.action_name != 'assets' %>  
43 - <% if @results.size != 1 %>  
44 - <h3><%= @names[name] %></h3>  
45 - <% end %> 30 + <% if @results.size > 1 %>
  31 + <h3><%= @names[name] %></h3>
46 <% end %> 32 <% end %>
47 <div class="search-results-innerbox search-results-type-empty"> 33 <div class="search-results-innerbox search-results-type-empty">
48 <div> <%= _('None') %> </div> 34 <div> <%= _('None') %> </div>
@@ -52,6 +38,6 @@ @@ -52,6 +38,6 @@
52 <% end %> 38 <% end %>
53 <% end %> 39 <% end %>
54 40
55 -<br style="clear:both" /> 41 +<div style="clear:both"></div>
56 </div><!-- end id="search-results" --> 42 </div><!-- end id="search-results" -->
57 43
app/views/search/_enterprise_homepage.rhtml 0 → 100644
@@ -0,0 +1 @@ @@ -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 </div> 5 </div>
  6 + <div class="search-content-second-column">
  7 + <% if event.body %>
  8 + <% body_stripped = strip_tags(event.body.to_s) %>
  9 + <div class="searc-article-event-date">
  10 + <span class="article-item-body"><%= excerpt(body_stripped, body_stripped.first(3), 200) %></span>
  11 + </div>
  12 + <% end %>
  13 + <% if event.start_date %>
  14 + <div class="searc-article-event-date">
  15 + <span class="search-field-label"><%= _('Start date') %></span>
  16 + <span class="article-item-date"><%= event.start_date %></span>
  17 + </div>
  18 + <% end %>
  19 + <% if event.end_date %>
  20 + <div class="searc-article-event-date">
  21 + <span class="search-field-label"><%= _('End date') %></span>
  22 + <span class="article-item-date"><%= event.end_date %></span>
  23 + </div>
  24 + <% end %>
  25 +
  26 + <%= render :partial => 'article_common', :object => event %>
  27 + </div>
  28 + <br class="clear"/>
6 </li> 29 </li>
app/views/search/_facets_menu.rhtml
1 -<% more_options = _("+ Options") %>  
2 -<% less_options = _("- Options") %>  
3 -<% less_options_limit = 7 %> 1 +<% less_options_limit = 8 %>
4 2
5 <div id="facets-menu"> 3 <div id="facets-menu">
6 - <% if !@facets["facet_fields"].empty? %>  
7 - <% @asset_class.each_facet do |facet_id, index| %>  
8 - <% facet = @asset_class.facets[facet_id] %>  
9 - <% solr_facet = @asset_class.to_solr_facet_fields[facet_id] %>  
10 - <% facets_all = @facets["facet_fields"][solr_facet] %>  
11 - <% facets_found = params[:facet] ? facets_all.reject {|name, count| params[:facet][facet_id.to_s].to_s == name.to_s } : facets_all %> 4 + <% @asset_class.map_facets_for(environment).each do |facet| %>
12 5
13 - <% if facets_found and facets_found.count > 0 %>  
14 - <div id="facet-menu-<%= index.to_s %>" class="facet-menu">  
15 - <div class="facet-menu-label">  
16 - <%= facet[:label] %>  
17 - </div><br /> 6 + <div id="facet-menu-<%= facet[:id].to_s %>" class="facet-menu">
  7 + <div class="facet-menu-label">
  8 + <%= facet[:label] %>
  9 + </div>
18 10
19 - <% if facets_found.count > less_options_limit %>  
20 - <div class="facet-menu-options facet-menu-more-options" style="display: none">  
21 - <% array = [] %>  
22 - <% @asset_class.each_facet_name(solr_facet, facets_found, :sort => :alphabetically) do |name, count| %>  
23 - <% array << {:id => name, :name => link_to(name, params.merge({"facet[#{facet_id.to_s}]" => name})) + " (#{count})"} %>  
24 - <% end %> 11 + <% results = @asset_class.map_facet_results(facet, params[:facet], @facets, @all_facets, :limit => less_options_limit) %>
  12 + <% facet_count = results.total_entries %>
25 13
26 - <%= text_field :facet, facet_id %>  
27 - <% javascript_tag do %>  
28 - jQuery.TokenList($("<%='facet_'+facet_id.to_s%>"), <%=array.to_json%>, {searchDelay: 0, permanentDropdown: true, theme: "facet", dontAdd: true, preventDuplicates: true});  
29 - <% end %>  
30 - </div>  
31 - <% end %>  
32 -  
33 - <div class="facet-menu-options facet-menu-less-options">  
34 - <% c = 0; @asset_class.each_facet_name(solr_facet, facets_found, :sort => :count) do |name, count| %>  
35 - <%= link_to(name, params.merge({"facet[#{facet_id.to_s}]" => name})) + " (#{count})" %><br />  
36 - <% break if (c += 1) > less_options_limit %>  
37 - <% end %>  
38 - </div> <br /> 14 + <% if facet_count > 0 %>
  15 + <div class="facet-menu-options facet-menu-more-options" style="display: none">
  16 + </div>
39 17
40 - <% if facets_found.count > less_options_limit %>  
41 - <%= link_to_function more_options, "jQuery('#facet-menu-"+index.to_s+" .facet-menu-options').toggle(200); " +  
42 - "jQuery(this).text(jQuery(this).text() == '"+less_options+"' ? '"+more_options+"' : '"+less_options+"');" %>  
43 - <br /> 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 />
44 <% end %> 21 <% end %>
  22 + </div> <br />
45 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" %>
46 <br /> 28 <br />
47 - </div>  
48 <% end %> 29 <% end %>
  30 +
  31 + <% else %>
  32 + <span class="facet-any-result-found"><%= _("No filter available") %></span>
49 <% end %> 33 <% end %>
50 - <% end %>  
51 - </div> 34 + </div>
  35 + <% end %>
  36 +</div>
app/views/search/_facets_unselect_menu.rhtml
1 -  
2 <div class="facets-applied"> 1 <div class="facets-applied">
3 <% if params[:facet] and params[:facet].count > 0 %> 2 <% if params[:facet] and params[:facet].count > 0 %>
4 - <span class="appliedFilters"><%= _("Applied filters") %> </span>  
5 - <% params[:facet].each do |facet_id, name| %>  
6 - <%= link_to(name, params.merge(:facet => params[:facet].reject {|k,v| k == facet_id}), :class => 'facet-selected') %>  
7 - <% end %> 3 + <span class="facets-applied-label"><%= _("Applied filters") %> </span>
  4 + <%= facet_selecteds_html_for(environment, asset_class(@asset), params) %>
8 <% end %> 5 <% end %>
9 </div> 6 </div>
app/views/search/_folder.rhtml 0 → 100644
@@ -0,0 +1,19 @@ @@ -0,0 +1,19 @@
  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 + <div class="search-content-second-column">
  7 + <div class="search-folder-items">
  8 + <span class="search-field-label"><%= _("Last items") %></span>
  9 + <% r = folder.children.last(3) %>
  10 + <% r.each do |a| %>
  11 + <%= link_to a.title, a.view_url, :class => 'search-folder-sample-item '+icon_for_article(a) %>
  12 + <% end %>
  13 + <span class="search-field-none"><%= _('None') if r.empty? %></span>
  14 + </div>
  15 +
  16 + <%= render :partial => 'article_common', :object => folder %>
  17 + </div>
  18 + <br class="clear"/>
  19 +</li>
app/views/search/_forum.rhtml 0 → 100644
@@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
  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 + <div class="search-content-second-column">
  7 + <div class="search-forum-items">
  8 + <span class="search-field-label"><%= _("Last topics") %></span>
  9 + <% r = forum.children.find(:all, :order => :updated_at, :conditions => ['type != ?', 'RssFeed']).last(3) %>
  10 + <% r.each do |a| %>
  11 + <%= link_to a.title, a.view_url, :class => 'search-forum-sample-item '+icon_for_article(a) %>
  12 + <% end %>
  13 + <span class="search-field-none"><%= _('None') if r.empty? %></span>
  14 + </div>
  15 +
  16 + <%= render :partial => 'article_common', :object => forum %>
  17 + </div>
  18 +
  19 + <br class="clear"/>
  20 +</li>
app/views/search/_gallery.rhtml 0 → 100644
@@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
  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 + <div class="search-content-second-column">
  7 + <%= render :partial => 'article_common', :object => gallery %>
  8 + </div>
  9 + <br class="clear"/>
  10 +</li>
app/views/search/_image.rhtml 0 → 100644
@@ -0,0 +1,47 @@ @@ -0,0 +1,47 @@
  1 +<div class="search-image-container">
  2 +
  3 + <% if image.is_a? UploadedFile %>
  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"><%= _('No image') %></div>
  36 + <% end %>
  37 + </div>
  38 + <% elsif image.is_a? Product %>
  39 + <% if image.image %>
  40 + <%= link_to '', product_path(image), :class => "search-image-pic", :style => 'background-image: url(%s)'% image.default_image(:thumb) %>
  41 + <% else %>
  42 + <div class="search-no-image"><%= _('No image') %></div>
  43 + <% end %>
  44 + <% else %>
  45 + <div class="search-content-type-icon icon-content-<%=image.class.to_s.underscore.dasherize%>"></div>
  46 + <% end %>
  47 +</div>
app/views/search/_product.rhtml
1 <% extra_content = @plugins.map(:asset_product_extras, product, product.enterprise).collect { |content| instance_eval(&content) } %> 1 <% extra_content = @plugins.map(:asset_product_extras, product, product.enterprise).collect { |content| instance_eval(&content) } %>
2 <% extra_properties = @plugins.map(:asset_product_properties, product)%> 2 <% extra_properties = @plugins.map(:asset_product_properties, product)%>
3 3
4 -<li class="product-item">  
5 - <div class="product-item-first-column">  
6 - <%= link_to_product product, :class => 'product-pic', :style => 'background-image:url(%s)' % product.default_image(:minor) %>  
7 - <%= product.price if product.price %> 4 +<li class="search-product-item">
  5 + <div class="search-product-item-first-column">
  6 + <%= render :partial => 'image', :object => product %>
  7 +
  8 + <% if product.available %>
  9 + <% if product.price && product.price > 0 %>
  10 + <% has_discount = product.discount && product.discount > 0 %>
  11 + <% if product.price %>
  12 + <span class="search-product-price-textid"><%=_("from") if has_discount %></span><%= price_span(product.price, :class => "search-product-price " + (has_discount ? 'with-discount' : '')) %>
  13 + <% if has_discount %>
  14 + <span class="search-product-price-textid"><%=_("by")%></span><%= price_span(product.price_with_discount, :class => "search-product-price") %>
  15 + <% end %>
  16 + <% if product.unit %>
  17 + <span class="search-product-unit">&nbsp;<%= _('/') %>&nbsp;<%= product.unit.name %></span>
  18 + <% end %>
  19 + <% end %>
  20 + <div class="search-product-inputs-info">
  21 + <% if product.inputs.count > product.inputs.collect(&:is_from_solidarity_economy).count(nil) %>
  22 + <% se_i = t_i = 0 %>
  23 + <% product.inputs.each{ |i| t_i += 1; se_i += 1 if i.is_from_solidarity_economy } %>
  24 + <% p = case (se_i.to_f/t_i)*100 when 0..24.999 then ["0", _("0%")]; when 25..49.999 then ["25", _("25%")]; when 50..74.999 then ["50", _("50%")]; when 75..100 then ["75", _("100%")]; end %>
  25 + <div class="search-product-percentage-from-solidarity-economy search-product-ecosol-percentage-icon-<%=p[0]%>" title="<%=_('Percentage of inputs from solidarity economy')%>">
  26 + <%= p[1] %>
  27 + </div>
  28 + <% end %>
  29 +
  30 + <% if product.inputs.count == product.inputs.collect(&:has_price_details?).count(true) %>
  31 + <% title = product.inputs.map{ |i|
  32 + '<div class="search-product-input-dots-to-price">' +
  33 + '<div class="search-product-input-name">' + i.product_category.name + '</div>' +
  34 + price_span(i.price_per_unit*i.amount_used, :class => 'search-product-input-price') +
  35 + '</div>' }.join('') %>
  36 + <%= link_to_function _("Open Price"), '', :title => title, :class => "search-product-price-details" %>
  37 + <% end %>
  38 + </div>
  39 + <% end %>
  40 + <% else %>
  41 + <span class="product-not-available"><%= _('Not available') %></div>
  42 + <% end %>
  43 +
8 </div> 44 </div>
9 - <div class="product-item-second-column">  
10 - <span class='product-title-link'><%= link_to_product product %></span>  
11 - <div class="product-supplier">  
12 - <span class="product-item-topic"><%= _('SUPPLIER') %> </span><%= link_to_homepage(product.enterprise.name, product.enterprise.identifier) %> 45 + <div class="search-product-item-second-column">
  46 + <%= link_to_product product, :class => 'search-result-title' %>
  47 + <div class="search-product-supplier">
  48 + <span class="search-field-label"><%= _('Supplier') %> </span><%= link_to_homepage(product.enterprise.name, product.enterprise.identifier) %>
13 </div> 49 </div>
14 - <div class="product-description"> 50 + <div class="search-product-description">
15 <% if product.description %> 51 <% if product.description %>
16 <% desc_stripped = strip_tags(product.description) %> 52 <% desc_stripped = strip_tags(product.description) %>
17 - <span class="product-item-topic"><%= _('DESCRIPTION') %> </span><%= excerpt(desc_stripped, desc_stripped.first(3), 100) %> 53 + <span class="search-field-label"><%= _('Description') %> </span><%= excerpt(desc_stripped, desc_stripped.first(3), 300) %>
18 <% end %> 54 <% end %>
19 </div> 55 </div>
20 </div> 56 </div>
21 - <div class="product-item-third-column">  
22 - <div class="product-region"> 57 + <div class="search-product-item-third-column">
  58 + <div class="search-product-region">
23 <% if product.enterprise.region %> 59 <% if product.enterprise.region %>
24 - <span class="product-item-topic"><%= _('REGION') %></span>  
25 - <br /><%= product.enterprise.region.name %> 60 + <span class="search-field-label"><%= _('City') %></span>
  61 + <br /><%= city_with_state(product.enterprise.region) %>
26 <% end %> 62 <% end %>
27 </div> 63 </div>
28 - <div class="product-qualifiers"> 64 + <div class="search-product-qualifiers">
29 <% if product.product_qualifiers.count > 0 %> 65 <% if product.product_qualifiers.count > 0 %>
30 - <span class="product-item-topic"><%= _('QUALIFIERS') %></span> 66 + <span class="search-field-label"><%= _('Qualifiers') %></span>
31 <% product.product_qualifiers.each do |pq| %> 67 <% product.product_qualifiers.each do |pq| %>
32 <% if pq.qualifier %> 68 <% if pq.qualifier %>
33 - <br /><%= pq.qualifier.name %> 69 + <span class="search-product-qualifier"><%= pq.qualifier.name + (pq.certifier.nil? ? _(";") : '') %></span>
34 <% end %> 70 <% end %>
35 <% if pq.certifier %> 71 <% if pq.certifier %>
36 - <br /><%= pq.certifier.name %> 72 + <span class="search-product-certifier">&nbsp;<%= _('cert. ') + pq.certifier.name + _(";") %></span>
37 <% end %> 73 <% end %>
38 <% end %> 74 <% end %>
39 <% end %> 75 <% end %>
app/views/search/_profile.rhtml
1 -<% if @query.blank? || !profile.enterprise? %>  
2 - <%= profile_image_link profile, :portrait %>  
3 -<% else %>  
4 - <div class="enterprise-result">  
5 - <%= profile_image_link profile, :portrait %>  
6 - <span><%= profile.name %></span>  
7 - <span><%= _("Region: ") + profile.region.name if profile.region %></span><br />  
8 - <% if !profile.description.blank? %>  
9 - <span><%= profile.description %></span><br />  
10 - <% end %> 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 + <% else %>
  24 + <% end %>
  25 + </div>
  26 + <% if !profile.description.blank? %>
  27 + <div><%= profile.description %></div><br />
  28 + <% end %>
11 29
12 - <div class="enterprise-categorization">  
13 - <% profile.top_level_categorization.each do |parent, children| %>  
14 - <span class="enterprise-categorization-parent"><%= parent.name + ':' %></span>  
15 - <span class="enterprise-categorization-children"><%= children.collect(&:name).join(', ') %></span>  
16 - <br />  
17 - <% end %>  
18 - </div>  
19 - </div>  
20 -<% end %> 30 + <div class="search-enterprise-categorization">
  31 + <% profile.top_level_categorization.each do |parent, children| %>
  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"><%= children.collect(&:name).join(', ') %></span>
  35 + </div>
  36 + <% end %>
  37 + </div>
  38 + </div>
  39 + <hr class="clearfix" />
  40 + </div>
  41 + <% end %>
  42 +</li>
app/views/search/_results_header.rhtml
1 -<div class="results-header">  
2 - <%= label_total_found(asset, results.total_entries) %>  
3 - <% if params[:display] != 'map' %>  
4 - <span class="current-page"><%= _("Showing page %s of %s") % [results.current_page, results.total_pages] %></span>  
5 - <% end %> 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.total_entries) %>
  5 + <% if params[:display] != 'map' %>
  6 + <span class="current-page"><%= _("Showing page %s of %s") % [results.current_page, results.total_pages] %></span>
  7 + <% end %>
  8 + </div>
6 9
7 - <%= facets_unselect_menu(asset) %> 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 %>
8 17
9 - <%= order_by(asset) if params[:display] != 'map' %> 18 + <div style="clear: both"></div>
10 </div> 19 </div>
app/views/search/_search_form.rhtml
@@ -3,26 +3,36 @@ @@ -3,26 +3,36 @@
3 3
4 <% form_tag( { :controller => 'search', :action => @asset ? @asset : 'index', :asset => nil, :category_path => ( @category ? @category.explode_path : [] ) }, 4 <% form_tag( { :controller => 'search', :action => @asset ? @asset : 'index', :asset => nil, :category_path => ( @category ? @category.explode_path : [] ) },
5 :method => 'get', :class => 'search_form' ) do %> 5 :method => 'get', :class => 'search_form' ) do %>
6 - <%= '<h3>%s</h3>' % form_title if defined? form_title %>  
7 6
8 <%= hidden_field_tag :display, params[:display] %> 7 <%= hidden_field_tag :display, params[:display] %>
9 8
10 - <%= hidden_field_tag :asset, params[:asset] %>  
11 -  
12 <div class="search-field"> 9 <div class="search-field">
13 <span class="formfield"> 10 <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? %> 11 + <%= text_field_tag 'query', @query, :id => 'search-input', :size => 50 %>
  12 + <%= javascript_tag "jQuery('#search-input').attr('title', \"#{hint}\").hint()" if defined?(hint) %>
  13 + <%= javascript_tag "jQuery('.search_form').submit(function() {
  14 + if (jQuery('#search-input').val().length < 3) {
  15 + jQuery('#search-empty-query-error').slideDown(200).delay(2500).slideUp(200);
  16 + return false;
  17 + }
  18 + });" %>
16 </span> 19 </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) %>  
20 - <% end %> 20 +
  21 + <%= submit_button(:search, _('Search')) %>
  22 +
  23 + <div id="search-empty-query-error">
  24 + <%= _("Type more than 2 characters to start a search") %>
  25 + </div>
21 </div> 26 </div>
22 27
23 - <% if lightbox?; button_bar do %>  
24 - <%= lightbox_close_button _('Close') %>  
25 - <% end; end %> 28 + <% if @empty_query %>
  29 + <% hint = environment.search_hints[@asset] %>
  30 + <% if hint and !hint.blank? %>
  31 + <span class="search-hint"><%= hint %></span>
  32 + <% end %>
  33 + <% end %>
  34 +
  35 + <div style="clear: both"></div>
26 36
27 <% end %> 37 <% end %>
28 38
app/views/search/_text_article.rhtml 0 → 100644
@@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
  1 +<li class="search-text-article-item article-item">
  2 + <%= link_to(text_article.title, text_article.url, :class => "search-result-title") %>
  3 + <div class="search-content-first-column">
  4 + <%= render :partial => 'image', :object => text_article %>
  5 + </div>
  6 + <div class="search-content-second-column">
  7 + <%= render :partial => 'article_common', :object => text_article %>
  8 + </div>
  9 + <br class="clear"/>
  10 +</li>
app/views/search/_uploaded_file.rhtml 0 → 100644
@@ -0,0 +1,36 @@ @@ -0,0 +1,36 @@
  1 +<li class="search-uploaded-file-item article-item">
  2 + <%= link_to uploaded_file.filename, uploaded_file.view_url, :class => 'search-result-title' %>
  3 + <hr class="clear" />
  4 +
  5 + <div class="search-content-first-column">
  6 + <%= render :partial => 'image', :object => uploaded_file %>
  7 + </div>
  8 +
  9 + <div class="search-uploaded-file-second-column">
  10 + <%= render :partial => 'article_author', :object => uploaded_file %>
  11 +
  12 + <div class="search-uploaded-file-description">
  13 + <% if !uploaded_file.body.blank? %>
  14 + <span class="search-field-label"><%= _("Description") %></span>
  15 + <% body = strip_tags(uploaded_file.body.to_s) %>
  16 + <%= excerpt(body, body.first(3), 200) %>
  17 + <% end %>
  18 + </div>
  19 +
  20 + <div class="search-uploaded-file-parent">
  21 + <% if uploaded_file.parent && uploaded_file.parent.published? %>
  22 + <% if uploaded_file.parent.gallery? %>
  23 + <span class="search-field-label"><%= _("Gallery") %></span>
  24 + <% else %>
  25 + <span class="search-field-label"><%= _("Folder") %></span>
  26 + <% end %>
  27 + <%= link_to uploaded_file.parent.name, {:controller => 'content_viewer', :profile => uploaded_file.profile.identifier, :action => 'view_page', :page => [uploaded_file.parent.slug]} %>
  28 + <% end %>
  29 + </div>
  30 +
  31 + <%= render :partial => 'article_tags', :object => uploaded_file.tags %>
  32 + <%= render :partial => 'article_categories', :object => uploaded_file.categories %>
  33 + <%= render :partial => 'article_last_change', :object => uploaded_file %>
  34 + </div>
  35 + <br style="clear: both"/>
  36 +</li>
app/views/search/articles.rhtml
1 -<%= search_page_title( _('Articles'), { :query => @query,  
2 - :total_results => @total_results } ) %> 1 +<%= search_page_title( @titles[:articles], @category ) %>
3 2
4 -<%= search_page_link_to_all( { :asset => params[:asset],  
5 - :category => @category }) %> 3 +<div id="search-column-left">
  4 + <% if !@empty_query %>
  5 + <%= facets_menu(:articles, @facets) %>
  6 + <% end %>
  7 +</div>
6 8
7 -<%= 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 => { :form_title => _('Search'), :simple_search => true,
  11 + :hint => _('Type the title, author or content desired') } %>
  12 + <%= render :partial => 'results_header', :locals => { :asset => :articles, :results => @results[:articles] } %>
8 13
9 -<% if !@query.blank? %>  
10 - <%= facets_menu(:articles, @facets) %>  
11 -<% end %>  
12 -  
13 -<%= render :partial => 'results_header', :locals => { :asset => :articles, :results => @results[:articles] } %>  
14 -  
15 -<%# FIXME ARMENGUE %>  
16 -<%= display_results(false) %>  
17 -  
18 -<%= pagination_links @results.values.first %> 14 + <% if !@empty_query or @filter %>
  15 + <%= display_results %>
  16 + <%= pagination_links @results.values.first %>
  17 + <% end %>
  18 +</div>
19 19
20 <br style="clear:both" /> 20 <br style="clear:both" />
app/views/search/category_index.rhtml
@@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
3 <div id="category-image"><%= image_tag(@category.image.public_filename(:thumb), :id => 'category-image') if @category.image %></div> 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> 4 <h1 id="category-name"><%= @category.name %></h1>
5 5
6 - <%= render :partial => 'display_results' %> 6 + <%= display_results %>
7 7
8 <div id="category-childs"> 8 <div id="category-childs">
9 <h2> <%= _('Sub-categories') %> </h2> 9 <h2> <%= _('Sub-categories') %> </h2>
app/views/search/communities.rhtml
1 -<%= search_page_title( __('Communities'), { :query => @query,  
2 - :total_results => @total_results } ) %> 1 +<%= search_page_title( @titles[:communities], @category ) %>
3 2
4 -<%= search_page_link_to_all( { :asset => params[:asset],  
5 - :category => @category }) %>  
6 -<%= render :partial => 'search_form', :locals => { :form_title => @query.blank? ? _('Search') : _("Refine your search"), :simple_search => true } %>  
7 -  
8 -<% if logged_in? %>  
9 - <% button_bar do %>  
10 - <%# FIXME shouldn't the user create the community in the current environment instead of going to its home environment? %>  
11 - <%= button(:add, __('New community'), user.url.merge(:controller => 'memberships', :action => 'new_community')) %> 3 +<div id='search-column-left'>
  4 + <% if logged_in? %>
  5 + <% button_bar do %>
  6 + <%# FIXME shouldn't the user create the community in the current environment instead of going to its home environment? %>
  7 + <%= button(:add, __('New community'), user.url.merge(:controller => 'memberships', :action => 'new_community')) %>
  8 + <% end %>
12 <% end %> 9 <% end %>
13 -<% end %>  
14 10
15 -<% if !@query.blank? %>  
16 - <%= facets_menu(:communities, @facets) %>  
17 -<% end %>  
18 -<%= render :partial => 'results_header', :locals => { :asset => :communities, :results => @results[:communities] } %> 11 + <% if !@empty_query %>
  12 + <%= facets_menu(:communities, @facets) %>
  13 + <% end %>
  14 +</div>
19 15
20 -<div id='search-results-and-pages'>  
21 - <%# FIXME ARMENGUE %>  
22 - <%= display_results(false) %> 16 +<div id='search-column-right'>
  17 + <%= render :partial => 'search_form', :locals => { :form_title => _('Search'), :simple_search => true,
  18 + :hint => _("Type words about the community you're looking for") } %>
  19 + <%= render :partial => 'results_header', :locals => { :asset => :communities, :results => @results[:communities] } %>
23 20
24 - <% if params[:display] != 'map' %>  
25 - <%= pagination_links @results.values.first %>  
26 - <% end %> 21 + <%= display_results %>
  22 + <%= pagination_links @results.values.first %>
27 </div> 23 </div>
28 24
29 <br style="clear:both" /> 25 <br style="clear:both" />
app/views/search/enterprises.rhtml
1 -<h1>  
2 - <% if !@query.blank? %>  
3 - <%=h @category ? (__('Enterprise results for "%{query}" in "%{category}"') % { :query => @query, :category => @category.name}) : (__('Enterprise results for "%s"') % @query) %>  
4 - <% else %>  
5 - <%=h @category ? (__('Enterprises in "%s"') % @category.name) : __('Enterprises') %>  
6 - <% end %>  
7 -</h1>  
8 -  
9 -<%= search_page_link_to_all( { :asset => params[:asset] }) %> 1 +<%= search_page_title( @titles[:enterprises], @category ) %>
10 2
11 -<%= render :partial => 'search_form', :locals => { :form_title => _("Refine your search"), :simple_search => true } %>  
12 -  
13 -<% if logged_in? && environment.enabled?('enterprise_registration') %>  
14 - <% button_bar do %>  
15 - <%= button(:add, __('New enterprise'), {:controller => 'enterprise_registration'}) %> 3 +<div id="search-column-left">
  4 + <% if logged_in? && environment.enabled?('enterprise_registration') %>
  5 + <% button_bar do %>
  6 + <%= button(:add, __('New enterprise'), {:controller => 'enterprise_registration'}) %>
  7 + <% end %>
16 <% end %> 8 <% end %>
17 -<% end %>  
18 -  
19 -<% if @categories_menu %>  
20 -<div class="has_cat_list">  
21 -<% end %>  
22 9
23 -<% cache(:action => 'assets', :asset => 'enterprises', :query => @query) do %>  
24 - <% if !@query.blank? %> 10 + <% if !@empty_query %>
  11 + <% button_bar do %>
  12 + <%= display_map_list_button %>
  13 + <% end %>
25 <%= facets_menu(:enterprises, @facets) %> 14 <%= facets_menu(:enterprises, @facets) %>
26 <% end %> 15 <% end %>
27 -<% end %> 16 +</div>
28 17
29 -<%= render :partial => 'results_header', :locals => { :asset => :enterprises, :results => @results[:enterprises] } %> 18 +<div id="search-column-right">
  19 + <%= render :partial => 'search_form', :locals => { :form_title => _('Search'), :simple_search => true,
  20 + :hint => _("Type words about the enterprise you're looking for") } %>
  21 + <%= render :partial => 'results_header', :locals => { :asset => :enterprises, :results => @results[:enterprises] } %>
30 22
31 -<%= display_results %>  
32 -  
33 -<% if @categories_menu %>  
34 -</div><!-- class="has_cat_list" -->  
35 -<% end %>  
36 -  
37 -<% if params[:display] != 'map' %>  
38 - <%= pagination_links @results[:enterprises] %>  
39 -<% end %> 23 + <%= display_results(true) %>
  24 + <% if params[:display] != 'map' %>
  25 + <%= pagination_links @results[:enterprises] %>
  26 + <% end %>
  27 +</div>
40 28
41 <br style="clear:both" /> 29 <br style="clear:both" />
app/views/search/events.rhtml
1 -<h1>  
2 - <%= _("%s's events") % @environment.name %>  
3 - <% if @category %>  
4 - :<small><%= @category.name %></small>  
5 - <% end %>  
6 -</h1> 1 +<%= search_page_title( @titles[:events], @category ) %>
7 2
8 <%= render :partial => 'events/agenda' %> 3 <%= render :partial => 'events/agenda' %>
app/views/search/facets_browse.rhtml 0 → 100644
@@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
  1 +<% results = @asset_class.map_facet_results(@facet, params[:facet], @facets, @all_facets) %>
  2 +
  3 +<% array = [] %>
  4 +<% @asset_class.facet_result_sort(@facet, results, :alphabetically).each do |id, label, count| %>
  5 + <% array << {:id => id, :name => facet_link_html(@facet, params.merge(:controller => 'search', :action => @asset), id, label, count)} %>
  6 +<% end %>
  7 +
  8 +<%= facet_javascript('facet-input-'+@facet[:id].to_s, @facet, array) %>
app/views/search/index.rhtml
1 <div id="search-page"> 1 <div id="search-page">
2 2
3 -<%= search_page_title(_('Search Results'), :query => CGI.escapeHTML(@query),  
4 - :total_results => @total_results) %> 3 +<%= search_page_title(_('Search Results'), @category) %>
5 4
6 <%= render :partial => 'search_form', :locals => { :form_title => _("Refine your search"), :simple_search => true } %> 5 <%= render :partial => 'search_form', :locals => { :form_title => _("Refine your search"), :simple_search => true } %>
7 6
app/views/search/people.rhtml
1 -<%= search_page_title( _('People'), { :query => @query,  
2 - :total_results => @total_results } ) %> 1 +<%= search_page_title( @titles[:people], @category ) %>
3 2
4 -<%= search_page_link_to_all( { :asset => params[:asset],  
5 - :category => @category }) %> 3 +<div id='search-column-left'>
  4 + <% if !@empty_query %>
  5 + <%= facets_menu(:people, @facets) %>
  6 + <% end %>
  7 +</div>
6 8
7 -<%= 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 => { :form_title => _('Search'), :simple_search => true,
  11 + :hint => _("Type words about the person you're looking for") } %>
  12 + <%= render :partial => 'results_header', :locals => { :asset => :people, :results => @results[:people] } %>
8 13
9 -<% if !@query.blank? %>  
10 - <%= facets_menu(:people, @facets) %>  
11 -<% end %>  
12 -  
13 -<%= render :partial => 'results_header', :locals => { :asset => :people, :results => @results[:people] } %>  
14 -  
15 -<%# FIXME ARMENGUE %>  
16 -<%= display_results(false) %>  
17 -  
18 -<% if params[:display] != 'map' %>  
19 - <%= pagination_links @results.values.first %>  
20 -<% end %> 14 + <%= display_results %>
  15 + <% if params[:display] != 'map' %>
  16 + <%= pagination_links @results.values.first %>
  17 + <% end %>
  18 +</div>
21 19
22 <br style="clear:both" /> 20 <br style="clear:both" />
app/views/search/products.rhtml
1 -<%= search_page_title( _('Products and Services'), { :query => @query,  
2 - :total_results => @total_results } ) %>  
3 -  
4 -<%= search_page_link_to_all( { :asset => params[:asset],  
5 - :category => @category }) %>  
6 -  
7 -<%= render :partial => 'search_form', :locals => { :form_title => _("Refine your search"), :simple_search => true } %>  
8 -  
9 -<% if @categories_menu %>  
10 -<div class="has_cat_list">  
11 -<% end %>  
12 -  
13 -<% cache(:action => 'assets', :asset => 'products', :query => @query) do %>  
14 - <% if !@query.blank? %>  
15 - <%= facets_menu(:products, @facets) %> 1 +<%= search_page_title( @titles[:products], @category ) %>
  2 +
  3 +<div id="search-column-left">
  4 + <% if !@empty_query %>
  5 + <% button_bar do %>
  6 + <%= display_map_list_button %>
  7 + <% end %>
  8 + <%= facets_menu(:products, @facets) %>
16 <% end %> 9 <% end %>
17 -<% end %>  
18 -  
19 -<%= render :partial => 'results_header', :locals => { :asset => :products, :results => @results[:products] } %>  
20 -  
21 -<%= display_results %>  
22 -  
23 -<% if @categories_menu %>  
24 -</div><!-- class="has_cat_list" -->  
25 -<% end %> 10 +</div>
  11 +
  12 +<div id="search-column-right">
  13 + <%= render :partial => 'search_form', :locals => { :form_title => _("Search"), :simple_search => true,
  14 + :hint => _('Type the product, service, city or qualifier desired') } %>
  15 + <%= render :partial => 'results_header', :locals => { :asset => :products, :results => @results[:products] } %>
  16 +
  17 + <% if !@empty_query %>
  18 + <%= display_results(true) %>
  19 + <% if params[:display] != 'map' %>
  20 + <%= pagination_links @results[:products] %>
  21 + <% end %>
  22 + <% end %>
  23 +</div>
26 24
27 -<% if params[:display] != 'map' %>  
28 - <%= pagination_links @results[:products] %>  
29 -<% end %>  
30 25
31 <br style="clear:both" /> 26 <br style="clear:both" />
lib/acts_as_faceted.rb
@@ -6,47 +6,180 @@ module ActsAsFaceted @@ -6,47 +6,180 @@ module ActsAsFaceted
6 module ActsMethods 6 module ActsMethods
7 # Example: 7 # Example:
8 # 8 #
9 - # acts_as_faceted :fields => {  
10 - # :f_category => {:label => _('Related products')},  
11 - # :f_region => {:label => _('Region')},  
12 - # :f_qualifier => {:label => _('Qualifiers')}},  
13 - # :order => [:f_category, :f_region, :f_qualifier] 9 + #acts_as_faceted :fields => {
  10 + # :f_type => {:label => _('Type'), :proc => proc{|klass| f_type_proc(klass)}},
  11 + # :f_published_at => {:type => :date, :label => _('Published date'), :queries => {'[* TO NOW-1YEARS/DAY]' => _("Older than one year"),
  12 + # '[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")}},
  13 + # :f_profile_type => {:label => _('Author'), :proc => proc{|klass| f_profile_type_proc(klass)}},
  14 + # :f_category => {:label => _('Categories')}},
  15 + # :order => [:f_type, :f_published_at, :f_profile_type, :f_category]
  16 + #
  17 + #acts_as_searchable :additional_fields => [ {:name => {:type => :string, :as => :name_sort, :boost => 5.0}} ] + facets_fields_for_solr,
  18 + # :exclude_fields => [:setting],
  19 + # :include => [:profile],
  20 + # :facets => facets_option_for_solr,
  21 + # :if => proc{|a| ! ['RssFeed'].include?(a.class.name)}
14 def acts_as_faceted(options) 22 def acts_as_faceted(options)
15 extend ClassMethods 23 extend ClassMethods
  24 + extend ActsAsSolr::CommonMethods
16 25
17 cattr_accessor :facets 26 cattr_accessor :facets
18 cattr_accessor :facets_order 27 cattr_accessor :facets_order
19 - cattr_accessor :solr_facet_fields  
20 - cattr_accessor :to_solr_facet_fields 28 + cattr_accessor :to_solr_fields_names
  29 + cattr_accessor :facets_results_containers
  30 + cattr_accessor :solr_fields_names
  31 + cattr_accessor :facets_option_for_solr
  32 + cattr_accessor :facets_fields_for_solr
  33 + cattr_accessor :facet_category_query
21 34
22 self.facets = options[:fields] 35 self.facets = options[:fields]
23 self.facets_order = options[:order] || facets 36 self.facets_order = options[:order] || facets
  37 + self.facets_results_containers = {:fields => 'facet_fields', :queries => 'facet_queries', :ranges => 'facet_ranges'}
  38 + self.facets_option_for_solr = Hash[facets.select{ |id,data| ! data.has_key?(:queries) }].keys
  39 + self.facets_fields_for_solr = facets.map{ |id,data| {id => data[:type] || :facet} }
  40 + self.solr_fields_names = facets.map{ |id,data| id.to_s + '_' + get_solr_field_type(data[:type] || :facet) }
  41 + self.facet_category_query = options[:category_query]
24 42
25 # A hash to retrieve the field key for the solr facet string returned 43 # A hash to retrieve the field key for the solr facet string returned
26 - # "field_name_facet" => :field_name  
27 - self.solr_facet_fields = Hash[facets.keys.map{|f| f.to_s+'_facet'}.zip(facets.keys)]  
28 # :field_name => "field_name_facet" 44 # :field_name => "field_name_facet"
29 - self.to_solr_facet_fields = Hash[facets.keys.zip(facets.keys.map{|f| f.to_s+'_facet'})] 45 + self.to_solr_fields_names = Hash[facets.keys.zip(solr_fields_names)]
  46 +
  47 + def facet_by_id(id)
  48 + {:id => id}.merge(facets[id]) if facets[id]
  49 + end
  50 +
  51 + def map_facets_for(environment)
  52 + list = facets_order ? facets_order : facets.keys
  53 + list.map do |id|
  54 + facet = facet_by_id(id)
  55 + next if facet[:type_if] and !facet[:type_if].call(self.new)
30 56
31 - def each_facet  
32 - if facets_order  
33 - facets_order.each_with_index { |f, i| yield [f, i] } 57 + if facet[:multi]
  58 + facet[:label].call(environment).map do |label_id, label|
  59 + facet.merge({:id => facet[:id].to_s+'_'+label_id.to_s, :solr_field => facet[:id], :label_id => label_id, :label => label})
  60 + end
  61 + else
  62 + facet.merge(:id => facet[:id].to_s, :solr_field => facet[:id])
  63 + end
  64 + end.compact.flatten
  65 + end
  66 +
  67 + def map_facet_results(facet, facet_params, facets_data, unfiltered_facets_data = {}, options = {})
  68 + facets_data ||= {}
  69 + solr_facet = to_solr_fields_names[facet[:solr_field]]
  70 +
  71 + if unfiltered_facets_data
  72 + facets_data = unfiltered_facets_data.mash do |container, value|
  73 + [container, value.mash do |field, value|
  74 + facets_data[container] = {} if facets_data[container].nil? or facets_data[container] == []
  75 + f = Hash[Array(facets_data[container][field])]
  76 + zeros = []
  77 + [field, Array(value).map do |id, count|
  78 + count = f[id]
  79 + if count.nil?
  80 + zeros.push [id, 0]
  81 + nil
  82 + else
  83 + [id, count]
  84 + end
  85 + end.compact + zeros]
  86 + end]
  87 + end
  88 + end
  89 +
  90 + if facet[:queries]
  91 + container = facets_data[facets_results_containers[:queries]]
  92 + facet_data = (container.nil? or container.empty?) ? [] : container.select{ |k,v| k.starts_with? solr_facet }
34 else 93 else
35 - facets.each_with_index { |f, i| yield [f. i] } 94 + container = facets_data[facets_results_containers[:fields]]
  95 + facet_data = (container.nil? or container.empty?) ? [] : container[solr_facet] || []
36 end 96 end
  97 +
  98 + facet_count = facet_data.length
  99 +
  100 + if facet[:queries]
  101 + result = facet_data.map do |id, count|
  102 + q = id[id.index(':')+1,id.length]
  103 + label = facet_result_name(facet, q)
  104 + [q, label, count] if count > 0
  105 + end.compact
  106 + result = facet[:queries_order].map{ |id| result.detect{ |rid, label, count| rid == id } }.compact if facet[:queries_order]
  107 + elsif facet[:proc]
  108 + if facet[:label_id]
  109 + result = facet_data.map do |id, count|
  110 + name = facet_result_name(facet, id)
  111 + [id, name, count] if name
  112 + end.compact
  113 + # FIXME limit is NOT improving performance in this case :(
  114 + facet_count = result.length
  115 + result = result.first(options[:limit]) if options[:limit]
  116 + else
  117 + facet_data = facet_data.first(options[:limit]) if options[:limit]
  118 + result = facet_data.map { |id, count| [id, facet_result_name(facet, id), count] }
  119 + end
  120 + else
  121 + facet_data = facet_data.first(options[:limit]) if options[:limit]
  122 + result = facet_data.map { |id, count| [id, facet_result_name(facet, id), count] }
  123 + end
  124 +
  125 + sorted = facet_result_sort(facet, result, options[:sort])
  126 +
  127 + # length can't be used if limit option is given;
  128 + # total_entries comes to help
  129 + sorted.class.send(:define_method, :total_entries, proc { facet_count })
  130 +
  131 + sorted
37 end 132 end
38 133
39 - def each_facet_name(solr_facet, data, options = {})  
40 - facet = facets[solr_facet_fields[solr_facet]] 134 + def facet_result_sort(facet, facets_data, sort_by = nil)
  135 + if facet[:queries_order]
  136 + facets_data
  137 + elsif sort_by == :alphabetically
  138 + facets_data.sort{ |a,b| a[1] <=> b[1] }
  139 + elsif sort_by == :count
  140 + facets_data.sort{ |a,b| -1*(a[2] <=> b[2]) }
  141 + else
  142 + facets_data
  143 + end
  144 + end
41 145
42 - if options[:sort] == :alphabetically  
43 - result = data.sort{ |a,b| -1*(a[0] <=> b[0]) }  
44 - result.each { |name, count| yield [name, count] } 146 + def facet_result_name(facet, data)
  147 + if facet[:queries]
  148 + gettext(facet[:queries][data])
  149 + elsif facet[:proc]
  150 + if facet[:multi]
  151 + facet[:label_id] ||= 0
  152 + facet[:proc].call(facet, data)
  153 + else
  154 + gettext(facet[:proc].call(data))
  155 + end
45 else 156 else
46 - result = options[:sort] == :count ? data.sort{ |a,b| -1*(a[1] <=> b[1]) } : data  
47 - result.each { |name, count| yield [name, count] } 157 + data
48 end 158 end
49 end 159 end
  160 +
  161 + def facets_find_options(facets_selected = {}, options = {})
  162 + browses = []
  163 + facets_selected ||= {}
  164 + facets_selected.map do |id, value|
  165 + if value.kind_of?(Hash)
  166 + value.map do |label_id, value|
  167 + value.to_a.each do |value|
  168 + browses << id.to_s + ':' + (facets[id.to_sym][:queries] ? value : '"'+value.to_s+'"')
  169 + end
  170 + end
  171 + else
  172 + browses << id.to_s + ':' + (facets[id.to_sym][:queries] ? value : '"'+value.to_s+'"')
  173 + end
  174 + end.flatten
  175 +
  176 + {:facets => {:zeros => false, :sort => :count,
  177 + :fields => facets_option_for_solr,
  178 + :browse => browses,
  179 + :query => facets.map { |f, options| options[:queries].keys.map { |q| f.to_s + ':' + q } if options[:queries]}.compact.flatten,
  180 + }
  181 + }
  182 + end
50 end 183 end
51 end 184 end
52 185
@@ -54,3 +187,30 @@ end @@ -54,3 +187,30 @@ end
54 187
55 ActiveRecord::Base.extend ActsAsFaceted::ActsMethods 188 ActiveRecord::Base.extend ActsAsFaceted::ActsMethods
56 189
  190 +# from https://github.com/rubyworks/facets/blob/master/lib/core/facets/enumerable/graph.rb
  191 +module Enumerable
  192 + def graph(&yld)
  193 + if yld
  194 + h = {}
  195 + each do |*kv|
  196 + r = yld[*kv]
  197 + case r
  198 + when Hash
  199 + nk, nv = *r.to_a[0]
  200 + when Range
  201 + nk, nv = r.first, r.last
  202 + else
  203 + nk, nv = *r
  204 + end
  205 + h[nk] = nv
  206 + end
  207 + h
  208 + else
  209 + Enumerator.new(self,:graph)
  210 + end
  211 + end
  212 +
  213 + # Alias for #graph, which stands for "map hash".
  214 + alias_method :mash, :graph
  215 +end
  216 +
lib/acts_as_searchable.rb
@@ -4,16 +4,18 @@ module ActsAsSearchable @@ -4,16 +4,18 @@ module ActsAsSearchable
4 ACTS_AS_SEARCHABLE_ENABLED = true unless defined? ACTS_AS_SEARCHABLE_ENABLED 4 ACTS_AS_SEARCHABLE_ENABLED = true unless defined? ACTS_AS_SEARCHABLE_ENABLED
5 5
6 def acts_as_searchable(options = {}) 6 def acts_as_searchable(options = {})
7 - if ACTS_AS_SEARCHABLE_ENABLED  
8 - if (!options[:fields])  
9 - options[:additional_fields] |= [{:schema_name => :string}]  
10 - else  
11 - options[:fields] << {:schema_name => :string}  
12 - end  
13 - acts_as_solr options  
14 - extend FindByContents  
15 - send :include, InstanceMethods 7 + return if !ACTS_AS_SEARCHABLE_ENABLED
  8 +
  9 + if (!options[:fields])
  10 + options[:additional_fields] |= [{:schema_name => :string}]
  11 + else
  12 + options[:fields] << {:schema_name => :string}
16 end 13 end
  14 + acts_as_solr options
  15 + extend FindByContents
  16 + send :include, InstanceMethods
  17 +
  18 + handle_asynchronously :solr_save
17 end 19 end
18 20
19 module InstanceMethods 21 module InstanceMethods
@@ -31,14 +33,20 @@ module ActsAsSearchable @@ -31,14 +33,20 @@ module ActsAsSearchable
31 def find_by_contents(query, pg_options = {}, options = {}, db_options = {}) 33 def find_by_contents(query, pg_options = {}, options = {}, db_options = {})
32 pg_options[:page] ||= 1 34 pg_options[:page] ||= 1
33 pg_options[:per_page] ||= 20 35 pg_options[:per_page] ||= 20
34 - options[:limit] = pg_options[:per_page].to_i*pg_options[:page].to_i  
35 - options[:scores] = true;  
36 - 36 + options[:limit] ||= pg_options[:per_page].to_i*pg_options[:page].to_i
  37 + options[:scores] ||= true;
  38 + all_facets_enabled = options.delete(:all_facets)
37 query = !schema_name.empty? ? "+schema_name:\"#{schema_name}\" AND #{query}" : query 39 query = !schema_name.empty? ? "+schema_name:\"#{schema_name}\" AND #{query}" : query
  40 + results = []
  41 + facets = all_facets = {}
  42 +
38 solr_result = find_by_solr(query, options) 43 solr_result = find_by_solr(query, options)
39 - if solr_result.nil?  
40 - results = facets = []  
41 - else 44 + if all_facets_enabled
  45 + options[:facets][:browse] = nil
  46 + all_facets = find_by_solr(query, options.merge(:limit => 0)).facets
  47 + end
  48 +
  49 + if !solr_result.nil?
42 facets = options.include?(:facets) ? solr_result.facets : [] 50 facets = options.include?(:facets) ? solr_result.facets : []
43 51
44 if db_options.empty? 52 if db_options.empty?
@@ -61,7 +69,7 @@ module ActsAsSearchable @@ -61,7 +69,7 @@ module ActsAsSearchable
61 results = results.paginate(pg_options.merge(:total_entries => solr_result.total)) 69 results = results.paginate(pg_options.merge(:total_entries => solr_result.total))
62 end 70 end
63 71
64 - {:results => results, :facets => facets} 72 + {:results => results, :facets => facets, :all_facets => all_facets}
65 end 73 end
66 end 74 end
67 end 75 end
public/designs/themes/base/style.css
1 /* ==> button.css <== */ 1 /* ==> button.css <== */
2 2
3 -  
4 .button { 3 .button {
5 -moz-border-radius: 3px; 4 -moz-border-radius: 3px;
6 -webkit-border-radius: 3px; 5 -webkit-border-radius: 3px;
@@ -502,11 +501,11 @@ div#notice { @@ -502,11 +501,11 @@ div#notice {
502 } 501 }
503 502
504 #content .profile-list li a, 503 #content .profile-list li a,
505 -#content .common-profile-list-block li a { 504 +#content .common-profile-list-block .vcard li a {
506 color: #555; 505 color: #555;
507 } 506 }
508 #content .profile-list li a:hover, 507 #content .profile-list li a:hover,
509 -#content .common-profile-list-block li a:hover { 508 +#content .common-profile-list-block .vcard li a:hover {
510 color: #000; 509 color: #000;
511 text-decoration: none; 510 text-decoration: none;
512 } 511 }
public/javascripts/application.js
@@ -773,3 +773,17 @@ jQuery(&#39;a[title]&#39;).live(&#39;mouseout&#39;, function (e) { @@ -773,3 +773,17 @@ jQuery(&#39;a[title]&#39;).live(&#39;mouseout&#39;, function (e) {
773 altBeautify.hide(); 773 altBeautify.hide();
774 }); 774 });
775 775
  776 +
  777 +function facet_options_toggle(id, url) {
  778 + jQuery('#facet-menu-'+id+' .facet-menu-options').toggle('fast' , function () {
  779 + more = jQuery('#facet-menu-'+id+' .facet-menu-more-options');
  780 + console.log(more);
  781 + if (more.is(':visible') && more.children().length == 0) {
  782 + more.addClass('small-loading');
  783 + more.load(url, function () {
  784 + more.removeClass('small-loading');
  785 + });
  786 + }
  787 + });
  788 +}
  789 +