Module: SearchHelper

Defined in:
app/helpers/search_helper.rb

Overview

Markup generators for the search controller

Instance Method Summary (collapse)

Instance Method Details

- (String) document_bibliography_entry(doc)

Get the short, formatted representation of a document

This function returns the short bibliographic entry for a document that will appear in the search results list. The formatting here depends on the current user's settings. By default, we use a jQuery Mobile-formatted partial with an H3 and some P's. The user can set, however, to format the bibliographic entries using their favorite CSL style.

Examples:

Get the entry for a given document

document_bibliography_entry(Document.new(authors: 'W. Johnson',
                                         year: '2000'))
# "Johnson, W. 2000. ..."


304
305
306
307
308
309
310
# File 'app/helpers/search_helper.rb', line 304

def document_bibliography_entry(doc)
  if user_signed_in? && current_user.csl_style
    return doc.to_csl_entry(current_user.csl_style)
  end

  render partial: 'document', locals: { document: doc }
end

Create a link to the given set of facets

This function converts an array of facets to a link (generated via link_to) to the search page for that filtered query. All parameters other than :fq are simply duplicated (including the search query itself, :q).

Examples:

Get a “remove all facets” link

facet_link("Remove all facets", [])
# => link_to "Remove all facets", search_path

Get a link to a given set of facets

facet_link("Some facets", [...])
# => link_to "Some facets", search_path({ fq: [ ... ] })


174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'app/helpers/search_helper.rb', line 174

def facet_link(text, facets)
  new_params = params.dup

  if facets.empty?
    new_params[:fq] = nil
    return link_to text,
                   search_path(new_params),
                   data: { transition: 'none' }
  end

  new_params[:fq] = []
  facets.each { |f| new_params[:fq] << f.query }
  link_to text,
          search_path(new_params),
          data: { transition: 'none' }
end

Return a set of list items for faceted browsing

This function queries both the active facets on the current search and the available facets for authors, journals, and years. It returns a set of <li> elements (not a <ul>), including list dividers.

Examples:

Get all of the links for faceted browsing

facet_link_list(@result)
# "<li>Active Filters</li>...<li>Authors</li><li>"
  "<a href='...'>Johnson</a></li>..."


243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
# File 'app/helpers/search_helper.rb', line 243

def facet_link_list(result)
  # Bail now if there's no facet data (faceted down to one document)
  return ''.html_safe unless result.facets

  # Convert the active facet queries to facets
  active_facets = []
  if params[:fq]
    params[:fq].each do |query|
      active_facets << result.facets.for_query(query)
    end
    active_facets.compact!
  end

  # Start with the active facets
  ret = ''.html_safe
  unless active_facets.empty?
    ret << (:li,
                       I18n.t('search.index.active_filters'),
                       data: { role: 'list-divider' })
    ret << (:li, data: { icon: 'delete' }) do
      facet_link I18n.t('search.index.remove_all'), []
    end
    active_facets.each do |f|
      ret << (:li, data: { icon: 'delete' }) do
        other_facets = active_facets.reject { |x| x == f }
        facet_link "#{f.field_label}: #{f.label}", other_facets
      end
    end
  end

  # Run the facet-list code for all three facet fields
  ret << list_links_for_facet(result,
                              :authors_facet,
                              I18n.t('search.index.authors_facet'),
                              active_facets)
  ret << list_links_for_facet(result,
                              :journal_facet,
                              I18n.t('search.index.journal_facet'),
                              active_facets)
  ret << list_links_for_facet(result,
                              :year,
                              I18n.t('search.index.year_facet'),
                              active_facets)
  ret
end

Get the list of facet links for one particular field

This function takes the facets from the Document class, checks them against active_facets, and creates a set of list items. It is used by facet_link_list.

Examples:

Get the links for the authors facet

list_links_for_facet(@result, :authors_facet, "Authors", [...])
# "<li><a href='...'>Johnson <span class='ui-li-count'>2</a></li>..."


206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
# File 'app/helpers/search_helper.rb', line 206

def list_links_for_facet(result, field, header, active_facets)
  return ''.html_safe unless result.facets

  # Get the facets for this field
  facets = (result.facets.sorted_for_field(field) - active_facets).take(5)

  # Bail if there's no facets
  ret = ''.html_safe
  return ret if facets.empty?

  # Build the return value
  ret << (:li, header, data: { role: 'list-divider' })
  facets.each do |f|
    ret << (:li) do
      # Link to whatever the current facets are, plus the new one
      link = facet_link f.label, active_facets + [f]
      count =  :span, f.hits.to_s, class: 'ui-li-count'
      link + count
    end
  end

  ret
