Commit 6e82bdc7062af8f0447fff19593054948cbeb5e5
1 parent
144d5783
Exists in
staging
and in
42 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 |