blacklight 5.7.2 → 5.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -3
  3. data/Gemfile +1 -4
  4. data/VERSION +1 -1
  5. data/app/assets/stylesheets/blacklight/_catalog.css.scss +38 -1
  6. data/app/assets/stylesheets/blacklight/_facets.css.scss +10 -0
  7. data/app/assets/stylesheets/blacklight/_layout.css.scss +6 -0
  8. data/app/controllers/bookmarks_controller.rb +3 -163
  9. data/app/helpers/blacklight/blacklight_helper_behavior.rb +18 -186
  10. data/app/helpers/blacklight/catalog_helper_behavior.rb +36 -2
  11. data/app/helpers/blacklight/component_helper_behavior.rb +77 -0
  12. data/app/helpers/blacklight/configuration_helper_behavior.rb +30 -21
  13. data/app/helpers/blacklight/render_partials_helper.rb +185 -0
  14. data/app/helpers/blacklight/url_helper_behavior.rb +24 -3
  15. data/app/helpers/component_helper.rb +3 -0
  16. data/app/views/_user_util_links.html.erb +2 -15
  17. data/app/views/blacklight/nav/_bookmark.html.erb +4 -0
  18. data/app/views/blacklight/nav/_saved_searches.html.erb +1 -0
  19. data/app/views/blacklight/nav/_search_history.html.erb +1 -0
  20. data/app/views/bookmarks/_tools.html.erb +6 -9
  21. data/app/views/bookmarks/index.html.erb +1 -1
  22. data/app/views/catalog/_bookmark_control.html.erb +8 -8
  23. data/app/views/catalog/_constraints_element.html.erb +1 -1
  24. data/app/views/catalog/_document_action.html.erb +4 -0
  25. data/app/views/catalog/_email_form.html.erb +1 -1
  26. data/app/views/catalog/_facet_limit.html.erb +1 -1
  27. data/app/views/catalog/_index_header_default.html.erb +5 -6
  28. data/app/views/catalog/_per_page_widget.html.erb +3 -1
  29. data/app/views/catalog/_results_pagination.html.erb +1 -1
  30. data/app/views/catalog/_search_form.html.erb +5 -8
  31. data/app/views/catalog/_show_more_like_this.html.erb +2 -2
  32. data/app/views/catalog/_show_tools.html.erb +5 -34
  33. data/app/views/catalog/_sms_form.html.erb +1 -1
  34. data/app/views/catalog/_sort_and_per_page.html.erb +2 -6
  35. data/app/views/catalog/_sort_widget.html.erb +1 -1
  36. data/app/views/catalog/_zero_results.html.erb +2 -2
  37. data/app/views/catalog/citation.js.erb +1 -1
  38. data/app/views/catalog/email_sent.html.erb +2 -9
  39. data/app/views/catalog/email_success.html.erb +9 -0
  40. data/app/views/catalog/sms_sent.html.erb +2 -9
  41. data/app/views/catalog/sms_success.html.erb +9 -0
  42. data/app/views/kaminari/blacklight/_gap.html.erb +1 -1
  43. data/app/views/kaminari/blacklight/_page.html.erb +5 -1
  44. data/app/views/shared/_header_navbar.html.erb +1 -1
  45. data/config/locales/blacklight.en.yml +1 -1
  46. data/config/locales/blacklight.es.yml +1 -1
  47. data/config/locales/blacklight.fr.yml +1 -1
  48. data/config/locales/blacklight.pt-BR.yml +1 -1
  49. data/lib/blacklight.rb +3 -0
  50. data/lib/blacklight/base.rb +0 -1
  51. data/lib/blacklight/bookmarks.rb +135 -0
  52. data/lib/blacklight/catalog.rb +58 -77
  53. data/lib/blacklight/catalog/component_configuration.rb +99 -0
  54. data/lib/blacklight/configuration.rb +82 -4
  55. data/lib/blacklight/configuration/tool_config.rb +4 -0
  56. data/lib/blacklight/controller.rb +5 -1
  57. data/lib/blacklight/document_presenter.rb +17 -8
  58. data/lib/blacklight/request_builders.rb +136 -4
  59. data/lib/blacklight/routes.rb +5 -0
  60. data/lib/blacklight/solr_helper.rb +90 -208
  61. data/lib/blacklight/solr_repository.rb +69 -0
  62. data/lib/blacklight/token_based_user.rb +58 -0
  63. data/lib/blacklight/utils.rb +13 -1
  64. data/lib/generators/blacklight/install_generator.rb +6 -7
  65. data/spec/controllers/alternate_controller_spec.rb +19 -0
  66. data/spec/controllers/catalog_controller_spec.rb +89 -4
  67. data/spec/features/alternate_controller_spec.rb +0 -1
  68. data/spec/features/bookmarks_spec.rb +31 -6
  69. data/spec/features/search_results_spec.rb +11 -0
  70. data/spec/features/search_spec.rb +5 -0
  71. data/spec/helpers/blacklight_helper_spec.rb +49 -8
  72. data/spec/helpers/catalog_helper_spec.rb +56 -8
  73. data/spec/helpers/configuration_helper_spec.rb +5 -5
  74. data/spec/helpers/url_helper_spec.rb +15 -8
  75. data/spec/lib/blacklight/catalog/component_configuration_spec.rb +29 -0
  76. data/spec/lib/blacklight/configuration_spec.rb +15 -0
  77. data/spec/lib/blacklight/solr_helper_spec.rb +44 -104
  78. data/spec/lib/blacklight/solr_repository_spec.rb +113 -0
  79. data/spec/lib/utils_spec.rb +27 -0
  80. data/spec/views/_user_util_links.html.erb_spec.rb +6 -3
  81. data/spec/views/catalog/_show_sidebar.erb_spec.rb +8 -2
  82. data/spec/views/catalog/_show_tools.html.erb_spec.rb +82 -0
  83. data/spec/views/catalog/_sort_and_per_page.html.erb_spec.rb +15 -1
  84. data/tasks/blacklight.rake +25 -1
  85. metadata +24 -2
