blacklight 5.7.2 → 5.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
@@ -5,7 +5,6 @@ module Blacklight::Base
5
5
  include Blacklight::Configurable
6
6
  include Blacklight::SolrHelper
7
7
 
8
- require 'blacklight/catalog/search_context'
9
8
  include Blacklight::Catalog::SearchContext
10
9
 
11
10
  included do
@@ -0,0 +1,135 @@
1
+ # -*- encoding : utf-8 -*-
2
+ # note that while this is mostly restful routing, the #update and #destroy actions
3
+ # take the Solr document ID as the :id, NOT the id of the actual Bookmark action.
4
+ module Blacklight::Bookmarks
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ ##
9
+ # Give Bookmarks access to the CatalogController configuration
10
+ include Blacklight::Configurable
11
+ include Blacklight::SolrHelper
12
+ include Blacklight::TokenBasedUser
13
+
14
+ copy_blacklight_config_from(CatalogController)
15
+
16
+ before_filter :verify_user
17
+
18
+ blacklight_config.show.document_actions[:bookmark].if = false if blacklight_config.show.document_actions[:bookmark]
19
+ blacklight_config.show.document_actions[:sms].if = false if blacklight_config.show.document_actions[:sms]
20
+ end
21
+
22
+ def action_documents
23
+ bookmarks = token_or_current_or_guest_user.bookmarks
24
+ bookmark_ids = bookmarks.collect { |b| b.document_id.to_s }
25
+ get_solr_response_for_document_ids(bookmark_ids)
26
+ end
27
+
28
+ def action_success_redirect_path
29
+ bookmarks_path
30
+ end
31
+
32
+ # Blacklight uses #search_action_url to figure out the right URL for
33
+ # the global search box
34
+ def search_action_url *args
35
+ catalog_index_url *args
36
+ end
37
+
38
+ def index
39
+ @bookmarks = token_or_current_or_guest_user.bookmarks
40
+ bookmark_ids = @bookmarks.collect { |b| b.document_id.to_s }
41
+
42
+ @response, @document_list = get_solr_response_for_document_ids(bookmark_ids)
43
+
44
+ respond_to do |format|
45
+ format.html { }
46
+ format.rss { render :layout => false }
47
+ format.atom { render :layout => false }
48
+ format.json do
49
+ render json: render_search_results_as_json
50
+ end
51
+
52
+ additional_response_formats(format)
53
+ document_export_formats(format)
54
+ end
55
+ end
56
+
57
+
58
+ def update
59
+ create
60
+ end
61
+
62
+ # For adding a single bookmark, suggest use PUT/#update to
63
+ # /bookmarks/$docuemnt_id instead.
64
+ # But this method, accessed via POST to /bookmarks, can be used for
65
+ # creating multiple bookmarks at once, by posting with keys
66
+ # such as bookmarks[n][document_id], bookmarks[n][title].
67
+ # It can also be used for creating a single bookmark by including keys
68
+ # bookmark[title] and bookmark[document_id], but in that case #update
69
+ # is simpler.
70
+ def create
71
+ if params[:bookmarks]
72
+ @bookmarks = params[:bookmarks]
73
+ else
74
+ @bookmarks = [{ document_id: params[:id], document_type: blacklight_config.solr_document_model.to_s }]
75
+ end
76
+
77
+ current_or_guest_user.save! unless current_or_guest_user.persisted?
78
+
79
+ success = @bookmarks.all? do |bookmark|
80
+ current_or_guest_user.bookmarks.where(bookmark).exists? || current_or_guest_user.bookmarks.create(bookmark)
81
+ end
82
+
83
+ if request.xhr?
84
+ success ? render(json: { bookmarks: { count: current_or_guest_user.bookmarks.count }}) : render(:text => "", :status => "500")
85
+ else
86
+ if @bookmarks.length > 0 && success
87
+ flash[:notice] = I18n.t('blacklight.bookmarks.add.success', :count => @bookmarks.length)
88
+ elsif @bookmarks.length > 0
89
+ flash[:error] = I18n.t('blacklight.bookmarks.add.failure', :count => @bookmarks.length)
90
+ end
91
+
92
+ redirect_to :back
93
+ end
94
+ end
95
+
96
+ # Beware, :id is the Solr document_id, not the actual Bookmark id.
97
+ # idempotent, as DELETE is supposed to be.
98
+ def destroy
99
+ bookmark = current_or_guest_user.bookmarks.where(document_id: params[:id], document_type: blacklight_config.solr_document_model).first
100
+
101
+ success = bookmark && bookmark.delete && bookmark.destroyed?
102
+
103
+ unless request.xhr?
104
+ if success
105
+ flash[:notice] = I18n.t('blacklight.bookmarks.remove.success')
106
+ else
107
+ flash[:error] = I18n.t('blacklight.bookmarks.remove.failure')
108
+ end
109
+ redirect_to :back
110
+ else
111
+ # ajaxy request needs no redirect and should not have flash set
112
+ success ? render(json: { bookmarks: { count: current_or_guest_user.bookmarks.count }}) : render(:text => "", :status => "500")
113
+ end
114
+ end
115
+
116
+ def clear
117
+ if current_or_guest_user.bookmarks.clear
118
+ flash[:notice] = I18n.t('blacklight.bookmarks.clear.success')
119
+ else
120
+ flash[:error] = I18n.t('blacklight.bookmarks.clear.failure')
121
+ end
122
+ redirect_to :action => "index"
123
+ end
124
+
125
+ protected
126
+ def verify_user
127
+ unless current_or_guest_user or (action == "index" and token_or_current_or_guest_user)
128
+ flash[:notice] = I18n.t('blacklight.bookmarks.need_login') and raise Blacklight::Exceptions::AccessDenied
129
+ end
130
+ end
131
+
132
+ def start_new_search_session?
133
+ action_name == "index"
134
+ end
135
+ end
@@ -1,8 +1,17 @@
1
1
  # -*- encoding : utf-8 -*-
