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 1 class SearchController < PublicController
2 2  
3 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 8 helper TagsHelper
8 9 include SearchHelper
  10 + include ActionView::Helpers::NumberHelper
9 11  
10 12 before_filter :load_category
11 13 before_filter :load_search_assets
  14 + before_filter :load_query
12 15  
13 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 38 end
31 39 end
32 40  
33   - alias :contents :articles
  41 + def contents
  42 + redirect_to params.merge(:action => :articles)
  43 + end
34 44  
35 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 48 else
  49 + @results[@asset] = @environment.people.visible.send(@filter).paginate(paginate_options)
49 50 @facets = {}
50 51 end
51   - @results[@asset] = @results[@asset].compact.paginate(:per_page => limit, :page => params[:page])
52 52 end
53 53  
54 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 57 end
69 58 end
70 59  
71 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 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 66 end
86 67 end
87 68  
88 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 72 else
102   - @facets = {}
  73 + @results[@asset] = @environment.communities.visible.send(@filter).paginate(paginate_options)
103 74 end
104   - @results[@asset] = @results[@asset].compact.paginate(:per_page => limit, :page => params[:page])
105 75 end
106 76  
107 77 def events
108   - @asset = :events
109   - params[:asset] |= [@asset]
110   - @query = params[:query] || ''
111   - @order ||= [@asset]
112   - @results ||= {}
113 78 @category_id = @category ? @category.id : nil
114 79  
115 80 if params[:year] || params[:month]
... ... @@ -129,9 +94,7 @@ class SearchController &lt; PublicController
129 94 @results[@asset] = Event.send('find', :all)
130 95 end
131 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 98 end
136 99  
137 100 @selected_day = nil
... ... @@ -157,6 +120,7 @@ class SearchController &lt; PublicController
157 120 @results = {}
158 121 @order = []
159 122 @names = {}
  123 + @results_only = true
160 124  
161 125 @enabled_searchs.select { |key,description| @searching[key] }.each do |key, description|
162 126 send(key)
... ... @@ -186,19 +150,17 @@ class SearchController &lt; PublicController
186 150 @names = {}
187 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 163 end
201   - @facets = {}
202 164 end
203 165  
204 166 def tags
... ... @@ -218,50 +180,33 @@ class SearchController &lt; PublicController
218 180  
219 181 def events_by_day
220 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 184 render :partial => 'events/events_by_day'
227 185 end
228 186  
229 187 #######################################################
230 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 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 210 end
266 211  
267 212 FILTERS = %w(
... ... @@ -277,112 +222,83 @@ class SearchController &lt; PublicController
277 222 end
278 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 236 end
306 237  
307 238 def load_search_assets
308 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 246 ].select {|key, name| !environment.enabled?('disable_asset_' + key.to_s) }
316 247  
317 248 @searching = {}
  249 + @titles = {}
318 250 @enabled_searchs.each do |key, name|
  251 + @titles[key] = name
319 252 @searching[key] = params[:action] == 'index' || params[:action] == key.to_s
320 253 end
321 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 256 def limit
343   - searching = @searching.values.select{|v|v}
  257 + searching = @searching.values.select{ |v| v }
344 258 if params[:display] == 'map'
345 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 268 else
347   - (searching.size <= 1) ? SINGLE_SEARCH_LIMIT : MULTIPLE_SEARCH_LIMIT
  269 + MULTIPLE_SEARCH_LIMIT
348 270 end
349 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 297 end
  298 +
  299 + result[:order] = solr_order if solr_order
  300 +
  301 + result