end

- (String) num_hits_string(result)

Return a formatted version of the number of hits for the last search

Examples:

Print the number of hits for the search (in HAML)

= num_hits_string(@result)


13
14
15
16
17
18
19
# File 'app/helpers/search_helper.rb', line 13

def num_hits_string(result)
  if params[:precise] || params[:q] || params[:fq]
    I18n.t 'search.index.num_hits_found', count: result.num_hits
  else
    I18n.t 'search.index.num_documents_database', count: result.num_hits
  end
end

Make a link to a page for the pagination widget

Examples:

Get a link to the 3rd page of results, with a right-arrow icon

page_link('Page 3!', 2, 'arrow-r', true)


31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'app/helpers/search_helper.rb', line 31

def page_link(text, num, icon = '', right = false)
  new_params = params.dup
  if num == 0
    new_params.delete :page
  else
    new_params[:page] = num
  end

  data = { transition: :none, role: :button }
  data[:icon] = icon unless icon.empty?
  data[:iconpos] = 'right' if right

  link_to text, search_path(new_params), data: data
end

- (String) render_pagination(result)

Render the pagination links

We currently render four buttons, in a 4x1 grid: first, previous, next, and last. Pagination is difficult for an application like this; we don't want infinite scroll, as there are far too many items, but full pagination (like that on Google or Flickr) really doesn't work on mobile devices. So this is a compromise.

Examples:

Put the current pagination links in a paragraph element

<p><%= render_pagination(@result) %></p>


59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'app/helpers/search_helper.rb', line 59

def render_pagination(result)
  num_pages = result.num_hits.to_f / @per_page.to_f
  num_pages = Integer(num_pages.ceil)
  return '' if num_pages == 0

   :div, class: 'ui-grid-c' do
    content = (:div, class: 'ui-block-a') do
      if @page != 0
        page_link(I18n.t('search.index.first_button'),
                  0,
                  'back')
      end
    end
    content << (:div, class: 'ui-block-b') do
      if @page != 0
        page_link(I18n.t('search.index.previous_button'),
                  @page - 1,
                  'arrow-l')
      end
    end

    content << (:div, class: 'ui-block-c') do
      if @page != (num_pages - 1)
        page_link(I18n.t('search.index.next_button'),
                  @page + 1,
                  'arrow-r',
                  true)
      end
    end
    content << (:div, class: 'ui-block-d') do
      if @page != num_pages - 1
        page_link(I18n.t('search.index.last_button'),
                  num_pages - 1,
                  'forward',
                  true)
      end
    end

    content
  end
end

- (Array<String>) sort_methods

Return an array of all sort methods

Examples:

Create links to all the sort methods

<%= sort_methods.each do |s| %>
  <%= link_to ... %>


108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'app/helpers/search_helper.rb', line 108

def sort_methods
  [
    'score desc',
    'authors_sort asc',
    'authors_sort desc',
    'title_sort asc',
    'title_sort desc',
    'journal_sort asc',
    'journal_sort desc',
    'year_sort asc',
    'year_sort desc'
  ]
end

- (String) sort_to_string(sort)

Get the given sort method as a string

This function converts a sort method ('relevance', 'title', 'author', 'journal', 'year') and sort direction ('asc' or 'desc') into a user-friendly string.

Examples:

Get the user-friendly version of 'score desc'

sort_to_string 'score desc'
# => 'Sort: Relevance'


134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'app/helpers/search_helper.rb', line 134

def sort_to_string(sort)
  parts = sort.split(' ')
  return I18n.t('search.index.sort_unknown') unless parts.count == 2

  method = parts[0]
  dir = I18n.t("search.index.sort_#{parts[1]}")

  method_spec = case method
                when 'score'
                  I18n.t('search.index.sort_score')
                when 'title_sort'
                  "#{Document.human_attribute_name('title')} #{dir}"
                when 'authors_sort'
                  "#{Document.human_attribute_name('authors')} #{dir}"
                when 'journal_sort'
                  "#{Document.human_attribute_name('journal')} #{dir}"
                when 'year_sort'
                  "#{Document.human_attribute_name('year')} #{dir}"
                end

  "#{I18n.t('search.index.sort_prefix')} #{method_spec}"
end