-
Notifications
You must be signed in to change notification settings - Fork 64
/
blacklight_configuration.rb
409 lines (332 loc) · 14.4 KB
/
blacklight_configuration.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
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
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
# frozen_string_literal: true
require 'blacklight/open_struct_with_hash_access'
module Spotlight
##
# Exhibit-specific blacklight configuration model
# rubocop:disable Metrics/ClassLength
class BlacklightConfiguration < ActiveRecord::Base
has_paper_trail
belongs_to :exhibit, touch: true, optional: true
serialize :facet_fields, Hash
serialize :index_fields, Hash
serialize :search_fields, Hash
serialize :sort_fields, Hash
serialize :default_solr_params, Hash
serialize :show, Hash
serialize :index, Hash
serialize :per_page, Array
serialize :document_index_view_types, Array
include Spotlight::BlacklightConfigurationDefaults
delegate :document_model, to: :default_blacklight_config
# get rid of empty values
before_validation do |model|
model.index_fields&.each do |_k, v|
v[:enabled] ||= v.any? { |_k1, v1| !v1.blank? }
default_blacklight_config.view.keys.each do |view|
v[view] &&= value_to_boolean(v[view])
end
v[:show] &&= value_to_boolean(v[:show])
v.reject! { |_k, v1| v1.blank? && v1 != false }
end
model.facet_fields&.each do |_k, v|
v[:show] &&= value_to_boolean(v[:show])
v[:show] ||= true if v[:show].nil?
v.reject! { |_k, v1| v1.blank? && v1 != false }
end
model.search_fields&.each do |k, v|
v[:enabled] &&= value_to_boolean(v[:enabled])
v[:enabled] ||= true if v[:enabled].nil?
v[:label] = default_blacklight_config.search_fields[k][:label] if default_blacklight_config.search_fields[k] && !v[:label].present?
v.reject! { |_k, v1| v1.blank? && v1 != false }
end
model.sort_fields&.each do |k, v|
v[:enabled] &&= value_to_boolean(v[:enabled])
v[:enabled] ||= true if v[:enabled].nil?
v[:label] = default_blacklight_config.sort_fields[k][:label] if default_blacklight_config.sort_fields[k] && !v[:label].present?
v.reject! { |_k, v1| v1.blank? && v1 != false }
end
model.per_page&.reject!(&:blank?)
model.document_index_view_types&.reject!(&:blank?)
end
##
# Serialize this configuration to a Blacklight::Configuration object
# appropriate to the current view. If a value isn't set in this record,
# it will use the configuration set upstream (in default_blacklight_config)
# @param [String] view the configuration may be different depending on the index view selected
# rubocop:disable Metrics/MethodLength, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity, Metrics/AbcSize
def blacklight_config
@blacklight_config ||= begin
# Create a new config based on the defaults
config = default_blacklight_config.inheritable_copy(self.class)
config.current_exhibit = exhibit
config.document_presenter_class = lambda do |context|
if context.action_name == 'index'
config.index.document_presenter_class
else
config.show.document_presenter_class
end
end
config.show.merge! show unless show.blank?
config.index.merge! index unless index.blank?
config.index.respond_to[:iiif_json] = true
config.index.thumbnail_field ||= Spotlight::Engine.config.thumbnail_field
config.add_results_collection_tool 'curator_actions', if: :render_curator_actions?
unless config.curator_actions
config.curator_actions ||= Blacklight::NestedOpenStructWithHashAccess.new(Blacklight::Configuration::ToolConfig)
config.curator_actions.save_search!
config.curator_actions.bulk_actions!
end
unless config.bulk_actions
config.bulk_actions ||= Blacklight::NestedOpenStructWithHashAccess.new(Blacklight::Configuration::ToolConfig)
config.bulk_actions.change_visibility!
config.bulk_actions.add_tags!
config.bulk_actions.remove_tags!
end
config.default_solr_params = config.default_solr_params.merge(default_solr_params)
config.default_per_page = default_per_page if default_per_page
config.view.embed!
config.view.embed.partials ||= ['openseadragon']
config.view.embed.if = false
config.view.embed.locals ||= { osd_container_class: '' }
# Add any custom fields
config.index_fields.merge! custom_index_fields(config)
config.index_fields.reject! { |_k, v| v.if == false }
# Update with customizations
config.index_fields.each do |k, v|
v.original = v.dup
if index_fields[k]
v.merge! index_fields[k].symbolize_keys
elsif v.custom_field
set_custom_field_defaults(v)
else
set_index_field_defaults(v)
end
v.immutable = Blacklight::OpenStructWithHashAccess.new(v.immutable)
v.merge! v.immutable.to_h.symbolize_keys
v.if = :field_enabled? unless v.if == false
v.normalize! config
v.validate!
end
config.show_fields.reject! { |_k, v| v.if == false }
config.show_fields.reject { |k, _v| config.index_fields[k] }.each do |k, v|
v.original = v.dup
config.index_fields[k] = v
if index_fields[k]
v.merge! index_fields[k].symbolize_keys
else
set_show_field_defaults(v)
end
v.immutable = Blacklight::OpenStructWithHashAccess.new(v.immutable)
v.merge! v.immutable.to_h.symbolize_keys
v.if = :field_enabled? unless v.if == false
v.normalize! config
v.validate!
end
##
# Sort after the show fields have also been added
config.index_fields = Hash[config.index_fields.sort_by { |k, _v| field_weight(index_fields, k) }]
config.show_fields = config.index_fields
config.search_fields.merge! custom_search_fields(config)
unless search_fields.blank?
config.search_fields = Hash[config.search_fields.sort_by { |k, _v| field_weight(search_fields, k) }]
config.search_fields.each do |k, v|
v.original = v.dup
v.if = :field_enabled? unless v.if == false
next if search_fields[k].blank?
v.merge! search_fields[k].symbolize_keys
v.normalize! config
v.validate!
end
end
unless sort_fields.blank?
config.sort_fields = Hash[config.sort_fields.sort_by { |k, _v| field_weight(sort_fields, k) }]
config.sort_fields.each do |k, v|
v.original = v.dup
v.if = :field_enabled? unless v.if == false
next if sort_fields[k].blank?
v.merge! sort_fields[k].symbolize_keys
v.normalize! config
v.validate!
end
end
config.facet_fields.merge! custom_facet_fields
unless facet_fields.blank?
config.facet_fields = Hash[config.facet_fields.sort_by { |k, _v| field_weight(facet_fields, k) }]
config.facet_fields.each do |k, v|
v.original = v.dup unless v.custom_field
next if facet_fields[k].blank?
v.merge! facet_fields[k].symbolize_keys
v.enabled = v.show
v.if = :field_enabled? unless v.if == false
v.normalize! config
v.validate!
end
end
config.per_page = (config.per_page & per_page) unless per_page.blank?
unless document_index_view_types.blank?
config.view.each do |k, v|
v.original = v.dup
v.key = k
v.if = :enabled_in_spotlight_view_type_configuration? unless v.if == false
end
end
if config.search_fields.blank?
config.navbar.partials[:saved_searches].if = false if config.navbar.partials.key? :saved_searches
config.navbar.partials[:search_history].if = false if config.navbar.partials.key? :search_history
end
config
end
end
# rubocop:enable Metrics/MethodLength, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
def custom_index_fields(blacklight_config)
Hash[exhibit.custom_fields.reject(&:new_record?).map do |custom_field|
original_config = blacklight_config.index_fields[custom_field.field] || {}
field = Blacklight::Configuration::IndexField.new original_config.merge(
custom_field.configuration.merge(
key: custom_field.field, field: custom_field.solr_field, custom_field: true
)
)
[custom_field.field, field]
end]
end
def custom_facet_fields
Hash[exhibit.custom_fields.facetable.reject(&:new_record?).map do |x|
field = Blacklight::Configuration::FacetField.new x.configuration.merge(
key: x.field, field: x.solr_field, show: false, custom_field: true
)
field.if = :field_enabled?
field.enabled = false
field.limit = true
[x.field, field]
end]
end
def custom_search_fields(blacklight_config)
Hash[exhibit.custom_search_fields.reject(&:new_record?).map do |custom_field|
original_config = blacklight_config.search_fields[custom_field.field] || {}
field = Blacklight::Configuration::SearchField.new original_config.merge(
custom_field.configuration.merge(
key: custom_field.slug, solr_parameters: { qf: custom_field.field }, custom_field: true
)
)
[custom_field.slug, field]
end]
end
##
# Get the "upstream" blacklight configuration to use
def default_blacklight_config
@default_blacklight_config ||= begin
config = Spotlight::Engine.blacklight_config.deep_copy
add_exhibit_specific_fields(config)
config
end
end
# Parse params checkbox arrays into simple arrays.
# A group of checkboxes on a form returns values like this:
# {"list"=>"1", "gallery"=>"1", "map"=>"0"}
# where, "list" and "gallery" are selected and "map" is not. This function
# digests that hash into a list of selected values. e.g.:
# ["list", "gallery"]
def document_index_view_types=(hash_or_array)
if hash_or_array.is_a? Hash
super(hash_or_array.select { |_, checked| checked == '1' }.keys)
else
super(hash_or_array)
end
end
# @return [OpenStructWithHashAccess] keys are view types; value is 1 if enabled
# A group of checkboxes on a form needs values like this:
# {"list"=>"1", "gallery"=>"1", "map"=>"0"}
# where, "list" and "gallery" are selected and "map" is not. This function
# takes ["list", "gallery"] and turns it into the above.
def document_index_view_types_selected_hash
selected_view_types = document_index_view_types
avail_view_types = default_blacklight_config.view.to_h.reject { |_k, v| v.if == false }.keys
Blacklight::OpenStructWithHashAccess.new.tap do |s|
avail_view_types.each do |k|
s[k] = selected_view_types.include?(k.to_s)
end
end
end
protected
def add_exhibit_specific_fields(config)
add_exhibit_tags_fields(config)
add_uploaded_resource_fields(config)
add_autocomplete_field(config)
end
def add_exhibit_tags_fields(config)
# rubocop:disable Style/GuardClause
unless config.show_fields.include? :exhibit_tags
config.add_show_field :exhibit_tags, field: config.document_model.solr_field_for_tagger(exhibit),
link_to_facet: true,
separator_options: { words_connector: nil, two_words_connector: nil, last_word_connector: nil }
end
unless config.facet_fields.include? :exhibit_tags
config.add_facet_field :exhibit_tags, field: config.document_model.solr_field_for_tagger(exhibit), limit: true
end
# rubocop:enable Style/GuardClause
end
def add_uploaded_resource_fields(config)
exhibit.uploaded_resource_fields.each do |f|
add_uploaded_resource_field(config, f)
end
end
def add_uploaded_resource_field(config, f)
key = Array(f.solr_field || f.field_name).first.to_s
return if config.index_fields.any? { |_k, v| v.field == key }
options = f.blacklight_options || {}
options[:label] = f.label if f.label
config.add_index_field key, options
end
def add_autocomplete_field(config)
return unless Spotlight::Engine.config.autocomplete_search_field && !config.search_fields[Spotlight::Engine.config.autocomplete_search_field]
config.add_search_field(Spotlight::Engine.config.autocomplete_search_field) do |field|
field.include_in_simple_select = false
field.solr_parameters = Spotlight::Engine.config.default_autocomplete_params.deep_dup
field.solr_parameters[:fl] ||= default_autocomplete_field_list(config)
end
end
def default_autocomplete_field_list(config)
[
config.document_model.unique_key,
config.view_config(:show).title_field,
config.index.thumbnail_field || Spotlight::Engine.config.thumbnail_field,
Spotlight::Engine.config.iiif_manifest_field
].flatten.join(' ')
end
# rubocop:disable Naming/AccessorMethodName
def set_index_field_defaults(field)
return unless index_fields.blank?
views = default_blacklight_config.view.keys | %i[show enabled]
field.merge!((views - field.keys).map { |v| [v, !title_only_by_default?(v)] }.to_h)
end
# Check to see whether config.view.foobar.title_only_by_default is available
def title_only_by_default?(view)
return false if %i[show enabled].include?(view)
title_only = default_blacklight_config.view.send(:[], view)&.title_only_by_default
title_only.nil? ? false : title_only
end
def set_show_field_defaults(field)
return unless index_fields.blank?
views = default_blacklight_config.view.keys
field.merge! Hash[views.map { |v| [v, false] }]
field.enabled = true
field.show = true
end
def set_custom_field_defaults(field)
field.show = true if field.show.nil?
field.enabled = true if field.enabled.nil?
end
# rubocop:enable Naming/AccessorMethodName
# @return [Integer] the weight (sort order) for this field
def field_weight(fields, index)
if fields[index] && fields[index][:weight]
fields[index][:weight].to_i
else
100 + (fields.keys.index(index) || fields.keys.length)
end
end
def value_to_boolean(v)
ActiveModel::Type::Boolean.new.cast v
end
end
end