386 302 end
387 303  
388 304 def asset_class(asset)
... ...
app/helpers/display_helper.rb
... ... @@ -8,14 +8,24 @@ module DisplayHelper
8 8 opts
9 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 17 def product_path(product)
12 18 product.enterprise.enabled? ? product.enterprise.public_profile_url.merge(:controller => 'manage_products', :action => 'show', :id => product) : product.enterprise.url
13 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 26 return _('Uncategorized product') unless category
17 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 29 end
20 30  
21 31 def link_to_product_category(category)
... ...
app/helpers/search_helper.rb
... ... @@ -9,54 +9,31 @@ module SearchHelper
9 9 (n * 100.0).round
10 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 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 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 37 end
61 38  
62 39 def facets_menu(asset, _facets)
... ... @@ -148,15 +125,15 @@ module SearchHelper
148 125  
149 126 def order_by(asset)
150 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 137 select_tag(asset.to_s + '[order]', options_for_select(options[asset], params[:order_by]),
161 138 {:onchange => "window.location=jQuery.param.querystring(window.location.href, { 'order_by' : this.options[this.selectedIndex].value})"}),
162 139 :class => "search-ordering")
... ... @@ -178,4 +155,5 @@ module SearchHelper
178 155 ''
179 156 end
180 157 end
  158 +
181 159 end
... ...
app/models/article.rb
... ... @@ -139,11 +139,18 @@ class Article &lt; ActiveRecord::Base
139 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 149 # retrieves the latest +limit+ articles, sorted from the most recent to the
143 150 # oldest.
144 151 #
145 152 # Only includes articles where advertise == true
146   - def self.recent(limit, extra_conditions = {})
  153 + def self.recent(limit = nil, extra_conditions = {})