2
- module Blacklight::Catalog
2
+ module Blacklight::Catalog
3
3
  extend ActiveSupport::Concern
4
-
4
+ extend ActiveSupport::Autoload
5
+
6
+ eager_autoload do
7
+ autoload :ComponentConfiguration
8
+ autoload :DocumentActions
9
+ autoload :SearchContext
10
+ end
11
+
5
12
  include Blacklight::Base
13
+ include Blacklight::Catalog::ComponentConfiguration
14
+ include Blacklight::Facet
6
15
 
7
16
  SearchHistoryWindow = 100 # how many searches to save in session history
8
17
 
@@ -18,13 +27,13 @@ module Blacklight::Catalog
18
27
 
19
28
  record_search_parameters
20
29
  end
21
-
30
+
22
31
  # get search results from the solr index
23
32
  def index
24
33
  (@response, @document_list) = get_search_results
25
-
34
+
26
35
  respond_to do |format|
27
- format.html { }
36
+ format.html { preferred_view }
28
37
  format.rss { render :layout => false }
29
38
  format.atom { render :layout => false }
30
39
  format.json do
@@ -35,10 +44,10 @@ module Blacklight::Catalog
35
44
  document_export_formats(format)
36
45
  end
37
46
  end
38
-
47
+
39
48
  # get single document from the solr index
40
49
  def show
41
- @response, @document = get_solr_response_for_doc_id
50
+ @response, @document = get_solr_response_for_doc_id params[:id]
42
51
 
43
52
  respond_to do |format|
44
53
  format.html {setup_next_and_previous_documents}
@@ -49,10 +58,10 @@ module Blacklight::Catalog
49
58
  # export formats.
50
59
  @document.export_formats.each_key do | format_name |
51
60
  # It's important that the argument to send be a symbol;
52
- # if it's a string, it makes Rails unhappy for unclear reasons.
61
+ # if it's a string, it makes Rails unhappy for unclear reasons.
53
62
  format.send(format_name.to_sym) { render :text => @document.export_as(format_name), :layout => false }
54
63
  end
55
-
64
+
56
65
  end
57
66
  end
58
67
 
@@ -80,14 +89,14 @@ module Blacklight::Catalog
80
89
 
81
90
  respond_to do |format|
82
91
  # Draw the facet selector for users who have javascript disabled:
83
- format.html
92
+ format.html
84
93
  format.json { render json: render_facet_list_as_json }
85
94
 
86
95
  # Draw the partial for the "more" facet modal window:
87
96
  format.js { render :layout => false }
88
97
  end
89
98
  end
90
-
99
+
91
100
  # method to serve up XML OpenSearch description and JSON autocomplete response
92
101
  def opensearch
93
102
  respond_to do |format|
@@ -99,72 +108,13 @@ module Blacklight::Catalog
99
108
  end
100
109
  end
101
110
  end