@@ -9,6 +9,8 @@ module Blacklight::CatalogHelperBehavior
9
9
  # @param [RSolr::Resource] (or other Kaminari-compatible objects)
10
10
  # @return [String]
11
11
  def page_entries_info(collection, options = {})
12
+ return unless show_pagination? collection
13
+
12
14
  entry_name = if options[:entry_name]
13
15
  options[:entry_name]
14
16
  elsif collection.respond_to? :model # DataMapper
@@ -92,7 +94,17 @@ module Blacklight::CatalogHelperBehavior
92
94
  #
93
95
  # @return [String]
94
96
  def render_document_class(document = @document)
95
- 'blacklight-' + document.get(blacklight_config.view_config(document_index_view_type_field).display_type_field).parameterize rescue nil
97
+ types = document[blacklight_config.view_config(document_index_view_type).display_type_field]
98
+
99
+ return if types.blank?
100
+
101
+ Array(types).map do |t|
102
+ document_class_prefix + t.parameterize rescue nil
103
+ end.join(' ')
104
+ end
105
+
106
+ def document_class_prefix
107
+ 'blacklight-'
96
108
  end
97
109
 
98
110
  ##
@@ -114,6 +126,16 @@ module Blacklight::CatalogHelperBehavior
114
126
  !response.empty?
115
127
  end
116
128
 
129
+ ##
130
+ # Should we display the pagination controls?
131
+ #
132
+ # @param [Blacklight::SolrResponse]
133
+ # @return [Boolean]
134
+ def show_pagination? response = nil
135
+ response ||= @response
136
+ response.limit_value > 0
137
+ end
138
+
117
139
  ##
118
140
  # If no search parameters have been given, we should
119
141
  # auto-focus the user's cursor into the searchbox
@@ -154,7 +176,7 @@ module Blacklight::CatalogHelperBehavior
154
176
  if url_options === false || url_options[:suppress_link]
155
177
  value
156
178
  else
157
- link_to_document document, url_options.merge(:label => value)
179
+ link_to_document document, value, url_options
158
180
  end
159
181
  end
160
182
  end
@@ -213,4 +235,16 @@ module Blacklight::CatalogHelperBehavior
213
235
  render('endnote') + render('refworks')
214
236
  end
215
237
  end
