Commit 6e82bdc7062af8f0447fff19593054948cbeb5e5
1 parent
144d5783
Exists in
master
and in
29 other branches
[otw] products action... =/
Showing
34 changed files
with
604 additions
and
338 deletions
Show diff stats
app/controllers/public/search_controller.rb
@@ -8,6 +8,7 @@ class SearchController < PublicController | @@ -8,6 +8,7 @@ class SearchController < PublicController | ||
8 | before_filter :load_category | 8 | before_filter :load_category |
9 | before_filter :load_search_assets | 9 | before_filter :load_search_assets |
10 | before_filter :load_query | 10 | before_filter :load_query |
11 | + before_filter :load_search_engine | ||
11 | 12 | ||
12 | # Backwards compatibility with old URLs | 13 | # Backwards compatibility with old URLs |
13 | def redirect_asset_param | 14 | def redirect_asset_param |
@@ -18,7 +19,7 @@ class SearchController < PublicController | @@ -18,7 +19,7 @@ class SearchController < PublicController | ||
18 | no_design_blocks | 19 | no_design_blocks |
19 | 20 | ||
20 | def facets_browse | 21 | def facets_browse |
21 | - @asset = params[:asset] | 22 | + @asset = params[:asset].to_sym |
22 | @asset_class = asset_class(@asset) | 23 | @asset_class = asset_class(@asset) |
23 | 24 | ||
24 | @facets_only = true | 25 | @facets_only = true |
@@ -31,11 +32,12 @@ class SearchController < PublicController | @@ -31,11 +32,12 @@ class SearchController < PublicController | ||
31 | end | 32 | end |
32 | 33 | ||
33 | def articles | 34 | def articles |
34 | - if !@empty_query | ||
35 | - full_text_search ['public:true'] | 35 | + if @search_engine && !@empty_query |
36 | + full_text_search | ||
36 | else | 37 | else |
37 | @results[@asset] = @environment.articles.public.send(@filter).paginate(paginate_options) | 38 | @results[@asset] = @environment.articles.public.send(@filter).paginate(paginate_options) |
38 | end | 39 | end |
40 | + render :template => 'search/search_page' | ||
39 | end | 41 | end |
40 | 42 | ||
41 | def contents | 43 | def contents |
@@ -43,49 +45,51 @@ class SearchController < PublicController | @@ -43,49 +45,51 @@ class SearchController < PublicController | ||
43 | end | 45 | end |
44 | 46 | ||
45 | def people | 47 | def people |
46 | - if !@empty_query | ||
47 | - full_text_search ['public:true'] | 48 | + if @search_engine && !@empty_query |
49 | + full_text_search | ||
48 | else | 50 | else |
49 | @results[@asset] = visible_profiles(Person).send(@filter).paginate(paginate_options) | 51 | @results[@asset] = visible_profiles(Person).send(@filter).paginate(paginate_options) |
50 | end | 52 | end |
53 | + render :template => 'search/search_page' | ||
51 | end | 54 | end |
52 | 55 | ||
53 | def products | 56 | def products |
54 | - public_filters = ['public:true', 'enabled:true'] | ||
55 | - if !@empty_query | ||
56 | - full_text_search public_filters | 57 | + if @search_engine && !@empty_query |
58 | + full_text_search | ||
57 | else | 59 | else |
58 | - @one_page = true | ||
59 | @geosearch = logged_in? && current_user.person.lat && current_user.person.lng | 60 | @geosearch = logged_in? && current_user.person.lat && current_user.person.lng |
60 | 61 | ||
61 | extra_limit = LIST_SEARCH_LIMIT*5 | 62 | extra_limit = LIST_SEARCH_LIMIT*5 |
62 | sql_options = {:limit => LIST_SEARCH_LIMIT, :order => 'random()'} | 63 | sql_options = {:limit => LIST_SEARCH_LIMIT, :order => 'random()'} |
63 | if @geosearch | 64 | if @geosearch |
64 | - full_text_search public_filters, :sql_options => sql_options, :extra_limit => extra_limit, | 65 | + full_text_search :sql_options => sql_options, :extra_limit => extra_limit, |
65 | :alternate_query => "{!boost b=recip(geodist(),#{"%e" % (1.to_f/DistBoost)},1,1)}", | 66 | :alternate_query => "{!boost b=recip(geodist(),#{"%e" % (1.to_f/DistBoost)},1,1)}", |
66 | :radius => DistFilt, :latitude => current_user.person.lat, :longitude => current_user.person.lng | 67 | :radius => DistFilt, :latitude => current_user.person.lat, :longitude => current_user.person.lng |
67 | else | 68 | else |
68 | - full_text_search public_filters, :sql_options => sql_options, :extra_limit => extra_limit, | 69 | + full_text_search :sql_options => sql_options, :extra_limit => extra_limit, |
69 | :boost_functions => ['recip(ms(NOW/HOUR,updated_at),1.3e-10,1,1)'] | 70 | :boost_functions => ['recip(ms(NOW/HOUR,updated_at),1.3e-10,1,1)'] |
70 | end | 71 | end |
71 | end | 72 | end |
73 | + render :template => 'search/search_page' | ||
72 | end | 74 | end |
73 | 75 | ||
74 | def enterprises | 76 | def enterprises |
75 | - if !@empty_query | ||
76 | - full_text_search ['public:true'] | 77 | + if @search_engine && !@empty_query |
78 | + full_text_search | ||
77 | else | 79 | else |
78 | @filter_title = _('Enterprises from network') | 80 | @filter_title = _('Enterprises from network') |
79 | @results[@asset] = visible_profiles(Enterprise, [{:products => :product_category}]).paginate(paginate_options) | 81 | @results[@asset] = visible_profiles(Enterprise, [{:products => :product_category}]).paginate(paginate_options) |
80 | end | 82 | end |
83 | + render :template => 'search/search_page' | ||
81 | end | 84 | end |
82 | 85 | ||
83 | def communities | 86 | def communities |
84 | - if !@empty_query | ||
85 | - full_text_search ['public:true'] | 87 | + if @search_engine && !@empty_query |
88 | + full_text_search | ||
86 | else | 89 | else |
87 | @results[@asset] = visible_profiles(Community).send(@filter).paginate(paginate_options) | 90 | @results[@asset] = visible_profiles(Community).send(@filter).paginate(paginate_options) |
88 | end | 91 | end |
92 | + render :template => 'search/search_page' | ||
89 | end | 93 | end |
90 | 94 | ||
91 | def events | 95 | def events |
@@ -104,7 +108,7 @@ class SearchController < PublicController | @@ -104,7 +108,7 @@ class SearchController < PublicController | ||
104 | environment.events.by_day(@selected_day) | 108 | environment.events.by_day(@selected_day) |
105 | end | 109 | end |
106 | 110 | ||
107 | - if !@empty_query | 111 | + if @search_engine && !@empty_query |
108 | full_text_search | 112 | full_text_search |
109 | else | 113 | else |
110 | @results[@asset] = date_range ? environment.events.by_range(date_range) : environment.events | 114 | @results[@asset] = date_range ? environment.events.by_range(date_range) : environment.events |
@@ -189,6 +193,7 @@ class SearchController < PublicController | @@ -189,6 +193,7 @@ class SearchController < PublicController | ||
189 | def load_query | 193 | def load_query |
190 | @asset = params[:action].to_sym | 194 | @asset = params[:action].to_sym |
191 | @order ||= [@asset] | 195 | @order ||= [@asset] |
196 | + params[:display] ||= 'list' | ||
192 | @results ||= {} | 197 | @results ||= {} |
193 | @filter = filter | 198 | @filter = filter |
194 | @filter_title = filter_description(@asset, @filter) | 199 | @filter_title = filter_description(@asset, @filter) |
@@ -211,6 +216,10 @@ class SearchController < PublicController | @@ -211,6 +216,10 @@ class SearchController < PublicController | ||
211 | end | 216 | end |
212 | end | 217 | end |
213 | 218 | ||
219 | + def load_search_engine | ||
220 | + @search_engine = @plugins.first_plugin(:search_engine?) | ||
221 | + end | ||
222 | + | ||
214 | FILTERS = %w( | 223 | FILTERS = %w( |
215 | more_recent | 224 | more_recent |
216 | more_active | 225 | more_active |
@@ -260,9 +269,7 @@ class SearchController < PublicController | @@ -260,9 +269,7 @@ class SearchController < PublicController | ||
260 | if map_search? | 269 | if map_search? |
261 | MAP_SEARCH_LIMIT | 270 | MAP_SEARCH_LIMIT |
262 | elsif !multiple_search? | 271 | elsif !multiple_search? |
263 | - if [:people, :communities].include? @asset | ||
264 | - BLOCKS_SEARCH_LIMIT | ||
265 | - elsif @asset == :enterprises and @empty_query | 272 | + if [:people, :communities, :enterprises].include? @asset |
266 | BLOCKS_SEARCH_LIMIT | 273 | BLOCKS_SEARCH_LIMIT |
267 | else | 274 | else |
268 | LIST_SEARCH_LIMIT | 275 | LIST_SEARCH_LIMIT |
@@ -273,41 +280,12 @@ class SearchController < PublicController | @@ -273,41 +280,12 @@ class SearchController < PublicController | ||
273 | end | 280 | end |
274 | 281 | ||
275 | def paginate_options(page = params[:page]) | 282 | def paginate_options(page = params[:page]) |
276 | - page = 1 if multiple_search? or params[:display] == 'map' | 283 | + page = 1 if multiple_search? or @display == 'map' |
277 | { :per_page => limit, :page => page } | 284 | { :per_page => limit, :page => page } |
278 | end | 285 | end |
279 | 286 | ||
280 | - def full_text_search(filters = [], options = {}) | ||
281 | - paginate_options = paginate_options(params[:page]) | ||
282 | - asset_class = asset_class(@asset) | ||
283 | - solr_options = options | ||
284 | - pg_options = paginate_options(params[:page]) | ||
285 | - | ||
286 | - if !multiple_search? | ||
287 | - if !@results_only and asset_class.respond_to? :facets | ||
288 | - solr_options.merge! asset_class.facets_find_options(params[:facet]) | ||
289 | - solr_options[:all_facets] = true | ||
290 | - end | ||
291 | - solr_options[:filter_queries] ||= [] | ||
292 | - solr_options[:filter_queries] += filters | ||
293 | - solr_options[:filter_queries] << "environment_id:#{environment.id}" | ||
294 | - solr_options[:filter_queries] << asset_class.facet_category_query.call(@category) if @category | ||
295 | - | ||
296 | - solr_options[:boost_functions] ||= [] | ||
297 | - params[:order_by] = nil if params[:order_by] == 'none' | ||
298 | - if params[:order_by] | ||
299 | - order = SortOptions[@asset][params[:order_by].to_sym] | ||
300 | - raise "Unknown order by" if order.nil? | ||
301 | - order[:solr_opts].each do |opt, value| | ||
302 | - solr_options[opt] = value.is_a?(Proc) ? instance_eval(&value) : value | ||
303 | - end | ||
304 | - end | ||
305 | - end | ||
306 | - | ||
307 | - ret = asset_class.find_by_contents(@query, paginate_options, solr_options) | ||
308 | - @results[@asset] = ret[:results] | ||
309 | - @facets = ret[:facets] | ||
310 | - @all_facets = ret[:all_facets] | 287 | + def full_text_search(options = {}) |
288 | + @results[@asset] = @plugins.first(:full_text_search, @asset, @query, @category, paginate_options(params[:page])) | ||
311 | end | 289 | end |
312 | 290 | ||
313 | private | 291 | private |
app/helpers/search_helper.rb
@@ -2,7 +2,7 @@ module SearchHelper | @@ -2,7 +2,7 @@ module SearchHelper | ||
2 | 2 | ||
3 | MAP_SEARCH_LIMIT = 2000 | 3 | MAP_SEARCH_LIMIT = 2000 |
4 | LIST_SEARCH_LIMIT = 20 | 4 | LIST_SEARCH_LIMIT = 20 |
5 | - BLOCKS_SEARCH_LIMIT = 18 | 5 | + BLOCKS_SEARCH_LIMIT = 24 |
6 | MULTIPLE_SEARCH_LIMIT = 8 | 6 | MULTIPLE_SEARCH_LIMIT = 8 |
7 | DistFilt = 200 | 7 | DistFilt = 200 |
8 | DistBoost = 50 | 8 | DistBoost = 50 |
@@ -50,7 +50,7 @@ module SearchHelper | @@ -50,7 +50,7 @@ module SearchHelper | ||
50 | end | 50 | end |
51 | 51 | ||
52 | def map_search? | 52 | def map_search? |
53 | - !@empty_query and !multiple_search? and params[:display] == 'map' | 53 | + !multiple_search? and params[:display] == 'map' |
54 | end | 54 | end |
55 | 55 | ||
56 | def search_page_title(title, category = nil) | 56 | def search_page_title(title, category = nil) |
@@ -66,8 +66,12 @@ module SearchHelper | @@ -66,8 +66,12 @@ module SearchHelper | ||
66 | :align => 'center', :class => 'search-category-context') if category | 66 | :align => 'center', :class => 'search-category-context') if category |
67 | end | 67 | end |
68 | 68 | ||
69 | - def display_results(map_capable = false) | ||
70 | - if map_capable and map_search? | 69 | + def map_capable?(asset) |
70 | + [:enterprises, :products].include?(asset) | ||
71 | + end | ||
72 | + | ||
73 | + def display_results(asset) | ||
74 | + if map_capable?(asset) and map_search? | ||
71 | partial = 'google_maps' | 75 | partial = 'google_maps' |
72 | klass = 'map' | 76 | klass = 'map' |
73 | else | 77 | else |
@@ -78,12 +82,6 @@ module SearchHelper | @@ -78,12 +82,6 @@ module SearchHelper | ||
78 | content_tag('div', render(:partial => partial), :class => "map-or-list-search-results #{klass}") | 82 | content_tag('div', render(:partial => partial), :class => "map-or-list-search-results #{klass}") |
79 | end | 83 | end |
80 | 84 | ||
81 | - def display_map_list_button | ||
82 | - button(:search, params[:display] == 'map' ? _('Display in list') : _('Display in map'), | ||
83 | - params.merge(:display => (params[:display] == 'map' ? 'list' : 'map')), | ||
84 | - :class => "map-toggle-button" ) | ||
85 | - end | ||
86 | - | ||
87 | def city_with_state(city) | 85 | def city_with_state(city) |
88 | if city and city.kind_of?(City) | 86 | if city and city.kind_of?(City) |
89 | s = city.parent | 87 | s = city.parent |
@@ -97,17 +95,6 @@ module SearchHelper | @@ -97,17 +95,6 @@ module SearchHelper | ||
97 | end | 95 | end |
98 | end | 96 | end |
99 | 97 | ||
100 | - def facets_menu(asset, _facets) | ||
101 | - @asset_class = asset_class(asset) | ||
102 | - @facets = _facets | ||
103 | - render(:partial => 'facets_menu') | ||
104 | - end | ||
105 | - | ||
106 | - def facets_unselect_menu(asset) | ||
107 | - @asset_class = asset_class(asset) | ||
108 | - render(:partial => 'facets_unselect_menu') | ||
109 | - end | ||
110 | - | ||
111 | def facet_javascript(input_id, facet, array) | 98 | def facet_javascript(input_id, facet, array) |
112 | array = [] if array.nil? | 99 | array = [] if array.nil? |
113 | hintText = _('Type in an option') | 100 | hintText = _('Type in an option') |
@@ -117,94 +104,6 @@ module SearchHelper | @@ -117,94 +104,6 @@ module SearchHelper | ||
117 | #{jquery_token_input_messages_json(hintText)}});") | 104 | #{jquery_token_input_messages_json(hintText)}});") |
118 | end | 105 | end |
119 | 106 | ||
120 | - def facet_link_html(facet, params, value, label, count) | ||
121 | - params = params ? params.dup : {} | ||
122 | - has_extra = label.kind_of?(Array) | ||
123 | - link_label = has_extra ? label[0] : label | ||
124 | - id = facet[:solr_field].to_s | ||
125 | - params[:facet] ||= {} | ||
126 | - params[:facet][id] ||= {} | ||
127 | - params[:page] = {} if params[:page] | ||
128 | - | ||
129 | - selected = facet[:label_id].nil? ? params[:facet][id] == value : params[:facet][id][facet[:label_id]].to_a.include?(value) | ||
130 | - | ||
131 | - if count > 0 | ||
132 | - url = params.merge(:facet => params[:facet].merge( | ||
133 | - id => facet[:label_id].nil? ? value : params[:facet][id].merge( facet[:label_id] => params[:facet][id][facet[:label_id]].to_a | [value] ) | ||
134 | - )) | ||
135 | - else | ||
136 | - # preserve others filters and change this filter | ||
137 | - url = params.merge(:facet => params[:facet].merge( | ||
138 | - id => facet[:label_id].nil? ? value : { facet[:label_id] => value } | ||
139 | - )) | ||
140 | - end | ||
141 | - | ||
142 | - content_tag 'div', link_to(link_label, url, :class => 'facet-result-link-label') + | ||
143 | - content_tag('span', (has_extra ? label[1] : ''), :class => 'facet-result-extra-label') + | ||
144 | - (count > 0 ? content_tag('span', " (#{count})", :class => 'facet-result-count') : ''), | ||
145 | - :class => 'facet-menu-item' + (selected ? ' facet-result-link-selected' : '') | ||
146 | - end | ||
147 | - | ||
148 | - def facet_selecteds_html_for(environment, klass, params) | ||
149 | - def name_with_extra(klass, facet, value) | ||
150 | - name = klass.facet_result_name(facet, value) | ||
151 | - name = name[0] + name[1] if name.kind_of?(Array) | ||
152 | - name | ||
153 | - end | ||
154 | - | ||
155 | - ret = [] | ||
156 | - params = params.dup | ||
157 | - params[:facet].each do |id, value| | ||
158 | - facet = klass.facet_by_id(id.to_sym) | ||
159 | - next unless facet | ||
160 | - if value.kind_of?(Hash) | ||
161 | - label_hash = facet[:label].call(environment) | ||
162 | - value.each do |label_id, value| | ||
163 | - facet[:label_id] = label_id | ||
164 | - facet[:label] = label_hash[label_id] | ||
165 | - value.to_a.each do |value| | ||
166 | - ret << [facet[:label], name_with_extra(klass, facet, value), | ||
167 | - params.merge(:facet => params[:facet].merge(id => params[:facet][id].merge(label_id => params[:facet][id][label_id].to_a.reject{ |v| v == value })))] | ||
168 | - end | ||
169 | - end | ||
170 | - else | ||
171 | - ret << [klass.facet_label(facet), name_with_extra(klass, facet, value), | ||
172 | - params.merge(:facet => params[:facet].reject{ |k,v| k == id })] | ||
173 | - end | ||
174 | - end | ||
175 | - | ||
176 | - ret.map do |label, name, url| | ||
177 | - content_tag('div', content_tag('span', label, :class => 'facet-selected-label') + | ||
178 | - content_tag('span', name, :class => 'facet-selected-name') + | ||
179 | - link_to('', url, :class => 'facet-selected-remove', :title => 'remove facet'), :class => 'facet-selected') | ||
180 | - end.join | ||
181 | - end | ||
182 | - | ||
183 | - def order_by(asset) | ||
184 | - options = SortOptions[asset].map do |name, options| | ||
185 | - next if options[:if] and ! instance_eval(&options[:if]) | ||
186 | - [_(options[:label]), name.to_s] | ||
187 | - end.compact | ||
188 | - | ||
189 | - content_tag('div', _('Sort results by ') + | ||
190 | - select_tag(asset.to_s + '[order]', options_for_select(options, params[:order_by] || 'none'), | ||
191 | - {:onchange => "window.location = jQuery.param.querystring(window.location.href, { 'order_by' : this.options[this.selectedIndex].value})"}), | ||
192 | - :class => "search-ordering") | ||
193 | - end | ||
194 | - | ||
195 | - def label_total_found(asset, total_found) | ||
196 | - labels = { | ||
197 | - :products => _("%s products offers found"), | ||
198 | - :articles => _("%s articles found"), | ||
199 | - :events => _("%s events found"), | ||
200 | - :people => _("%s people found"), | ||
201 | - :enterprises => _("%s enterprises found"), | ||
202 | - :communities => _("%s communities found"), | ||
203 | - } | ||
204 | - content_tag('span', labels[asset] % total_found, | ||
205 | - :class => "total-pages-found") if labels[asset] | ||
206 | - end | ||
207 | - | ||
208 | def asset_class(asset) | 107 | def asset_class(asset) |
209 | asset.to_s.singularize.camelize.constantize | 108 | asset.to_s.singularize.camelize.constantize |
210 | end | 109 | end |
@@ -213,4 +112,19 @@ module SearchHelper | @@ -213,4 +112,19 @@ module SearchHelper | ||
213 | asset_class(asset).table_name | 112 | asset_class(asset).table_name |
214 | end | 113 | end |
215 | 114 | ||
115 | + def display_filter(asset, display, float = 'right') | ||
116 | + if map_capable?(asset) | ||
117 | + list_link = display == 'list' ? _('List') : link_to(_('List'), params.merge(:display => 'list')) | ||
118 | + map_link = display == 'map' ? _('Map') : link_to(_('Map'), params.merge(:display => 'map')) | ||
119 | + content_tag('div', | ||
120 | + content_tag('strong', _('Display')) + ': ' + | ||
121 | + list_link + | ||
122 | + ' | ' + | ||
123 | + map_link, | ||
124 | + :id => 'search-display-filter', | ||
125 | + :style => "float: #{float}" | ||
126 | + ) | ||
127 | + end | ||
128 | + end | ||
129 | + | ||
216 | end | 130 | end |
app/views/search/_display_results.rhtml
1 | <div id="search-results" class="<%= !multiple_search? ? 'only-one-result-box' : 'multiple-results-boxes' %>"> | 1 | <div id="search-results" class="<%= !multiple_search? ? 'only-one-result-box' : 'multiple-results-boxes' %>"> |
2 | <% @order.each do |name| %> | 2 | <% @order.each do |name| %> |
3 | <% results = @results[name] %> | 3 | <% results = @results[name] %> |
4 | - <% empty = results.nil? || results.empty? %> | ||
5 | 4 | ||
6 | - <div class="search-results-<%= name %> search-results-box <%= "search-results-empty" if empty %>"> | ||
7 | - <% if not empty %> | 5 | + <div class="search-results-<%= name %> search-results-box <%= "search-results-empty" if results.blank? %>"> |
6 | + <% if !results.blank? %> | ||
8 | <% partial = partial_for_class(results.first.class.class_name.constantize) %> | 7 | <% partial = partial_for_class(results.first.class.class_name.constantize) %> |
9 | 8 | ||
10 | <% if multiple_search? %> | 9 | <% if multiple_search? %> |
app/views/search/_facets_menu.rhtml
@@ -1,36 +0,0 @@ | @@ -1,36 +0,0 @@ | ||
1 | -<% less_options_limit = 8 %> | ||
2 | - | ||
3 | -<div id="facets-menu"> | ||
4 | - <% @asset_class.map_facets_for(environment).each do |facet| %> | ||
5 | - | ||
6 | - <div id="facet-menu-<%= facet[:id].to_s %>" class="facet-menu"> | ||
7 | - <div class="facet-menu-label"> | ||
8 | - <%= @asset_class.facet_label(facet) %> | ||
9 | - </div> | ||
10 | - | ||
11 | - <% results = @asset_class.map_facet_results(facet, params[:facet], @facets, @all_facets, :limit => less_options_limit) %> | ||
12 | - <% facet_count = results.total_entries %> | ||
13 | - | ||
14 | - <% if facet_count > 0 %> | ||
15 | - <div class="facet-menu-options facet-menu-more-options" style="display: none"> | ||
16 | - </div> | ||
17 | - | ||
18 | - <div class="facet-menu-options facet-menu-less-options"> | ||
19 | - <% results.each do |id, label, count| %> | ||
20 | - <%= facet_link_html(facet, params, id, label, count) %><br /> | ||
21 | - <% end %> | ||
22 | - </div> <br /> | ||
23 | - | ||
24 | - <% if facet_count > less_options_limit %> | ||
25 | - <%= link_to_function _("Options"), | ||
26 | - "facet_options_toggle('#{facet[:id].to_s}', '#{url_for(params.merge(:action => 'facets_browse', :facet_id => facet[:id], :asset => @asset, :escape => false))}'); " + | ||
27 | - "jQuery(this).toggleClass('facet-less-options')", :class => "facet-options-toggle" %> | ||
28 | - <br /> | ||
29 | - <% end %> | ||
30 | - | ||
31 | - <% else %> | ||
32 | - <span class="facet-any-result-found"><%= _("No filter available") %></span> | ||
33 | - <% end %> | ||
34 | - </div> | ||
35 | - <% end %> | ||
36 | -</div> |
app/views/search/_profile.rhtml
1 | <li class="search-profile-item"> | 1 | <li class="search-profile-item"> |
2 | -<% if @empty_query or multiple_search? or !profile.enterprise? %> | 2 | +<% if @empty_query || multiple_search? || !profile.enterprise? || !@search_engine %> |
3 | <%= profile_image_link profile, :portrait, 'div', | 3 | <%= profile_image_link profile, :portrait, 'div', |
4 | @filter == 'more_recent' ? profile.send(@filter + '_label') + show_date(profile.created_at) : profile.send(@filter + '_label') %> | 4 | @filter == 'more_recent' ? profile.send(@filter + '_label') + show_date(profile.created_at) : profile.send(@filter + '_label') %> |
5 | <% else %> | 5 | <% else %> |
app/views/search/_results_header.rhtml
1 | <div class="search-results-header <%= "search-no-results" if @results[@asset].nil? or @results[@asset].length == 0 %>"> | 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 | - <% if @results[@asset].total_entries > 0 %> | ||
5 | - <%= label_total_found(@asset, @results[@asset].total_entries) %> | ||
6 | - <% if params[:display] != 'map' %> | ||
7 | - <span class="current-page"><%= _("Showing page %s of %s") % [@results[@asset].current_page, @results[@asset].total_pages] %></span> | ||
8 | - <% end %> | ||
9 | - <% end %> | ||
10 | - </div> | ||
11 | - | ||
12 | - <div class="search-results-header-facets-order-by"> | ||
13 | - <%= facets_unselect_menu(@asset) %> | ||
14 | - <%= order_by(@asset) if params[:display] != 'map' %> | ||
15 | - </div> | ||
16 | - <% else %> | ||
17 | - <div id='search-filter-title'><%= @filter_title if @filter_title %></div> | ||
18 | - <% end %> | ||
19 | - | 2 | + <div id='search-filter-title'><%= @filter_title if @filter_title %></div> |
3 | + <%= display_filter(@asset, params[:display]) if map_capable?(@asset) %> | ||
20 | <div style="clear: both"></div> | 4 | <div style="clear: both"></div> |
21 | </div> | 5 | </div> |
app/views/search/articles.rhtml
@@ -1,17 +0,0 @@ | @@ -1,17 +0,0 @@ | ||
1 | -<%= search_page_title( @titles[:articles], @category ) %> | ||
2 | - | ||
3 | -<div id="search-column-left"> | ||
4 | - <% if !@empty_query %> | ||
5 | - <%= facets_menu(:articles, @facets) %> | ||
6 | - <% end %> | ||
7 | -</div> | ||
8 | - | ||
9 | -<div id="search-column-right"> | ||
10 | - <%= render :partial => 'search_form', :locals => { :hint => _('Type the title, author or content desired') } %> | ||
11 | - <%= render :partial => 'results_header' %> | ||
12 | - | ||
13 | - <%= display_results %> | ||
14 | - <%= pagination_links @results[:articles] %> | ||
15 | -</div> | ||
16 | - | ||
17 | -<div style="clear: both"></div> |
app/views/search/communities.rhtml
@@ -1,25 +0,0 @@ | @@ -1,25 +0,0 @@ | ||
1 | -<%= search_page_title( @titles[:communities], @category ) %> | ||
2 | - | ||
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', :profile => user.identifier)) %> | ||
8 | - <% end %> | ||
9 | - <% end %> | ||
10 | - | ||
11 | - <% if !@empty_query %> | ||
12 | - <%= facets_menu(:communities, @facets) %> | ||
13 | - <% end %> | ||
14 | -</div> | ||
15 | - | ||
16 | -<div id='search-column-right'> | ||
17 | - <%= render :partial => 'search_form', :locals => { :hint => _("Type words about the community you're looking for") } %> | ||
18 | - <%= render :partial => 'results_header' %> | ||
19 | - | ||
20 | - <%= display_results %> | ||
21 | - <%= pagination_links @results.values.first %> | ||
22 | -</div> | ||
23 | - | ||
24 | -<div style="clear: both"></div> | ||
25 | - |
app/views/search/contents.rhtml
app/views/search/enterprises.rhtml
@@ -1,28 +0,0 @@ | @@ -1,28 +0,0 @@ | ||
1 | -<%= search_page_title( @titles[:enterprises], @category ) %> | ||
2 | - | ||
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 %> | ||
8 | - <% end %> | ||
9 | - | ||
10 | - <% if !@empty_query %> | ||
11 | - <% button_bar do %> | ||
12 | - <%= display_map_list_button %> | ||
13 | - <% end %> | ||
14 | - <%= facets_menu(:enterprises, @facets) %> | ||
15 | - <% end %> | ||
16 | -</div> | ||
17 | - | ||
18 | -<div id="search-column-right"> | ||
19 | - <%= render :partial => 'search_form', :locals => { :hint => _("Type words about the enterprise you're looking for") } %> | ||
20 | - <%= render :partial => 'results_header' %> | ||
21 | - | ||
22 | - <%= display_results(true) %> | ||
23 | - <% if params[:display] != 'map' %> | ||
24 | - <%= pagination_links @results[:enterprises] %> | ||
25 | - <% end %> | ||
26 | -</div> | ||
27 | - | ||
28 | -<div style="clear: both"></div> |
@@ -0,0 +1 @@ | @@ -0,0 +1 @@ | ||
1 | +<%= render :partial => 'events/agenda' %> |
app/views/search/events.rhtml
app/views/search/index.rhtml
@@ -7,7 +7,7 @@ | @@ -7,7 +7,7 @@ | ||
7 | <%= search_page_title(_('Search Results'), @category) %> | 7 | <%= search_page_title(_('Search Results'), @category) %> |
8 | <%= render :partial => 'search_form', :locals => { :hint => '' } %> | 8 | <%= render :partial => 'search_form', :locals => { :hint => '' } %> |
9 | <%= category_context(@category, params) %> | 9 | <%= category_context(@category, params) %> |
10 | - <%= display_results %> | 10 | + <%= display_results(@asset) %> |
11 | 11 | ||
12 | <div id="category-childs"> | 12 | <div id="category-childs"> |
13 | <% if @category %> | 13 | <% if @category %> |
app/views/search/people.rhtml
@@ -1,19 +0,0 @@ | @@ -1,19 +0,0 @@ | ||
1 | -<%= search_page_title( @titles[:people], @category ) %> | ||
2 | - | ||
3 | -<div id='search-column-left'> | ||
4 | - <% if !@empty_query %> | ||
5 | - <%= facets_menu(:people, @facets) %> | ||
6 | - <% end %> | ||
7 | -</div> | ||
8 | - | ||
9 | -<div id='search-column-right'> | ||
10 | - <%= render :partial => 'search_form', :locals => { :hint => _("Type words about the person you're looking for") } %> | ||
11 | - <%= render :partial => 'results_header' %> | ||
12 | - | ||
13 | - <%= display_results %> | ||
14 | - <% if params[:display] != 'map' %> | ||
15 | - <%= pagination_links @results.values.first %> | ||
16 | - <% end %> | ||
17 | -</div> | ||
18 | - | ||
19 | -<div style="clear: both"></div> |
app/views/search/products.rhtml
@@ -1,26 +0,0 @@ | @@ -1,26 +0,0 @@ | ||
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) %> | ||
9 | -<% end %> | ||
10 | -</div> | ||
11 | - | ||
12 | -<div id="search-column-right"> | ||
13 | - <%= render :partial => 'search_form', :locals => { :hint => _('Type the product, service, city or qualifier desired') } %> | ||
14 | - <%= render :partial => 'results_header' %> | ||
15 | - | ||
16 | - <%= display_results(true) %> | ||
17 | - <% if !@one_page and params[:display] != 'map' %> | ||
18 | - <%= pagination_links @results[:products] %> | ||
19 | -<% end %> | ||
20 | -</div> | ||
21 | - | ||
22 | -<% javascript_tag do %> | ||
23 | - jQuery('.search-product-price-details').altBeautify(); | ||
24 | -<% end %> | ||
25 | - | ||
26 | -<div style="clear: both"></div> |
@@ -0,0 +1,16 @@ | @@ -0,0 +1,16 @@ | ||
1 | +<%= search_page_title( @titles[@asset], @category ) %> | ||
2 | + | ||
3 | +<%= render :partial => 'results_header' %> | ||
4 | + | ||
5 | +<%= display_results(@asset) %> | ||
6 | +<% if params[:display] != 'map' %> | ||
7 | + <%= pagination_links @results[@asset] %> | ||
8 | +<% end %> | ||
9 | + | ||
10 | +<div style="clear: both"></div> | ||
11 | + | ||
12 | +<% if @asset == :product %> | ||
13 | + <% javascript_tag do %> | ||
14 | + jQuery('.search-product-price-details').altBeautify(); | ||
15 | + <% end %> | ||
16 | +<% end %> |
lib/noosfero/plugin.rb
@@ -351,6 +351,17 @@ class Noosfero::Plugin | @@ -351,6 +351,17 @@ class Noosfero::Plugin | ||
351 | nil | 351 | nil |
352 | end | 352 | end |
353 | 353 | ||
354 | + # -> Specifies plugin that works as a search engine | ||
355 | + # returns = true/false | ||
356 | + def search_engine? | ||
357 | + false | ||
358 | + end | ||
359 | + | ||
360 | + # -> Realizes a full text search | ||
361 | + # returns = whatever the plugin needs to render the view | ||
362 | + def full_text_search(asset, query, category, paginate_options) | ||
363 | + end | ||
364 | + | ||
354 | def method_missing(method, *args, &block) | 365 | def method_missing(method, *args, &block) |
355 | # This is a generic hotspot for all controllers on Noosfero. | 366 | # This is a generic hotspot for all controllers on Noosfero. |
356 | # If any plugin wants to define filters to run on any controller, the name of | 367 | # If any plugin wants to define filters to run on any controller, the name of |
plugins/solr/lib/solr_plugin.rb
1 | +require_dependency 'solr_plugin/search_helper' | ||
2 | + | ||
1 | class SolrPlugin < Noosfero::Plugin | 3 | class SolrPlugin < Noosfero::Plugin |
2 | 4 | ||
5 | + include SolrPlugin::SearchHelper | ||
6 | + | ||
3 | def self.plugin_name | 7 | def self.plugin_name |
4 | "Solr" | 8 | "Solr" |
5 | end | 9 | end |
@@ -8,6 +12,16 @@ class SolrPlugin < Noosfero::Plugin | @@ -8,6 +12,16 @@ class SolrPlugin < Noosfero::Plugin | ||
8 | _("Uses Solr as search engine.") | 12 | _("Uses Solr as search engine.") |
9 | end | 13 | end |
10 | 14 | ||
15 | + def search_engine? | ||
16 | + true | ||
17 | + end | ||
18 | + | ||
19 | + def full_text_search(asset, query, category, paginate_options) | ||
20 | + asset_class = asset_class(asset) | ||
21 | + solr_options = solr_options(asset, category) | ||
22 | + asset_class.find_by_contents(query, paginate_options, solr_options) | ||
23 | + end | ||
24 | + | ||
11 | end | 25 | end |
12 | 26 | ||
13 | Dir[File.join(SolrPlugin.root_path, 'lib', 'ext', '*.rb')].each {|file| require_dependency file } | 27 | Dir[File.join(SolrPlugin.root_path, 'lib', 'ext', '*.rb')].each {|file| require_dependency file } |
@@ -0,0 +1,113 @@ | @@ -0,0 +1,113 @@ | ||
1 | +class SolrPlugin < Noosfero::Plugin | ||
2 | + module ResultsHelper | ||
3 | + def set_results_variables | ||
4 | + if @results[@asset].kind_of?(Hash) | ||
5 | + ret = @results[@asset] | ||
6 | + @results[@asset] = ret[:results] | ||
7 | + @facets = ret[:facets] | ||
8 | + @all_facets = ret[:all_facets] | ||
9 | + end | ||
10 | + end | ||
11 | + | ||
12 | + def order_by(asset) | ||
13 | + options = SolrPlugin::SortOptions[asset].map do |name, options| | ||
14 | + next if options[:if] && !instance_eval(&options[:if]) | ||
15 | + [_(options[:label]), name.to_s] | ||
16 | + end.compact | ||
17 | + | ||
18 | + content_tag('div', _('Sort results by ') + | ||
19 | + select_tag(asset.to_s + '[order]', options_for_select(options, params[:order_by] || 'none'), | ||
20 | + {:onchange => "window.location = jQuery.param.querystring(window.location.href, { 'order_by' : this.options[this.selectedIndex].value})"} | ||
21 | + ), | ||
22 | + :class => "search-ordering" | ||
23 | + ) | ||
24 | + end | ||
25 | + | ||
26 | + def label_total_found(asset, total_found) | ||
27 | + labels = { | ||
28 | + :products => _("%s products offers found"), | ||
29 | + :articles => _("%s articles found"), | ||
30 | + :events => _("%s events found"), | ||
31 | + :people => _("%s people found"), | ||
32 | + :enterprises => _("%s enterprises found"), | ||
33 | + :communities => _("%s communities found"), | ||
34 | + } | ||
35 | + content_tag('span', labels[asset] % total_found, | ||
36 | + :class => "total-pages-found") if labels[asset] | ||
37 | + end | ||
38 | + | ||
39 | + def facets_menu(asset, _facets) | ||
40 | + @asset_class = asset_class(asset) | ||
41 | + @facets = _facets | ||
42 | + render(:partial => 'facets_menu') | ||
43 | + end | ||
44 | + | ||
45 | + def facets_unselect_menu(asset) | ||
46 | + @asset_class = asset_class(asset) | ||
47 | + render(:partial => 'facets_unselect_menu') | ||
48 | + end | ||
49 | + | ||
50 | + def facet_selecteds_html_for(environment, klass, params) | ||
51 | + def name_with_extra(klass, facet, value) | ||
52 | + name = klass.facet_result_name(facet, value) | ||
53 | + name = name[0] + name[1] if name.kind_of?(Array) | ||
54 | + name | ||
55 | + end | ||
56 | + | ||
57 | + ret = [] | ||
58 | + params = params.dup | ||
59 | + params[:facet].each do |id, value| | ||
60 | + facet = klass.facet_by_id(id.to_sym) | ||
61 | + next unless facet | ||
62 | + if value.kind_of?(Hash) | ||
63 | + label_hash = facet[:label].call(environment) | ||
64 | + value.each do |label_id, value| | ||
65 | + facet[:label_id] = label_id | ||
66 | + facet[:label] = label_hash[label_id] | ||
67 | + value.to_a.each do |value| | ||
68 | + ret << [facet[:label], name_with_extra(klass, facet, value), | ||
69 | + params.merge(:facet => params[:facet].merge(id => params[:facet][id].merge(label_id => params[:facet][id][label_id].to_a.reject{ |v| v == value })))] | ||
70 | + end | ||
71 | + end | ||
72 | + else | ||
73 | + ret << [klass.facet_label(facet), name_with_extra(klass, facet, value), | ||
74 | + params.merge(:facet => params[:facet].reject{ |k,v| k == id })] | ||
75 | + end | ||
76 | + end | ||
77 | + | ||
78 | + ret.map do |label, name, url| | ||
79 | + content_tag('div', content_tag('span', label, :class => 'facet-selected-label') + | ||
80 | + content_tag('span', name, :class => 'facet-selected-name') + | ||
81 | + link_to('', url, :class => 'facet-selected-remove', :title => 'remove facet'), :class => 'facet-selected') | ||
82 | + end.join | ||
83 | + end | ||
84 | + | ||
85 | + def facet_link_html(facet, params, value, label, count) | ||
86 | + params = params ? params.dup : {} | ||
87 | + has_extra = label.kind_of?(Array) | ||
88 | + link_label = has_extra ? label[0] : label | ||
89 | + id = facet[:solr_field].to_s | ||
90 | + params[:facet] ||= {} | ||
91 | + params[:facet][id] ||= {} | ||
92 | + params[:page] = {} if params[:page] | ||
93 | + | ||
94 | + selected = facet[:label_id].nil? ? params[:facet][id] == value : params[:facet][id][facet[:label_id]].to_a.include?(value) | ||
95 | + | ||
96 | + if count > 0 | ||
97 | + url = params.merge(:facet => params[:facet].merge( | ||
98 | + id => facet[:label_id].nil? ? value : params[:facet][id].merge( facet[:label_id] => params[:facet][id][facet[:label_id]].to_a | [value] ) | ||
99 | + )) | ||
100 | + else | ||
101 | + # preserve others filters and change this filter | ||
102 | + url = params.merge(:facet => params[:facet].merge( | ||
103 | + id => facet[:label_id].nil? ? value : { facet[:label_id] => value } | ||
104 | + )) | ||
105 | + end | ||
106 | + | ||
107 | + content_tag 'div', link_to(link_label, url, :class => 'facet-result-link-label') + | ||
108 | + content_tag('span', (has_extra ? label[1] : ''), :class => 'facet-result-extra-label') + | ||
109 | + (count > 0 ? content_tag('span', " (#{count})", :class => 'facet-result-count') : ''), | ||
110 | + :class => 'facet-menu-item' + (selected ? ' facet-result-link-selected' : '') | ||
111 | + end | ||
112 | + end | ||
113 | +end |
@@ -0,0 +1,83 @@ | @@ -0,0 +1,83 @@ | ||
1 | +class SolrPlugin < Noosfero::Plugin | ||
2 | + | ||
3 | + SortOptions = { | ||
4 | + :products => ActiveSupport::OrderedHash[ :none, {:label => _('Relevance')}, | ||
5 | + :more_recent, {:label => _('More recent'), :solr_opts => {:sort => 'updated_at desc, score desc'}}, | ||
6 | + :name, {:label => _('Name'), :solr_opts => {:sort => 'solr_plugin_name_sortable asc'}}, | ||
7 | + :closest, {:label => _('Closest to me'), :if => proc{ logged_in? && (profile=current_user.person).lat && profile.lng }, | ||
8 | + :solr_opts => {:sort => "geodist() asc", | ||
9 | + :latitude => proc{ current_user.person.lat }, :longitude => proc{ current_user.person.lng }}}, | ||
10 | + ], | ||
11 | + :events => ActiveSupport::OrderedHash[ :none, {:label => _('Relevance')}, | ||
12 | + :name, {:label => _('Name'), :solr_opts => {:sort => 'solr_plugin_name_sortable asc'}}, | ||
13 | + ], | ||
14 | + :articles => ActiveSupport::OrderedHash[ :none, {:label => _('Relevance')}, | ||
15 | + :name, {:label => _('Name'), :solr_opts => {:sort => 'solr_plugin_name_sortable asc'}}, | ||
16 | + :more_recent, {:label => _('More recent'), :solr_opts => {:sort => 'updated_at desc, score desc'}}, | ||
17 | + ], | ||
18 | + :enterprises => ActiveSupport::OrderedHash[ :none, {:label => _('Relevance')}, | ||
19 | + :name, {:label => _('Name'), :solr_opts => {:sort => 'solr_plugin_name_sortable asc'}}, | ||
20 | + ], | ||
21 | + :people => ActiveSupport::OrderedHash[ :none, {:label => _('Relevance')}, | ||
22 | + :name, {:label => _('Name'), :solr_opts => {:sort => 'solr_plugin_name_sortable asc'}}, | ||
23 | + ], | ||
24 | + :communities => ActiveSupport::OrderedHash[ :none, {:label => _('Relevance')}, | ||
25 | + :name, {:label => _('Name'), :solr_opts => {:sort => 'solr_plugin_name_sortable asc'}}, | ||
26 | + ], | ||
27 | + } | ||
28 | + | ||
29 | + module SearchHelper | ||
30 | + def asset_class(asset) | ||
31 | + asset.to_s.singularize.camelize.constantize | ||
32 | + end | ||
33 | + | ||
34 | + def asset_table(asset) | ||
35 | + asset_class(asset).table_name | ||
36 | + end | ||
37 | + | ||
38 | + def multiple_search? | ||
39 | + ['index', 'category_index'].include?(context.params[:action]) | ||
40 | + end | ||
41 | + | ||
42 | + def filters(asset) | ||
43 | + case asset | ||
44 | + when :products | ||
45 | + ['solr_plugin_public:true'] | ||
46 | + when :events | ||
47 | + [] | ||
48 | + else | ||
49 | + ['solr_plugin_public:true'] | ||
50 | + end | ||
51 | + end | ||
52 | + | ||
53 | + def results_only? | ||
54 | + context.params[:action] == 'index' | ||
55 | + end | ||
56 | + | ||
57 | + def solr_options(asset, category) | ||
58 | + asset_class = asset_class(asset) | ||
59 | + solr_options = {} | ||
60 | + if !multiple_search? | ||
61 | + if !results_only? and asset_class.respond_to? :facets | ||
62 | + solr_options.merge! asset_class.facets_find_options(context.params[:facet]) | ||
63 | + solr_options[:all_facets] = true | ||
64 | + end | ||
65 | + solr_options[:filter_queries] ||= [] | ||
66 | + solr_options[:filter_queries] += filters(asset) | ||
67 | + solr_options[:filter_queries] << "environment_id:#{context.environment.id}" | ||
68 | + solr_options[:filter_queries] << asset_class.facet_category_query.call(category) if category | ||
69 | + | ||
70 | + solr_options[:boost_functions] ||= [] | ||
71 | + context.params[:order_by] = nil if context.params[:order_by] == 'none' | ||
72 | + if context.params[:order_by] | ||
73 | + order = SolrPlugin::SortOptions[asset][context.params[:order_by].to_sym] | ||
74 | + raise "Unknown order by" if order.nil? | ||
75 | + order[:solr_opts].each do |opt, value| | ||
76 | + solr_options[opt] = value.is_a?(Proc) ? instance_eval(&value) : value | ||
77 | + end | ||
78 | + end | ||
79 | + end | ||
80 | + solr_options | ||
81 | + end | ||
82 | + end | ||
83 | +end |
@@ -0,0 +1,115 @@ | @@ -0,0 +1,115 @@ | ||
1 | +require 'test_helper' | ||
2 | + | ||
3 | +class ArticleTest < ActiveSupport::TestCase | ||
4 | + def setup | ||
5 | + @environment = Environment.default | ||
6 | + @environment.enable_plugin(SolrPlugin) | ||
7 | + @profile = create_user('testing').person | ||
8 | + end | ||
9 | + | ||
10 | + attr_accessor :environment, :profile | ||
11 | + | ||
12 | + should 'act as faceted' do | ||
13 | + person = fast_create(Person) | ||
14 | + cat = Category.create!(:name => 'hardcore', :environment_id => Environment.default.id) | ||
15 | + a = Article.create!(:name => 'black flag review', :profile_id => person.id) | ||
16 | + a.add_category(cat, true) | ||
17 | + a.save! | ||
18 | + assert_equal Article.type_name, Article.facet_by_id(:solr_plugin_f_type)[:proc].call(a.send(:solr_plugin_f_type)) | ||
19 | + assert_equal Person.type_name, Article.facet_by_id(:solr_plugin_f_profile_type)[:proc].call(a.send(:solr_plugin_f_profile_type)) | ||
20 | + assert_equal a.published_at, a.send(:solr_plugin_f_published_at) | ||
21 | + assert_equal ['hardcore'], a.send(:solr_plugin_f_category) | ||
22 | + assert_equal "solr_plugin_category_filter:\"#{cat.id}\"", Article.facet_category_query.call(cat) | ||
23 | + end | ||
24 | + | ||
25 | + should 'act as searchable' do | ||
26 | + TestSolr.enable | ||
27 | + person = fast_create(Person, :name => "Hiro", :address => 'U-Stor-It @ Inglewood, California', | ||
28 | + :nickname => 'Protagonist') | ||
29 | + person2 = fast_create(Person, :name => "Raven") | ||
30 | + category = fast_create(Category, :name => "science fiction", :acronym => "sf", :abbreviation => "sci-fi") | ||
31 | + a = Article.create!(:name => 'a searchable article about bananas', :profile_id => person.id, | ||
32 | + :body => 'the body talks about mosquitos', :abstract => 'and the abstract is about beer', | ||
33 | + :filename => 'not_a_virus.exe') | ||
34 | + a.add_category(category) | ||
35 | + c = a.comments.build(:title => 'snow crash', :author => person2, :body => 'wanna try some?') | ||
36 | + c.save! | ||
37 | + | ||
38 | + # fields | ||
39 | + assert_includes Article.find_by_contents('bananas')[:results].docs, a | ||
40 | + assert_includes Article.find_by_contents('mosquitos')[:results].docs, a | ||
41 | + assert_includes Article.find_by_contents('beer')[:results].docs, a | ||
42 | + assert_includes Article.find_by_contents('not_a_virus.exe')[:results].docs, a | ||
43 | + # filters | ||
44 | + assert_includes Article.find_by_contents('bananas', {}, {:filter_queries => ["solr_plugin_public:true"]})[:results].docs, a | ||
45 | + assert_not_includes Article.find_by_contents('bananas', {}, {:filter_queries => ["solr_plugin_public:false"]})[:results].docs, a | ||
46 | + assert_includes Article.find_by_contents('bananas', {}, {:filter_queries => ["environment_id:\"#{Environment.default.id}\""]})[:results].docs, a | ||
47 | + assert_includes Article.find_by_contents('bananas', {}, {:filter_queries => ["profile_id:\"#{person.id}\""]})[:results].docs, a | ||
48 | + # includes | ||
49 | + assert_includes Article.find_by_contents('Hiro')[:results].docs, a | ||
50 | + assert_includes Article.find_by_contents("person-#{person.id}")[:results].docs, a | ||
51 | + assert_includes Article.find_by_contents("California")[:results].docs, a | ||
52 | + assert_includes Article.find_by_contents("Protagonist")[:results].docs, a | ||
53 | +# FIXME: After merging with AI1826, searching on comments is not working | ||
54 | +# assert_includes Article.find_by_contents("snow")[:results].docs, a | ||
55 | +# assert_includes Article.find_by_contents("try some")[:results].docs, a | ||
56 | +# assert_includes Article.find_by_contents("Raven")[:results].docs, a | ||
57 | +# | ||
58 | +# FIXME: After merging with AI1826, searching on categories is not working | ||
59 | +# assert_includes Article.find_by_contents("science")[:results].docs, a | ||
60 | +# assert_includes Article.find_by_contents(category.slug)[:results].docs, a | ||
61 | +# assert_includes Article.find_by_contents("sf")[:results].docs, a | ||
62 | +# assert_includes Article.find_by_contents("sci-fi")[:results].docs, a | ||
63 | + end | ||
64 | + | ||
65 | + should 'boost name matches' do | ||
66 | + TestSolr.enable | ||
67 | + person = fast_create(Person) | ||
68 | + in_body = Article.create!(:name => 'something', :profile_id => person.id, :body => 'bananas in the body!') | ||
69 | + in_name = Article.create!(:name => 'bananas in the name!', :profile_id => person.id) | ||
70 | + assert_equal [in_name, in_body], Article.find_by_contents('bananas')[:results].docs | ||
71 | + end | ||
72 | + | ||
73 | + should 'boost if profile is enabled' do | ||
74 | + TestSolr.enable | ||
75 | + person2 = fast_create(Person, :enabled => false) | ||
76 | + art_profile_disabled = Article.create!(:name => 'profile disabled', :profile_id => person2.id) | ||
77 | + person1 = fast_create(Person, :enabled => true) | ||
78 | + art_profile_enabled = Article.create!(:name => 'profile enabled', :profile_id => person1.id) | ||
79 | + assert_equal [art_profile_enabled, art_profile_disabled], Article.find_by_contents('profile')[:results].docs | ||
80 | + end | ||
81 | + | ||
82 | + should 'index comments body together with article' do | ||
83 | + TestSolr.enable | ||
84 | + owner = create_user('testuser').person | ||
85 | + art = fast_create(TinyMceArticle, :profile_id => owner.id, :name => 'ytest') | ||
86 | + c1 = Comment.create(:title => 'test comment', :body => 'anything', :author => owner, :source => art); c1.save! | ||
87 | + | ||
88 | + assert_includes Article.find_by_contents('anything')[:results], art | ||
89 | + end | ||
90 | + | ||
91 | + should 'index by schema name when database is postgresql' do | ||
92 | + TestSolr.enable | ||
93 | + uses_postgresql 'schema_one' | ||
94 | + art1 = Article.create!(:name => 'some thing', :profile_id => @profile.id) | ||
95 | + assert_equal [art1], Article.find_by_contents('thing')[:results].docs | ||
96 | + uses_postgresql 'schema_two' | ||
97 | + art2 = Article.create!(:name => 'another thing', :profile_id => @profile.id) | ||
98 | + assert_not_includes Article.find_by_contents('thing')[:results], art1 | ||
99 | + assert_includes Article.find_by_contents('thing')[:results], art2 | ||
100 | + uses_postgresql 'schema_one' | ||
101 | + assert_includes Article.find_by_contents('thing')[:results], art1 | ||
102 | + assert_not_includes Article.find_by_contents('thing')[:results], art2 | ||
103 | + uses_sqlite | ||
104 | + end | ||
105 | + | ||
106 | + should 'not index by schema name when database is not postgresql' do | ||
107 | + TestSolr.enable | ||
108 | + uses_sqlite | ||
109 | + art1 = Article.create!(:name => 'some thing', :profile_id => @profile.id) | ||
110 | + assert_equal [art1], Article.find_by_contents('thing')[:results].docs | ||
111 | + art2 = Article.create!(:name => 'another thing', :profile_id => @profile.id) | ||
112 | + assert_includes Article.find_by_contents('thing')[:results], art1 | ||
113 | + assert_includes Article.find_by_contents('thing')[:results], art2 | ||
114 | + end | ||
115 | +end |
@@ -0,0 +1,29 @@ | @@ -0,0 +1,29 @@ | ||
1 | +require 'test_helper' | ||
2 | + | ||
3 | +class EnvironmentTest < ActiveSupport::TestCase | ||
4 | + def setup | ||
5 | + @environment = Environment.default | ||
6 | + @environment.enable_plugin(SolrPlugin) | ||
7 | + end | ||
8 | + | ||
9 | + attr_accessor :environment | ||
10 | + | ||
11 | + should 'find by contents from articles' do | ||
12 | + TestSolr.enable | ||
13 | + env = fast_create(Environment) | ||
14 | + env.enable_plugin(SolrPlugin) | ||
15 | + assert_nothing_raised do | ||
16 | + env.articles.find_by_contents('')[:results] | ||
17 | + end | ||
18 | + end | ||
19 | + | ||
20 | + should 'return more than 10 enterprises by contents' do | ||
21 | + TestSolr.enable | ||
22 | + Enterprise.destroy_all | ||
23 | + ('1'..'20').each do |n| | ||
24 | + Enterprise.create!(:name => 'test ' + n, :identifier => 'test_' + n) | ||
25 | + end | ||
26 | + | ||
27 | + assert_equal 20, environment.enterprises.find_by_contents('test')[:results].total_entries | ||
28 | + end | ||
29 | +end |
@@ -0,0 +1,23 @@ | @@ -0,0 +1,23 @@ | ||
1 | +require 'test_helper' | ||
2 | + | ||
3 | +class EventTest < ActiveSupport::TestCase | ||
4 | + def setup | ||
5 | + @environment = Environment.default | ||
6 | + @environment.enable_plugin(SolrPlugin) | ||
7 | + @profile = create_user('testing').person | ||
8 | + end | ||
9 | + | ||
10 | + attr_accessor :environment, :profile | ||
11 | + | ||
12 | + should 'be indexed by title' do | ||
13 | + TestSolr.enable | ||
14 | + e = Event.create!(:name => 'my surprisingly nice event', :start_date => Date.new(2008, 06, 06), :profile => profile) | ||
15 | + assert_includes Event.find_by_contents('surprisingly')[:results], e | ||
16 | + end | ||
17 | + | ||
18 | + should 'be indexed by body' do | ||
19 | + TestSolr.enable | ||
20 | + e = Event.create!(:name => 'bli', :start_date => Date.new(2008, 06, 06), :profile => profile, :body => 'my surprisingly long description about my freaking nice event') | ||
21 | + assert_includes Event.find_by_contents('surprisingly')[:results], e | ||
22 | + end | ||
23 | +end |
@@ -0,0 +1,17 @@ | @@ -0,0 +1,17 @@ | ||
1 | +require 'test_helper' | ||
2 | + | ||
3 | +class TextArticleTest < ActiveSupport::TestCase | ||
4 | + def setup | ||
5 | + @environment = Environment.default | ||
6 | + @environment.enable_plugin(SolrPlugin) | ||
7 | + end | ||
8 | + | ||
9 | + attr_accessor :environment | ||
10 | + | ||
11 | + should 'found TextileArticle by TextArticle indexes' do | ||
12 | + TestSolr.enable | ||
13 | + person = create_user('testuser').person | ||
14 | + article = TextileArticle.create!(:name => 'found article test', :profile => person) | ||
15 | + assert_equal TextileArticle.find_by_contents('found')[:results].docs, TextArticle.find_by_contents('found')[:results].docs | ||
16 | + end | ||
17 | +end |
@@ -0,0 +1,18 @@ | @@ -0,0 +1,18 @@ | ||
1 | +require 'test_helper' | ||
2 | + | ||
3 | +class TinyMceArticleTest < ActiveSupport::TestCase | ||
4 | + def setup | ||
5 | + @environment = Environment.default | ||
6 | + @environment.enable_plugin(SolrPlugin) | ||
7 | + @profile = create_user('testing').person | ||
8 | + end | ||
9 | + | ||
10 | + attr_accessor :environment, :profile | ||
11 | + | ||
12 | + should 'be found when searching for articles by query' do | ||
13 | + TestSolr.enable | ||
14 | + tma = TinyMceArticle.create!(:name => 'test tinymce article', :body => '---', :profile => profile) | ||
15 | + assert_includes TinyMceArticle.find_by_contents('article')[:results], tma | ||
16 | + assert_includes Article.find_by_contents('article')[:results], tma | ||
17 | + end | ||
18 | +end |
No preview for this file type
No preview for this file type
@@ -0,0 +1,10 @@ | @@ -0,0 +1,10 @@ | ||
1 | +<% if logged_in? %> | ||
2 | + <% button_bar do %> | ||
3 | + <%# FIXME shouldn't the user create the community in the current environment instead of going to its home environment? %> | ||
4 | + <%= button(:add, __('New community'), user.url.merge(:controller => 'memberships', :action => 'new_community', :profile => user.identifier)) if @asset == :communities %> | ||
5 | + <%= button(:add, __('New enterprise'), {:controller => 'enterprise_registration'}) if @asset == :enterprises && environment.enabled?('enterprise_registration') %> | ||
6 | + <% end %> | ||
7 | +<% end %> | ||
8 | +<% if !@empty_query %> | ||
9 | + <%= facets_menu(@asset, @facets) %> | ||
10 | +<% end %> |
@@ -0,0 +1,36 @@ | @@ -0,0 +1,36 @@ | ||
1 | +<% less_options_limit = 8 %> | ||
2 | + | ||
3 | +<div id="facets-menu"> | ||
4 | + <% @asset_class.map_facets_for(environment).each do |facet| %> | ||
5 | + | ||
6 | + <div id="facet-menu-<%= facet[:id].to_s %>" class="facet-menu"> | ||
7 | + <div class="facet-menu-label"> | ||
8 | + <%= @asset_class.facet_label(facet) %> | ||
9 | + </div> | ||
10 | + | ||
11 | + <% results = @asset_class.map_facet_results(facet, params[:facet], @facets, @all_facets, :limit => less_options_limit) %> | ||
12 | + <% facet_count = results.total_entries %> | ||
13 | + | ||
14 | + <% if facet_count > 0 %> | ||
15 | + <div class="facet-menu-options facet-menu-more-options" style="display: none"> | ||
16 | + </div> | ||
17 | + | ||
18 | + <div class="facet-menu-options facet-menu-less-options"> | ||
19 | + <% results.each do |id, label, count| %> | ||
20 | + <%= facet_link_html(facet, params, id, label, count) %><br /> | ||
21 | + <% end %> | ||
22 | + </div> <br /> | ||
23 | + | ||
24 | + <% if facet_count > less_options_limit %> | ||
25 | + <%= link_to_function _("Options"), | ||
26 | + "facet_options_toggle('#{facet[:id].to_s}', '#{url_for(params.merge(:action => 'facets_browse', :facet_id => facet[:id], :asset => @asset, :escape => false))}'); " + | ||
27 | + "jQuery(this).toggleClass('facet-less-options')", :class => "facet-options-toggle" %> | ||
28 | + <br /> | ||
29 | + <% end %> | ||
30 | + | ||
31 | + <% else %> | ||
32 | + <span class="facet-any-result-found"><%= _("No filter available") %></span> | ||
33 | + <% end %> | ||
34 | + </div> | ||
35 | + <% end %> | ||
36 | +</div> |
@@ -0,0 +1,7 @@ | @@ -0,0 +1,7 @@ | ||
1 | +<%= render :partial => 'search_form', :locals => { :hint => _("Type words about the %s you're looking for") % @asset.to_s.singularize } %> | ||
2 | +<%= render :partial => 'results_header' %> | ||
3 | + | ||
4 | +<%= display_results(@asset) %> | ||
5 | +<% if params[:display] != 'map' %> | ||
6 | + <%= pagination_links @results[@asset] %> | ||
7 | +<% end %> |
@@ -0,0 +1,22 @@ | @@ -0,0 +1,22 @@ | ||
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 | + <% if @results[@asset].total_entries > 0 %> | ||
5 | + <%= label_total_found(@asset, @results[@asset].total_entries) %> | ||
6 | + <% if params[:display] != 'map' %> | ||
7 | + <span class="current-page"><%= _("Showing page %s of %s") % [@results[@asset].current_page, @results[@asset].total_pages] %></span> | ||
8 | + <% end %> | ||
9 | + <% end %> | ||
10 | + </div> | ||
11 | + | ||
12 | + <div class="search-results-header-facets-order-by"> | ||
13 | + <%= facets_unselect_menu(@asset) %> | ||
14 | + <%= order_by(@asset) if params[:display] != 'map' %> | ||
15 | + </div> | ||
16 | + <% else %> | ||
17 | + <div id='search-filter-title'><%= @filter_title if @filter_title %></div> | ||
18 | + <% end %> | ||
19 | + <% float = !@empty_query && params[:display] == 'list' ? 'left' : 'right' %> | ||
20 | + <%= display_filter(@asset, params[:display], float) if map_capable?(@asset) %> | ||
21 | + <div style="clear: both"></div> | ||
22 | +</div> |
@@ -0,0 +1,24 @@ | @@ -0,0 +1,24 @@ | ||
1 | +<% extend SolrPlugin::ResultsHelper %> | ||
2 | +<% set_results_variables %> | ||
3 | + | ||
4 | +<%= search_page_title( @titles[@asset], @category ) %> | ||
5 | + | ||
6 | +<% if !@empty_query %> | ||
7 | + <div id='search-column-left'> | ||
8 | + <%= render :partial => 'facets' %> | ||
9 | + </div> | ||
10 | + | ||
11 | + <div id='search-column-right'> | ||
12 | + <%= render :partial => 'results' %> | ||
13 | + </div> | ||
14 | +<% else %> | ||
15 | + <%= render :partial => 'results' %> | ||
16 | +<% end %> | ||
17 | + | ||
18 | +<div style="clear: both"></div> | ||
19 | + | ||
20 | +<% if @asset == :products %> | ||
21 | + <% javascript_tag do %> | ||
22 | + jQuery('.search-product-price-details').altBeautify(); | ||
23 | + <% end %> | ||
24 | +<% end %> |
public/stylesheets/search.css
@@ -647,6 +647,7 @@ li.search-product-item hr { | @@ -647,6 +647,7 @@ li.search-product-item hr { | ||
647 | font-weight: bold; | 647 | font-weight: bold; |
648 | font-size: 130%; | 648 | font-size: 130%; |
649 | line-height: 35px; | 649 | line-height: 35px; |
650 | + float: left; | ||
650 | } | 651 | } |
651 | .search-results-header.search-no-results { | 652 | .search-results-header.search-no-results { |
652 | border-bottom: 0px; | 653 | border-bottom: 0px; |
@@ -665,6 +666,9 @@ li.search-product-item hr { | @@ -665,6 +666,9 @@ li.search-product-item hr { | ||
665 | color: #ff0000 | 666 | color: #ff0000 |
666 | } | 667 | } |
667 | 668 | ||
669 | +#search-display-filter { | ||
670 | + margin-top: 20px; | ||
671 | +} | ||
668 | 672 | ||
669 | /* Search field and button */ | 673 | /* Search field and button */ |
670 | 674 |