102
-
103
- # citation action
104
- def citation
105
- @response, @documents = get_solr_response_for_document_ids(params[:id])
106
- respond_to do |format|
107
- format.html
108
- format.js { render :layout => false }
109
- end
110
- end
111
-
112
-
113
- # Email Action (this will render the appropriate view on GET requests and process the form and send the email on POST requests)
114
- def email
115
- @response, @documents = get_solr_response_for_document_ids(params[:id])
116
-
117
- if request.post? and validate_email_params
118
- email = RecordMailer.email_record(@documents, {:to => params[:to], :message => params[:message]}, url_options)
119
-
120
- if email.respond_to? :deliver_now
121
- email.deliver_now
122
- else
123
- email.deliver
124
- end
125
-
126
- flash[:success] = I18n.t("blacklight.email.success")
127
-
128
- respond_to do |format|
129
- format.html { redirect_to catalog_path(params['id']) }
130
- format.js { render 'email_sent' }
131
- end and return
132
- end
133
111
 
134
- respond_to do |format|
135
- format.html
136
- format.js { render :layout => false }
137
- end
112
+ def action_documents
113
+ get_solr_response_for_document_ids(params[:id])
138
114
  end
139
115
 
140
-
141
- # SMS action (this will render the appropriate view on GET requests and process the form and send the email on POST requests)
142
- def sms
143
- @response, @documents = get_solr_response_for_document_ids(params[:id])
144
-
145
- if request.post? and validate_sms_params
146
- to = "#{params[:to].gsub(/[^\d]/, '')}@#{params[:carrier]}"
147
-
148
- sms = RecordMailer.sms_record(@documents, { :to => to }, url_options)
149
-
150
- if sms.respond_to? :deliver_now
151
- sms.deliver_now
152
- else
153
- sms.deliver
154
- end
155
-
156
- flash[:success] = I18n.t("blacklight.sms.success")
157
-
158
- respond_to do |format|
159
- format.html { redirect_to catalog_path(params['id']) }
160
- format.js { render 'sms_sent' }
161
- end and return
162
- end
163
-
164
- respond_to do |format|
165
- format.js { render :layout => false }
166
- format.html
167
- end
116
+ def action_success_redirect_path
117
+ catalog_path(params[:id])
168
118
  end
169
119
 
170
120
  ##
@@ -173,12 +123,22 @@ module Blacklight::Catalog
173
123
  def has_search_parameters?
174
124
  !params[:q].blank? or !params[:f].blank? or !params[:search_field].blank?
175
125
  end
176
-
177
- protected
126
+
127
+ protected
178
128
  #
179
129
  # non-routable methods ->
180
130
  #
181
131
 
132
+ ##
133
+ # If the params specify a view, then store it in the session. If the params
134
+ # do not specifiy the view, set the view parameter to the value stored in the
135
+ # session. This enables a user with a session to do subsequent searches and have
136
+ # them default to the last used view.
137
+ def preferred_view
138
+ session[:preferred_view] = params[:view] if params[:view]
139
+ params[:view] ||= session[:preferred_view]
140
+ end
141
+
182
142
  ##
183
143
  # Render additional response formats, as provided by the blacklight configuration
184
144
  def additional_response_formats format
@@ -265,7 +225,28 @@ module Blacklight::Catalog
265
225
 
266
226
  h
267
227
  end
268
-
228
+
229
+ # Email Action (this will render the appropriate view on GET requests and process the form and send the email on POST requests)
230
+ def email_action documents
231
+ mail = RecordMailer.email_record(documents, {:to => params[:to], :message => params[:message]}, url_options)
232
+ if mail.respond_to? :deliver_now
233
+ mail.deliver_now
234
+ else
235
+ mail.deliver
236
+ end
237
+ end
238
+
239
+ # SMS action (this will render the appropriate view on GET requests and process the form and send the email on POST requests)
240
+ def sms_action documents
241
+ to = "#{params[:to].gsub(/[^\d]/, '')}@#{params[:carrier]}"
242
+ mail = RecordMailer.sms_record(documents, { :to => to }, url_options)
243
+ if mail.respond_to? :deliver_now
244
+ mail.deliver_now
245
+ else
246
+ mail.deliver
247
+ end
248
+ end
249
+
269
250
  def validate_sms_params
270
251
  case
271
252
  when params[:to].blank?