238
+
239
+ def render_refworks_action? config, options = {}
240
+ options[:document] && options[:document].respond_to?(:export_formats) && options[:document].export_formats.keys.include?(:refworks_marc_txt )
241
+ end
242
+
243
+ def render_endnote_action? config, options = {}
244
+ options[:document] && options[:document].respond_to?(:export_formats) && options[:document].export_formats.keys.include?(:endnote )
245
+ end
246
+
247
+ def render_librarian_view_control? config, options = {}
248
+ respond_to? :librarian_view_catalog_path and options[:document] and options[:document].respond_to?(:to_marc)
249
+ end
216
250
  end
@@ -0,0 +1,77 @@
1
+ module Blacklight
2
+ module ComponentHelperBehavior
3
+
4
+ def document_action_label action, opts
5
+ t("blacklight.tools.#{action}", default: opts.label || action.to_s.humanize)
6
+ end
7
+
8
+ def document_action_path action_opts, url_opts = nil
9
+ self.send(action_opts.path ||"#{action_opts.key}_#{controller_name}_path", url_opts)
10
+ end
11
+
12
+ ##
13
+ # Render "document actions" area for navigation header
14
+ # (normally renders "Saved Searches", "History", "Bookmarks")
15
+ #
16
+ # @param [Hash] options
17
+ # @return [String]
18
+ def render_nav_actions(options={}, &block)
19
+ render_filtered_partials(blacklight_config.navbar.partials, options, &block)
20
+ end
21
+
22
+ ##
23
+ # Render "document actions" area for search results view
24
+ # (normally renders next to title in the list view)
25
+ #
26
+ # @param [SolrDocument] document
27
+ # @param [Hash] options
28
+ # @option options [String] :wrapping_class
29
+ # @return [String]
30
+ def render_index_doc_actions(document, options={})
31
+ wrapping_class = options.delete(:wrapping_class) || "index-document-functions"
32
+ rendered = render_filtered_partials(blacklight_config.index.document_actions, { document: document }.merge(options))
33
+ content_tag("div", rendered, class: wrapping_class)
34
+ end
35
+
36
+ ##
37
+ # Render "collection actions" area for search results view
38
+ # (normally renders next to pagination at the top of the result set)
39
+ #
40
+ # @param [Hash] options
41
+ # @option options [String] :wrapping_class
42
+ # @return [String]
43
+ def render_results_collection_tools(options = {})
44
+ wrapping_class = options.delete(:wrapping_class) || "search-widgets"
45
+ rendered = render_filtered_partials(blacklight_config.index.collection_actions, options)
46
+ content_tag("div", rendered, class: wrapping_class)
47
+ end
48
+
49
+ def render_filtered_partials(partials, options={}, &block)
50
+ content = []
51
+ partials.select { |_, config| evaluate_if_unless_configuration config, options }.each do |key, config|
52
+ config.key ||= key
53
+ rendered = render(partial: config.partial || key.to_s, locals: { document_action_config: config }.merge(options))
54
+ if block_given?
55
+ yield config, rendered
56
+ else
57
+ content << rendered
58
+ end
59
+ end
60
+ safe_join(content, "\n") unless block_given?
61
+ end
62
+
63
+ ##
64
+ # Render "document actions" for the item detail 'show' view.
65
+ # (this normally renders next to title)
66
+ #
67
+ # By default includes 'Bookmarks'
68
+ #
69
+ # @param [SolrDocument] document
70
+ # @param [Hash] options
71
+ # @return [String]
72
+ def render_show_doc_actions(document=@document, options={}, &block)
73
+ render_filtered_partials(blacklight_config.show.document_actions, { document: document }.merge(options), &block)
74
+ end
75
+
76
+ end
77
+ end
@@ -58,36 +58,39 @@ module Blacklight::ConfigurationHelperBehavior
58
58
  ##
59
59
  # Look up the label for the index field
60
60
  def index_field_label document, field
61
- label = index_fields(document)[field].label
61
+ field_config = index_fields(document)[field]
62
62
 
63
63
  solr_field_label(
64
- label,
65
64
  :"blacklight.search.fields.index.#{field}",
66
- :"blacklight.search.fields.#{field}"
65
+ :"blacklight.search.fields.#{field}",
66
+ (field_config.label if field_config),
67
+ field.to_s.humanize
67
68
  )
68
69
  end
69
70
 
70
71
  ##
71
72
  # Look up the label for the show field
72
73
  def document_show_field_label document, field