147 154 # FIXME this method is a horrible hack
148 155 options = { :limit => limit,
149 156 :conditions => [
... ... @@ -558,17 +565,53 @@ class Article &lt; ActiveRecord::Base
558 565 end
559 566  
560 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 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 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 615 end
573 616 def f_profile_type
574 617 self.profile.class.to_s
... ... @@ -579,16 +622,21 @@ class Article &lt; ActiveRecord::Base
579 622 public
580 623  
581 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 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 641 private
594 642  
... ...
app/models/category.rb
... ... @@ -36,18 +36,38 @@ class Category &lt; ActiveRecord::Base
36 36 { :conditions => [ "type IN (?) OR type IS NULL", types.reject{ |t| t.blank? } ] }
37 37 }
38 38  
  39 + def recent_people(limit = 10)
  40 + self.people.paginate(:order => 'created_at DESC, id DESC', :page => 1, :per_page => limit)
  41 + end
  42 +
  43 + def recent_enterprises(limit = 10)
  44 + self.enterprises.paginate(:order => 'created_at DESC, id DESC', :page => 1, :per_page => limit)
  45 + end
  46 +
  47 + def recent_communities(limit = 10)
  48 + self.communities.paginate(:order => 'created_at DESC, id DESC', :page => 1, :per_page => limit)
  49 + end
  50 +
  51 + def recent_products(limit = 10)
  52 + self.products.paginate(:order => 'created_at DESC, id DESC', :page => 1, :per_page => limit)
  53 + end
  54 +
39 55 def recent_articles(limit = 10)
40 56 self.articles.recent(limit)
41 57 end
42 58  
43 59 def recent_comments(limit = 10)
44   - comments.find(:all, :order => 'created_at DESC, comments.id DESC', :limit => limit)
  60 + comments.paginate(:all, :order => 'created_at DESC, comments.id DESC', :page => 1, :per_page => limit)
45 61 end
46 62  
47 63 def most_commented_articles(limit = 10)
48 64 self.articles.most_commented(limit)
49 65 end
50 66  
  67 + def upcoming_events(limit = 10)
  68 + self.events.find(:all, :conditions => [ 'start_date >= ?', Date.today ], :order => 'start_date')
  69 + end
  70 +
51 71 def display_in_menu?
52 72 display_in_menu
53 73 end
... ... @@ -64,10 +84,6 @@ class Category &lt; ActiveRecord::Base
64 84 results
65 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 87 def is_leaf_displayable_in_menu?
72 88 return false if self.display_in_menu == false
73 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 247  
248 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 254 def news_amount_by_folder=(amount)
254 255 settings[:news_amount_by_folder] = amount.to_i
... ...
app/views/layouts/application-ng.rhtml
... ... @@ -66,7 +66,7 @@
66 66 </div>
67 67 </span>
68 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 70 <div><%=_('Press <strong>Enter</strong> to send the search query.')%></div>
71 71 <%= javascript_tag 'jQuery("#user form input").hint();' %>
72 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 8 </div>
  9 + <br class="clear"/>
21 10 </li>
... ...
app/views/search/_article_author.rhtml 0 → 100644
... ... @@ -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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 4 <% results = @results[name] %>
5 5 <% if !results.nil? and !results.empty? %>
6 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 12 <% end %>
27   - <% partial = partial_for_class results.first.class %>
  13 +
  14 + <% partial = partial_for_class(results.first.class.class_name.constantize) %>
28 15 <div class="search-results-innerbox search-results-type-<%= partial %> <%= 'common-profile-list-block' if partial == 'profile' %>">
29 16 <div class="search-results-innerbox2"><!-- the innerbox2 is a workarround for MSIE -->
30 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 22 </ul>
36 23 <hr />
37 24 </div><!-- end class="search-results-innerbox2" -->
38 25 </div><!-- end class="search-results-innerbox" -->
  26 +
39 27 </div><!-- end class="search-results-<%= name %>" -->
40 28 <% else %>
41 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 32 <% end %>
47 33 <div class="search-results-innerbox search-results-type-empty">
48 34 <div> <%= _('None') %> </div>
... ... @@ -52,6 +38,6 @@
52 38 <% end %>
53 39 <% end %>
54 40  
55   -<br style="clear:both" />
  41 +<div style="clear:both"></div>
56 42 </div><!-- end id="search-results" -->
57 43  
... ...
app/views/search/_enterprise_homepage.rhtml 0 → 100644
... ... @@ -0,0 +1 @@
  1 +<%= render :partial => 'text_article', :object => enterprise_homepage %>
... ...
app/views/search/_event.rhtml
1   -<li class="<%= icon_for_article(event) %>">
2   - <strong><%= link_to(event.title, event.url) %></strong>
3   - <div class="item_meta">
4   - <%= show_period(event.start_date, event.end_date) %>
  1 +<li class="search-event-item article-item">
  2 + <%= link_to(event.title, event.url, :class => "search-result-title") %>
  3 + <div class="search-content-first-column">
  4 + <%= render :partial => 'image', :object => event %>
5 5 </div>
  6 + <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 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 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 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 28 <br />
47   - </div>
48 29 <% end %>
  30 +
  31 + <% else %>
  32 + <span class="facet-any-result-found"><%= _("No filter available") %></span>
49 33 <% end %>
50   - <% end %>
51   - </div>
  34 + </div>
  35 + <% end %>
  36 +</div>
... ...
app/views/search/_facets_unselect_menu.rhtml
1   -
2 1 <div class="facets-applied">
3 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 5 <% end %>
9 6 </div>
... ...
app/views/search/_folder.rhtml 0 → 100644
... ... @@ -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 @@
  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 @@
  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 @@
  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 1 <% extra_content = @plugins.map(:asset_product_extras, product, product.enterprise).collect { |content| instance_eval(&content) } %>
2 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 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 49 </div>
14   - <div class="product-description">
  50 + <div class="search-product-description">
15 51 <% if product.description %>
16 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 54 <% end %>
19 55 </div>
20 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 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 62 <% end %>
27 63 </div>
28   - <div class="product-qualifiers">
  64 + <div class="search-product-qualifiers">
29 65 <% if product.product_qualifiers.count > 0 %>
30   - <span class="product-item-topic"><%= _('QUALIFIERS') %></span>
  66 + <span class="search-field-label"><%= _('Qualifiers') %></span>
31 67 <% product.product_qualifiers.each do |pq| %>
32 68 <% if pq.qualifier %>
33   - <br /><%= pq.qualifier.name %>
  69 + <span class="search-product-qualifier"><%= pq.qualifier.name + (pq.certifier.nil? ? _(";") : '') %></span>
34 70 <% end %>
35 71 <% if pq.certifier %>
36   - <br /><%= pq.certifier.name %>
  72 + <span class="search-product-certifier">&nbsp;<%= _('cert. ') + pq.certifier.name + _(";") %></span>
37 73 <% end %>
38 74 <% end %>
39 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 19 </div>
... ...
app/views/search/_search_form.rhtml
... ... @@ -3,26 +3,36 @@
3 3  
4 4 <% form_tag( { :controller => 'search', :action => @asset ? @asset : 'index', :asset => nil, :category_path => ( @category ? @category.explode_path : [] ) },
5 5 :method => 'get', :class => 'search_form' ) do %>
6   - <%= '<h3>%s</h3>' % form_title if defined? form_title %>
7 6  
8 7 <%= hidden_field_tag :display, params[:display] %>
9 8  
10   - <%= hidden_field_tag :asset, params[:asset] %>
11   -
12 9 <div class="search-field">
13 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 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 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 37 <% end %>
28 38  
... ...
app/views/search/_text_article.rhtml 0 → 100644
... ... @@ -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 @@
  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 20 <br style="clear:both" />
... ...
app/views/search/category_index.rhtml
... ... @@ -3,7 +3,7 @@
3 3 <div id="category-image"><%= image_tag(@category.image.public_filename(:thumb), :id => 'category-image') if @category.image %></div>
4 4 <h1 id="category-name"><%= @category.name %></h1>
5 5  
6   - <%= render :partial => 'display_results' %>
  6 + <%= display_results %>
7 7  
8 8 <div id="category-childs">
9 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 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 23 </div>
28 24  
29 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 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 14 <%= facets_menu(:enterprises, @facets) %>
26 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 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 3 <%= render :partial => 'events/agenda' %>
... ...
app/views/search/facets_browse.rhtml 0 → 100644
... ... @@ -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 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 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 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 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 26 <br style="clear:both" />
... ...
lib/acts_as_faceted.rb
... ... @@ -6,47 +6,180 @@ module ActsAsFaceted
6 6 module ActsMethods
7 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 22 def acts_as_faceted(options)
15 23 extend ClassMethods
  24 + extend ActsAsSolr::CommonMethods
16 25  
17 26 cattr_accessor :facets
18 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 35 self.facets = options[:fields]
23 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 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 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 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 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 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 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 158 end
49 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 183 end
51 184 end
52 185  
... ... @@ -54,3 +187,30 @@ end
54 187  
55 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 4 ACTS_AS_SEARCHABLE_ENABLED = true unless defined? ACTS_AS_SEARCHABLE_ENABLED
5 5  
6 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 13 end
  14 + acts_as_solr options
  15 + extend FindByContents
  16 + send :include, InstanceMethods
  17 +
  18 + handle_asynchronously :solr_save
17 19 end
18 20  
19 21 module InstanceMethods
... ... @@ -31,14 +33,20 @@ module ActsAsSearchable
31 33 def find_by_contents(query, pg_options = {}, options = {}, db_options = {})
32 34 pg_options[:page] ||= 1
33 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 39 query = !schema_name.empty? ? "+schema_name:\"#{schema_name}\" AND #{query}" : query
  40 + results = []
  41 + facets = all_facets = {}
  42 +
38 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 50 facets = options.include?(:facets) ? solr_result.facets : []
43 51  
44 52 if db_options.empty?
... ... @@ -61,7 +69,7 @@ module ActsAsSearchable
61 69 results = results.paginate(pg_options.merge(:total_entries => solr_result.total))
62 70 end
63 71  
64   - {:results => results, :facets => facets}
  72 + {:results => results, :facets => facets, :all_facets => all_facets}
65 73 end
66 74 end
67 75 end
... ...
public/designs/themes/base/style.css
1 1 /* ==> button.css <== */
2 2  
3   -
4 3 .button {
5 4 -moz-border-radius: 3px;
6 5 -webkit-border-radius: 3px;
... ... @@ -502,11 +501,11 @@ div#notice {
502 501 }
503 502  
504 503 #content .profile-list li a,
505   -#content .common-profile-list-block li a {
  504 +#content .common-profile-list-block .vcard li a {
506 505 color: #555;
507 506 }
508 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 509 color: #000;
511 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 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 +
... ...