@@ -0,0 +1,99 @@
1
+ module Blacklight
2
+ module Catalog::ComponentConfiguration
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ add_results_document_tool(:bookmark, partial: 'bookmark_control', if: :render_bookmarks_control?)
7
+
8
+ add_results_collection_tool(:sort_widget)
9
+ add_results_collection_tool(:per_page_widget)
10
+ add_results_collection_tool(:view_type_group)
11
+
12
+ add_show_tools_partial(:bookmark, partial: 'bookmark_control', if: :render_bookmarks_control?)
13
+ add_show_tools_partial(:refworks, if: :render_refworks_action?)
14
+ add_show_tools_partial(:endnote, if: :render_endnote_action? )
15
+ add_show_tools_partial(:email, callback: :email_action, validator: :validate_email_params)
16
+ add_show_tools_partial(:sms, callback: :sms_action, validator: :validate_sms_params)
17
+ add_show_tools_partial(:citation)
18
+ add_show_tools_partial(:librarian_view, if: :render_librarian_view_control?)
19
+
20
+ add_nav_action(:bookmark, partial: 'blacklight/nav/bookmark', if: :render_bookmarks_control?)
21
+ add_nav_action(:saved_searches, partial: 'blacklight/nav/saved_searches', if: :render_saved_searches?)
22
+ add_nav_action(:search_history, partial: 'blacklight/nav/search_history')
23
+ end
24
+
25
+ module ClassMethods
26
+
27
+ ##
28
+ # Add a partial to the tools for rendering a document
29
+ # @param partial [String] the name of the document partial
30
+ # @param opts [Hash]
31
+ # @option opts [Symbol,Proc] :if render this action if the method identified by the symbol or the proc evaluates to true.
32
+ # The proc will receive the action configuration and the document or documents for the action.
33
+ # @option opts [Symbol,Proc] :unless render this action unless the method identified by the symbol or the proc evaluates to true
34
+ # The proc will receive the action configuration and the document or documents for the action.
35
+ def add_show_tools_partial name, opts = {}
36
+ blacklight_config.add_show_tools_partial(name, opts)
37
+
38
+ define_method name do
39
+ @response, @documents = action_documents
40
+
41
+ if request.post? and
42
+ opts[:callback] and
43
+ (opts[:validator].blank? || self.send(opts[:validator]))
44
+
45
+ self.send(opts[:callback], @documents)
46
+
47
+ flash[:success] ||= I18n.t("blacklight.#{name}.success", default: nil)
48
+
49
+ respond_to do |format|
50
+ format.html { redirect_to action_success_redirect_path }
51
+ format.js { render "#{name}_success" }
52
+ end
53
+ else
54
+ respond_to do |format|
55
+ format.html
56
+ format.js { render :layout => false }
57
+ end
58
+ end
59
+ end unless method_defined? name
60
+ end
61
+
62
+ ##
63
+ # Add a tool to be displayed for each document in the search results.
64
+ # @param partial [String] the name of the document partial
65
+ # @param opts [Hash]
66
+ # @option opts [Symbol,Proc] :if render this action if the method identified by the symbol or the proc evaluates to true.
67
+ # The proc will receive the action configuration and the document or documents for the action.
68
+ # @option opts [Symbol,Proc] :unless render this action unless the method identified by the symbol or the proc evaluates to true
69
+ # The proc will receive the action configuration and the document or documents for the action.
70
+ def add_results_document_tool name, opts = {}
71
+ blacklight_config.add_results_document_tool(name, opts)
72
+ end
73
+
74
+ ##
75
+ # Add a tool to be displayed for the list of search results themselves.
76
+ # @param partial [String] the name of the document partial
77
+ # @param opts [Hash]
78
+ # @option opts [Symbol,Proc] :if render this action if the method identified by the symbol or the proc evaluates to true.
79
+ # The proc will receive the action configuration and the document or documents for the action.
80
+ # @option opts [Symbol,Proc] :unless render this action unless the method identified by the symbol or the proc evaluates to true
81
+ # The proc will receive the action configuration and the document or documents for the action.
82
+ def add_results_collection_tool name, opts = {}
83
+ blacklight_config.add_results_collection_tool(name, opts)
84
+ end
85
+
86
+ ##
87
+ # Add a partial to the header navbar
88
+ # @param partial [String] the name of the document partial
89
+ # @param opts [Hash]
90
+ # @option opts [Symbol,Proc] :if render this action if the method identified by the symbol or the proc evaluates to true.
91
+ # The proc will receive the action configuration and the document or documents for the action.
92
+ # @option opts [Symbol,Proc] :unless render this action unless the method identified by the symbol or the proc evaluates to true
93
+ # The proc will receive the action configuration and the document or documents for the action.
94
+ def add_nav_action name, opts = {}
95
+ blacklight_config.add_nav_action(name, opts)
96
+ end
97
+ end
98
+ end
99
+ end