73
- label = document_show_fields(document)[field].label
74
-
74
+ field_config = document_show_fields(document)[field]
75
+
75
76
  solr_field_label(
76
- label,
77
77
  :"blacklight.search.fields.show.#{field}",
78
- :"blacklight.search.fields.#{field}"
78
+ :"blacklight.search.fields.#{field}",
79
+ (field_config.label if field_config),
80
+ field.to_s.humanize
79
81
  )
80
82
  end
81
83
 
82
84
  ##
83
85
  # Look up the label for the facet field
84
86
  def facet_field_label field
85
- label = blacklight_config.facet_fields[field].label
87
+ field_config = blacklight_config.facet_fields[field]
86
88
 
87
89
  solr_field_label(
88
- label,
89
90
  :"blacklight.search.fields.facet.#{field}",
90
- :"blacklight.search.fields.#{field}"
91
+ :"blacklight.search.fields.#{field}",
92
+ (field_config.label if field_config),
93
+ field.to_s.humanize
91
94
  )
92
95
  end
93
96
 
@@ -103,15 +106,9 @@ module Blacklight::ConfigurationHelperBehavior
103
106
  # before falling back to the label
104
107
  # @param [Symbol] any number of additional keys
105
108
  # @param [Symbol] ...
106
- def solr_field_label label, *i18n_keys
107
- if label.is_a? Symbol
108
- return t(label)
109
- end
110
-
109
+ def solr_field_label *i18n_keys
111
110
  first, *rest = i18n_keys
112
111
 
113
- rest << label
114
-
115
112
  t(first, default: rest)
116
113
  end
117
114
 
@@ -167,15 +164,27 @@ module Blacklight::ConfigurationHelperBehavior
167
164
  ##
168
165
  # Determine whether to render a field by evaluating :if and :unless conditions
169
166
  #
170
- # @param [SolrDocument] document
171
167
  # @param [Blacklight::Solr::Configuration::SolrField] solr_field
172
168
  # @return [Boolean]
173
169
  def should_render_field? field_config, *args
174
- return field_config if field_config === true or field_config === false
170
+ evaluate_if_unless_configuration field_config, *args
171
+ end
172
+
173
+ ##
174
+ # Evaluate conditionals for a configuration with if/unless attributes
175
+ #
176
+ # @param displayable_config [#if,#unless] an object that responds to if/unless
177
+ # @return [Boolean]
178
+ def evaluate_if_unless_configuration displayable_config, *args
179
+ return displayable_config if displayable_config === true or displayable_config === false
175
180
 
176
- if_value = !field_config.respond_to?(:if) || field_config.if.nil? || evaluate_configuration_conditional(field_config.if, field_config, *args)
181
+ if_value = !displayable_config.respond_to?(:if) ||
182
+ displayable_config.if.nil? ||
183
+ evaluate_configuration_conditional(displayable_config.if, displayable_config, *args)
177
184
 
178
- unless_value = !field_config.respond_to?(:unless) || field_config.unless.nil? || !evaluate_configuration_conditional(field_config.unless, field_config, *args)
185
+ unless_value = !displayable_config.respond_to?(:unless) ||
186
+ displayable_config.unless.nil? ||
187
+ !evaluate_configuration_conditional(displayable_config.unless, displayable_config, *args)
179
188
 
180
189
  if_value && unless_value
181
190
  end
@@ -0,0 +1,185 @@
1
+ module Blacklight::RenderPartialsHelper
2
+ ##
3
+ # Render the document index view
4
+ #
5
+ # @param [Array<SolrDocument>] list of documents to render
6
+ # @param [Hash] locals to pass to the render call
7
+ # @return [String]
8
+ def render_document_index documents = nil, locals = {}
9
+ documents ||= @document_list
10
+ render_document_index_with_view(document_index_view_type, documents, locals)
11
+ end
12
+
13
+ ##
14
+ # Render the document index for a grouped response
15
+ def render_grouped_document_index
16
+ render 'catalog/group_default'
17
+ end
18
+
19
+ ##
20
+ # Return the list of partials for a given solr document
21
+ # @param [SolrDocument]
22
+ # @return [String]
23
+ def render_document_partials(doc, partials = [], locals ={})
24
+ safe_join(partials.map do |action_name|
25
+ render_document_partial(doc, action_name, locals)
26
+ end, "\n")
27
+ end
28
+
29
+ ##
30
+ # Given a doc and a base name for a partial, this method will attempt to render
31
+ # an appropriate partial based on the document format and view type.
32
+ #
33
+ # If a partial that matches the document format is not found,
34
+ # render a default partial for the base name.
35
+ #
36
+ # @see #document_partial_path_templates
37
+ #
38
+ # @param [SolrDocument] doc
39
+ # @param [String] base name for the partial
40
+ # @param [Hash] locales to pass through to the partials
41
+ def render_document_partial(doc, base_name, locals = {})
42
+ format = if method(:document_partial_name).arity == 1
43
+ Deprecation.warn self, "The #document_partial_name with a single argument is deprecated. Update your override to include a second argument for the 'base name'"
44
+ document_partial_name(doc)
45
+ else
46
+ document_partial_name(doc, base_name)
47
+ end
48
+
49
+ view_type = document_index_view_type
50
+ template = cached_view ['show', view_type, base_name, format].join('_') do
51
+ find_document_show_template_with_view(view_type, base_name, format, locals)
52
+ end
53
+ if template
54
+ template.render(self, locals.merge(document: doc))
55
+ else
56
+ ''
57
+ end
58
+ end
59
+
60
+ ##
61
+ # Render the document index for the given view type with the
62
+ # list of documents.
63
+ #
64
+ # This method will interpolate the list of templates with
65
+ # the current view, and gracefully handles missing templates.
66
+ #
67
+ # @see #document_index_path_templates
68
+ #
69
+ # @param [String] view type
70
+ # @param [Array<SolrDocument>] list of documents to render
71
+ # @param [Hash] locals to pass to the render call
72
+ # @return [String]
73
+ def render_document_index_with_view view, documents, locals = {}
74
+ template = cached_view ['index', view].join('_') do
75
+ find_document_index_template_with_view(view, locals)
76
+ end
77
+
78
+ if template
79
+ template.render(self, locals.merge(documents: documents))
80
+ else
81
+ ''
82
+ end
83
+ end
84
+
85
+ ##
86
+ # A list of document partial templates to attempt to render
87
+ #
88
+ # @see #render_document_index_with_view
89
+ # @return [Array<String>]
90
+ def document_index_path_templates
91
+ # first, the legacy template names for backwards compatbility
92
+ # followed by the new, inheritable style
93
+ # finally, a controller-specific path for non-catalog subclasses
94
+ @document_index_path_templates ||= ["document_%{index_view_type}", "catalog/document_%{index_view_type}", "catalog/document_list"]
95
+ end
96
+
97
+
98
+ protected
99
+ ##
100
+ # Return a partial name for rendering a document
101
+ # this method can be overridden in order to transform the value
102
+ # (e.g. 'PdfBook' => 'pdf_book')
103
+ #
104
+ # @param [SolrDocument] document
105
+ # @param [String, Array] display_type a value suggestive of a partial
106
+ # @return [String] the name of the partial to render
107
+ # @example
108
+ # type_field_to_partial_name(['a book-article'])
109
+ # => 'a_book_article'
110
+ def type_field_to_partial_name(document, display_type)
111
+ # using "_" as sep. to more closely follow the views file naming conventions
112
+ # parameterize uses "-" as the default sep. which throws errors
113
+ Array(display_type).join(" ").gsub("-","_").parameterize("_")
114
+ end
115
+
116
+ ##
117
+ # Return a normalized partial name for rendering a single document
118
+ #
119
+ # @param [SolrDocument]
120
+ # @param [Symbol] base name for the partial
121
+ # @return [String]
122
+ def document_partial_name(document, base_name = nil)
123
+ view_config = blacklight_config.view_config(:show)
124
+
125
+ display_type = if base_name and view_config.has_key? :"#{base_name}_display_type_field"
126
+ document[view_config[:"#{base_name}_display_type_field"]]
127
+ end
128
+
129
+ display_type ||= document[view_config.display_type_field]
130
+
131
+ display_type ||= 'default'
132
+
133
+ type_field_to_partial_name(document, display_type)
134
+ end
135
+
136
+ ##
137
+ # A list of document partial templates to try to render for a document
138
+ #
139
+ # The partial names will be interpolated with the following variables:
140
+ # - action_name: (e.g. index, show)
141
+ # - index_view_type: (the current view type, e.g. list, gallery)
142
+ # - format: the document's format (e.g. book)
143
+ #
144
+ # @see #render_document_partial
145
+ def document_partial_path_templates
146
+ # first, the legacy template names for backwards compatbility
147
+ # followed by the new, inheritable style
148
+ # finally, a controller-specific path for non-catalog subclasses
149
+ @partial_path_templates ||= ["%{action_name}_%{index_view_type}_%{format}", "%{action_name}_%{index_view_type}_default", "%{action_name}_%{format}", "%{action_name}_default", "catalog/%{action_name}_%{format}", "catalog/_%{action_name}_partials/%{format}", "catalog/_%{action_name}_partials/default"]
150
+ end
151
+
152
+ private
153
+ def find_document_show_template_with_view view_type, base_name, format, locals
154
+ document_partial_path_templates.each do |str|
155
+ partial = str % { action_name: base_name, format: format, index_view_type: view_type }
156
+ logger.debug "Looking for document partial #{partial}"
157
+ template = lookup_context.find_all(partial, lookup_context.prefixes + [""], true, locals.keys + [:document], {}).first
158
+ return template if template
159
+ end
160
+ nil
161
+ end
162
+
163
+ def find_document_index_template_with_view view, locals
164
+ document_index_path_templates.each do |str|
165
+ partial = str % { index_view_type: view }
166
+ logger.debug "Looking for document index partial #{partial}"
167
+ template = lookup_context.find_all(partial, lookup_context.prefixes + [""], true, locals.keys + [:documents], {}).first
168
+ return template if template
169
+ end
170
+ nil
171
+ end
172
+
173
+ ##
174
+ # @param [Symbol] page the page type, either :index or :show
175
+ # @param [String] type the type of object
176
+ # @block the block to evaluate if the cache misses
177
+ def cached_view key
178
+ @view_cache ||= {}
179
+ if @view_cache.key?(key)
180
+ @view_cache[key]
181
+ else
182
+ @view_cache[key] = yield
183
+ end
184
+ end
185
+ end
@@ -19,13 +19,24 @@ module Blacklight::UrlHelperBehavior
19
19
  end
20
20
  end
21
21
 
22
+ # link_to_document(doc, 'VIEW', :counter => 3)
22
23
  # link_to_document(doc, :label=>'VIEW', :counter => 3)
23
24
  # Use the catalog_path RESTful route to create a link to the show page for a specific item.
24
25
  # catalog_path accepts a HashWithIndifferentAccess object. The solr query params are stored in the session,
25
26
  # so we only need the +counter+ param here. We also need to know if we are viewing to document as part of search results.
26
- def link_to_document(doc, opts={:label=>nil, :counter => nil})
27
- opts[:label] ||= document_show_link_field(doc)
28
- label = render_document_index_label doc, opts
27
+ def link_to_document(doc, field_or_opts = nil, opts={:counter => nil})
28
+ if field_or_opts.kind_of? Hash
29
+ opts = field_or_opts
30
+ if opts[:label]
31
+ Deprecation.warn self, "The second argument to link_to_document should now be the label."
32
+ field = opts.delete(:label)
33
+ end
34
+ else
35
+ field = field_or_opts
36
+ end
37
+
38
+ field ||= document_show_link_field(doc)
39
+ label = presenter(doc).render_document_index_label field, opts
29
40
  link_to label, url_for_document(doc), document_link_params(doc, opts)
30
41
  end
31
42
 
@@ -287,6 +298,16 @@ module Blacklight::UrlHelperBehavior
287
298
  "http://www.refworks.com/express/expressimport.asp?vendor=#{CGI.escape(params[:vendor] || application_name)}&filter=#{CGI.escape(params[:filter] || "MARC Format")}&encoding=65001" + (("&url=#{CGI.escape(params[:url])}" if params[:url]) || "")
288
299
  end
289
300
 
301
+ def refworks_catalog_path opts = {}
302
+ if opts[:id]
303
+ refworks_export_url(url: polymorphic_url(url_for_document(opts[:id]), format: :refworks_marc_txt, only_path: false))
304
+ end
305
+ end
306
+
307
+ def endnote_catalog_path opts = {}
308
+ catalog_path(opts.merge(format: 'endnote'))
309
+ end
310
+
290
311
  if ::Rails.version < "4.0"
291
312
  def asset_url *args
292
313
  "#{request.protocol}#{request.host_with_port}#{asset_path(*args)}"