blacklight 9.0.0.beta7 → 9.0.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.
- checksums.yaml +4 -4
- data/.docker/app/Dockerfile +2 -1
- data/.github/matrix.json +21 -20
- data/README.md +2 -2
- data/VERSION +1 -1
- data/app/assets/javascripts/blacklight/blacklight.esm.js +13 -7
- data/app/assets/javascripts/blacklight/blacklight.esm.js.map +1 -1
- data/app/assets/javascripts/blacklight/blacklight.js +13 -7
- data/app/assets/javascripts/blacklight/blacklight.js.map +1 -1
- data/app/components/blacklight/advanced_search_form_component.rb +2 -1
- data/app/components/blacklight/document_component.rb +10 -13
- data/app/components/blacklight/facets/filters_component.rb +2 -2
- data/app/components/blacklight/facets/suggest_component.html.erb +17 -12
- data/app/components/blacklight/facets/suggest_component.rb +2 -3
- data/app/components/blacklight/metadata_field_component.html.erb +2 -2
- data/app/components/blacklight/metadata_field_component.rb +2 -1
- data/app/components/blacklight/metadata_field_layout_component.rb +9 -4
- data/app/components/blacklight/search_bar_component.html.erb +1 -1
- data/app/controllers/concerns/blacklight/catalog.rb +3 -4
- data/app/javascript/blacklight-frontend/checkbox_submit.js +2 -2
- data/app/javascript/blacklight-frontend/facet_suggest.js +4 -1
- data/app/javascript/blacklight-frontend/modal.js +7 -4
- data/app/presenters/blacklight/document_presenter.rb +6 -5
- data/app/presenters/blacklight/facet_field_presenter.rb +10 -3
- data/app/presenters/blacklight/field_presenter.rb +4 -2
- data/app/presenters/blacklight/rendering/abstract_step.rb +7 -1
- data/app/presenters/blacklight/rendering/join.rb +9 -5
- data/app/presenters/blacklight/rendering/terminator.rb +1 -1
- data/app/services/blacklight/search_service.rb +4 -2
- data/app/views/catalog/_show_main_content.html.erb +9 -5
- data/app/views/catalog/index.html.erb +0 -1
- data/app/views/catalog/show.html.erb +2 -2
- data/config/locales/blacklight.en.yml +1 -1
- data/lib/blacklight/component.rb +2 -0
- data/lib/blacklight/configuration/facet_field.rb +2 -0
- data/lib/blacklight/configuration/view_config.rb +30 -16
- data/lib/blacklight/configuration.rb +56 -9
- data/lib/blacklight/routes/searchable.rb +1 -1
- data/lib/blacklight/search_builder.rb +160 -1
- data/lib/blacklight/search_state/pivot_filter_field.rb +1 -1
- data/lib/blacklight/solr/field_reflection_search_builder.rb +11 -0
- data/lib/blacklight/solr/repository.rb +5 -5
- data/lib/blacklight/solr/search_builder_behavior.rb +73 -7
- data/lib/blacklight/solr/single_doc_search_builder.rb +25 -0
- data/lib/generators/blacklight/templates/catalog_controller.rb +27 -5
- data/lib/generators/blacklight/templates/solr/conf/solrconfig.xml +0 -67
- data/package.json +1 -1
- data/spec/components/blacklight/document_component_spec.rb +0 -7
- data/spec/components/blacklight/facets/filters_component_spec.rb +3 -3
- data/spec/components/blacklight/facets/suggest_component_spec.rb +14 -1
- data/spec/components/blacklight/search_bar_component_spec.rb +24 -1
- data/spec/controllers/blacklight/catalog_spec.rb +1 -1
- data/spec/features/advanced_search_spec.rb +39 -20
- data/spec/features/facets_spec.rb +9 -0
- data/spec/models/blacklight/configuration_spec.rb +126 -0
- data/spec/models/blacklight/search_builder_spec.rb +11 -1
- data/spec/models/blacklight/solr/repository_spec.rb +6 -0
- data/spec/models/blacklight/solr/search_builder_behavior_spec.rb +214 -8
- data/spec/presenters/blacklight/document_presenter_spec.rb +3 -3
- data/spec/presenters/blacklight/field_presenter_spec.rb +103 -22
- data/spec/presenters/blacklight/rendering/pipeline_spec.rb +130 -14
- metadata +8 -16
- data/app/controllers/concerns/blacklight/facetable.rb +0 -34
- data/app/models/facet_search_builder.rb +0 -5
- data/app/services/blacklight/facet_search_service.rb +0 -44
- data/app/views/shared/_sitelinks_search_box.html.erb +0 -12
- data/lib/blacklight/abstract_search_builder.rb +0 -154
- data/lib/blacklight/facet_search_builder.rb +0 -18
- data/lib/blacklight/solr/facet_search_builder_behavior.rb +0 -62
- data/spec/features/sitelinks_search_box_spec.rb +0 -13
- data/spec/models/blacklight/facet_search_builder_spec.rb +0 -19
- data/spec/models/blacklight/solr/facet_search_builder_behavior_spec.rb +0 -929
|
@@ -12,20 +12,15 @@ RSpec.describe Blacklight::Rendering::Pipeline do
|
|
|
12
12
|
let(:values) { %w[a b] }
|
|
13
13
|
let(:field_config) { Blacklight::Configuration::NullField.new }
|
|
14
14
|
|
|
15
|
-
it { is_expected.to eq
|
|
16
|
-
|
|
17
|
-
context "when separator_options are in the config" do
|
|
18
|
-
let(:values) { %w[c d] }
|
|
19
|
-
let(:field_config) { Blacklight::Configuration::NullField.new(itemprop: nil, separator_options: { two_words_connector: '; ' }) }
|
|
20
|
-
|
|
21
|
-
it { is_expected.to eq "c; d" }
|
|
22
|
-
end
|
|
15
|
+
it { is_expected.to eq %w[a b] }
|
|
23
16
|
|
|
24
17
|
context "when itemprop is in the config" do
|
|
25
18
|
let(:values) { ['a'] }
|
|
26
19
|
let(:field_config) { Blacklight::Configuration::NullField.new(itemprop: 'some-prop', separator_options: nil) }
|
|
27
20
|
|
|
28
|
-
it
|
|
21
|
+
it 'renders the expected markup' do
|
|
22
|
+
expect(rendered.first).to have_css("span[@itemprop='some-prop']", text: "a")
|
|
23
|
+
end
|
|
29
24
|
end
|
|
30
25
|
|
|
31
26
|
it 'sets the operations on the instance as equal to the class variable' do
|
|
@@ -37,13 +32,134 @@ RSpec.describe Blacklight::Rendering::Pipeline do
|
|
|
37
32
|
end
|
|
38
33
|
|
|
39
34
|
context 'outside of an HTML context' do
|
|
40
|
-
|
|
35
|
+
context 'when options determines format' do
|
|
36
|
+
let(:options) { { format: 'text' } }
|
|
37
|
+
|
|
38
|
+
let(:values) { ['"blah"', "<notatag>"] }
|
|
39
|
+
let(:field_config) { Blacklight::Configuration::NullField.new itemprop: 'some-prop' }
|
|
40
|
+
|
|
41
|
+
it 'does not HTML escape values or inject HTML tags' do
|
|
42
|
+
expect(rendered).to eq ['"blah"', "<notatag>"]
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
context 'when context determines format' do
|
|
47
|
+
let(:values) { ['"blah"', "<notatag>"] }
|
|
48
|
+
let(:field_config) { Blacklight::Configuration::NullField.new itemprop: 'some-prop' }
|
|
49
|
+
let(:controller) { CatalogController.new }
|
|
50
|
+
let(:search_state) { Blacklight::SearchState.new({ format: 'text' }, controller.blacklight_config, controller) }
|
|
51
|
+
|
|
52
|
+
before { allow(context).to receive(:search_state).and_return(search_state) }
|
|
53
|
+
|
|
54
|
+
it 'does not HTML escape values or inject HTML tags' do
|
|
55
|
+
expect(rendered).to eq ['"blah"', '<notatag>']
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
context 'when link_to_facet is in the config' do
|
|
61
|
+
let(:values) { %w[book manuscript] }
|
|
62
|
+
let(:field_config) { Blacklight::Configuration::Field.new(field: 'format', key: 'format', link_to_facet: true) }
|
|
63
|
+
let(:controller) { CatalogController.new }
|
|
64
|
+
let(:search_state) { Blacklight::SearchState.new({}, controller.blacklight_config, controller) }
|
|
65
|
+
|
|
66
|
+
before do
|
|
67
|
+
allow(context).to receive(:search_state).and_return(search_state)
|
|
68
|
+
allow(context).to receive(:search_action_path) { |f| "/catalog?f[format][]=#{f['f']['format'].first}" }
|
|
69
|
+
allow(context).to receive(:link_to) { |value, link| ActiveSupport::SafeBuffer.new("<a href=#{link}>#{value}</a>") }
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it 'renders html' do
|
|
73
|
+
expect(rendered).to eq ["<a href=/catalog?f[format][]=book>book</a>", "<a href=/catalog?f[format][]=manuscript>manuscript</a>"]
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
context 'outside html context' do
|
|
77
|
+
let(:values) { %w[book manuscript] }
|
|
78
|
+
let(:field_config) { Blacklight::Configuration::Field.new(field: 'format', link_to_facet: true) }
|
|
79
|
+
let(:search_state) { Blacklight::SearchState.new({ format: 'json' }, CatalogController.blacklight_config, CatalogController.new) }
|
|
80
|
+
|
|
81
|
+
it 'does not render html' do
|
|
82
|
+
expect(rendered).to eq %w[book manuscript]
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
context 'when joining values' do
|
|
88
|
+
context 'with join in the config' do
|
|
89
|
+
let(:field_config) { Blacklight::Configuration::NullField.new(join: true) }
|
|
90
|
+
|
|
91
|
+
it 'joins the values' do
|
|
92
|
+
expect(rendered).to eq ['a and b']
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
context 'with join is in the options' do
|
|
97
|
+
let(:options) { { join: true } }
|
|
98
|
+
let(:field_config) { Blacklight::Configuration::NullField.new }
|
|
99
|
+
|
|
100
|
+
it 'joins the values' do
|
|
101
|
+
expect(rendered).to eq ['a and b']
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
context 'with separator_options in the config' do
|
|
106
|
+
let(:values) { %w[c d] }
|
|
107
|
+
let(:field_config) { Blacklight::Configuration::NullField.new(separator_options: { two_words_connector: '; ' }) }
|
|
108
|
+
|
|
109
|
+
it { is_expected.to eq ["c; d"] }
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
context 'with a single value' do
|
|
113
|
+
let(:values) { [1] }
|
|
114
|
+
let(:field_config) { Blacklight::Configuration::NullField.new(join: true) }
|
|
115
|
+
|
|
116
|
+
it 'does not run the join step' do
|
|
117
|
+
expect(rendered).to eq [1]
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
context 'with a single html value' do
|
|
122
|
+
let(:values) { ['<b>value</b>'] }
|
|
123
|
+
let(:field_config) { Blacklight::Configuration::NullField.new(join: true) }
|
|
124
|
+
|
|
125
|
+
it 'does not escape the html' do
|
|
126
|
+
expect(rendered).to eq ['<b>value</b>']
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
it 'does not mark the value as html_safe' do
|
|
130
|
+
expect(rendered.first).not_to be_html_safe
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
context 'with an array of values containing unsafe characters' do
|
|
135
|
+
let(:values) { ['<a', 'b'] }
|
|
136
|
+
let(:field_config) { Blacklight::Configuration::NullField.new(join: true) }
|
|
137
|
+
|
|
138
|
+
it 'escapes the unsafe characters' do
|
|
139
|
+
expect(rendered).to eq ["<a and b"]
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
it 'marks the joined value as html_safe' do
|
|
143
|
+
expect(rendered.first).to be_html_safe
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
context 'outside the html context' do
|
|
148
|
+
let(:values) { %w[a b <c] }
|
|
149
|
+
let(:field_config) { Blacklight::Configuration::Field.new(join: true) }
|
|
150
|
+
let(:options) { { format: 'json' } }
|
|
151
|
+
|
|
152
|
+
it 'does not run the join step' do
|
|
153
|
+
expect(rendered).to eq %w[a b <c]
|
|
154
|
+
end
|
|
41
155
|
|
|
42
|
-
|
|
43
|
-
|
|
156
|
+
it 'does not escape unsafe html characters' do
|
|
157
|
+
expect(rendered.last).to eq '<c'
|
|
158
|
+
end
|
|
44
159
|
|
|
45
|
-
|
|
46
|
-
|
|
160
|
+
it 'does not mark the values as html_safe' do
|
|
161
|
+
expect(rendered.none?(&:html_safe?)).to be true
|
|
162
|
+
end
|
|
47
163
|
end
|
|
48
164
|
end
|
|
49
165
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: blacklight
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 9.0.0
|
|
4
|
+
version: 9.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jonathan Rochkind
|
|
@@ -14,9 +14,10 @@ authors:
|
|
|
14
14
|
- Dan Funk
|
|
15
15
|
- Naomi Dushay
|
|
16
16
|
- Justin Coyne
|
|
17
|
+
autorequire:
|
|
17
18
|
bindir: exe
|
|
18
19
|
cert_chain: []
|
|
19
|
-
date:
|
|
20
|
+
date: 2025-11-25 00:00:00.000000000 Z
|
|
20
21
|
dependencies:
|
|
21
22
|
- !ruby/object:Gem::Dependency
|
|
22
23
|
name: rails
|
|
@@ -589,7 +590,6 @@ files:
|
|
|
589
590
|
- app/controllers/concerns/blacklight/bookmarks.rb
|
|
590
591
|
- app/controllers/concerns/blacklight/catalog.rb
|
|
591
592
|
- app/controllers/concerns/blacklight/controller.rb
|
|
592
|
-
- app/controllers/concerns/blacklight/facetable.rb
|
|
593
593
|
- app/controllers/concerns/blacklight/search_context.rb
|
|
594
594
|
- app/controllers/concerns/blacklight/search_history.rb
|
|
595
595
|
- app/controllers/concerns/blacklight/searchable.rb
|
|
@@ -632,7 +632,6 @@ files:
|
|
|
632
632
|
- app/models/concerns/blacklight/document/semantic_fields.rb
|
|
633
633
|
- app/models/concerns/blacklight/suggest/response.rb
|
|
634
634
|
- app/models/concerns/blacklight/user.rb
|
|
635
|
-
- app/models/facet_search_builder.rb
|
|
636
635
|
- app/models/record_mailer.rb
|
|
637
636
|
- app/models/search.rb
|
|
638
637
|
- app/models/search_builder.rb
|
|
@@ -661,7 +660,6 @@ files:
|
|
|
661
660
|
- app/presenters/blacklight/thumbnail_presenter.rb
|
|
662
661
|
- app/services/blacklight/bookmarks_search_builder.rb
|
|
663
662
|
- app/services/blacklight/document_factory.rb
|
|
664
|
-
- app/services/blacklight/facet_search_service.rb
|
|
665
663
|
- app/services/blacklight/field_retriever.rb
|
|
666
664
|
- app/services/blacklight/search_params_yaml_coder.rb
|
|
667
665
|
- app/services/blacklight/search_service.rb
|
|
@@ -738,7 +736,6 @@ files:
|
|
|
738
736
|
- app/views/shared/_flash_msg.html.erb
|
|
739
737
|
- app/views/shared/_footer.html.erb
|
|
740
738
|
- app/views/shared/_modal.html.erb
|
|
741
|
-
- app/views/shared/_sitelinks_search_box.html.erb
|
|
742
739
|
- app/views/shared/_user_util_links.html.erb
|
|
743
740
|
- blacklight.gemspec
|
|
744
741
|
- compose.yaml
|
|
@@ -762,7 +759,6 @@ files:
|
|
|
762
759
|
- db/migrate/20140320000000_add_polymorphic_type_to_bookmarks.rb
|
|
763
760
|
- lib/blacklight.rb
|
|
764
761
|
- lib/blacklight/abstract_repository.rb
|
|
765
|
-
- lib/blacklight/abstract_search_builder.rb
|
|
766
762
|
- lib/blacklight/component.rb
|
|
767
763
|
- lib/blacklight/configuration.rb
|
|
768
764
|
- lib/blacklight/configuration/context.rb
|
|
@@ -781,7 +777,6 @@ files:
|
|
|
781
777
|
- lib/blacklight/configuration/view_config.rb
|
|
782
778
|
- lib/blacklight/engine.rb
|
|
783
779
|
- lib/blacklight/exceptions.rb
|
|
784
|
-
- lib/blacklight/facet_search_builder.rb
|
|
785
780
|
- lib/blacklight/nested_open_struct_with_hash_access.rb
|
|
786
781
|
- lib/blacklight/open_struct_with_hash_access.rb
|
|
787
782
|
- lib/blacklight/parameters.rb
|
|
@@ -798,7 +793,7 @@ files:
|
|
|
798
793
|
- lib/blacklight/solr/default_filter_query_builder.rb
|
|
799
794
|
- lib/blacklight/solr/document.rb
|
|
800
795
|
- lib/blacklight/solr/facet_paginator.rb
|
|
801
|
-
- lib/blacklight/solr/
|
|
796
|
+
- lib/blacklight/solr/field_reflection_search_builder.rb
|
|
802
797
|
- lib/blacklight/solr/repository.rb
|
|
803
798
|
- lib/blacklight/solr/request.rb
|
|
804
799
|
- lib/blacklight/solr/response.rb
|
|
@@ -811,6 +806,7 @@ files:
|
|
|
811
806
|
- lib/blacklight/solr/response/response.rb
|
|
812
807
|
- lib/blacklight/solr/response/spelling.rb
|
|
813
808
|
- lib/blacklight/solr/search_builder_behavior.rb
|
|
809
|
+
- lib/blacklight/solr/single_doc_search_builder.rb
|
|
814
810
|
- lib/blacklight/version.rb
|
|
815
811
|
- lib/generators/blacklight/assets/importmap_generator.rb
|
|
816
812
|
- lib/generators/blacklight/assets/propshaft_generator.rb
|
|
@@ -911,7 +907,6 @@ files:
|
|
|
911
907
|
- spec/features/search_results_spec.rb
|
|
912
908
|
- spec/features/search_sort_spec.rb
|
|
913
909
|
- spec/features/search_spec.rb
|
|
914
|
-
- spec/features/sitelinks_search_box_spec.rb
|
|
915
910
|
- spec/features/sms_spec.rb
|
|
916
911
|
- spec/fixtures/sample_solr_documents.yml
|
|
917
912
|
- spec/helpers/blacklight/configuration_helper_behavior_spec.rb
|
|
@@ -945,13 +940,11 @@ files:
|
|
|
945
940
|
- spec/models/blacklight/document/dublin_core_spec.rb
|
|
946
941
|
- spec/models/blacklight/document_spec.rb
|
|
947
942
|
- spec/models/blacklight/facet_paginator_spec.rb
|
|
948
|
-
- spec/models/blacklight/facet_search_builder_spec.rb
|
|
949
943
|
- spec/models/blacklight/icon_spec.rb
|
|
950
944
|
- spec/models/blacklight/search_builder_spec.rb
|
|
951
945
|
- spec/models/blacklight/solr/default_filter_query_builder_spec.rb
|
|
952
946
|
- spec/models/blacklight/solr/document_spec.rb
|
|
953
947
|
- spec/models/blacklight/solr/facet_paginator_spec.rb
|
|
954
|
-
- spec/models/blacklight/solr/facet_search_builder_behavior_spec.rb
|
|
955
948
|
- spec/models/blacklight/solr/repository_spec.rb
|
|
956
949
|
- spec/models/blacklight/solr/request_spec.rb
|
|
957
950
|
- spec/models/blacklight/solr/response/facets_spec.rb
|
|
@@ -1017,6 +1010,7 @@ homepage: http://projectblacklight.org/
|
|
|
1017
1010
|
licenses:
|
|
1018
1011
|
- Apache 2.0
|
|
1019
1012
|
metadata: {}
|
|
1013
|
+
post_install_message:
|
|
1020
1014
|
rdoc_options: []
|
|
1021
1015
|
require_paths:
|
|
1022
1016
|
- lib
|
|
@@ -1031,7 +1025,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
1031
1025
|
- !ruby/object:Gem::Version
|
|
1032
1026
|
version: '0'
|
|
1033
1027
|
requirements: []
|
|
1034
|
-
rubygems_version: 3.
|
|
1028
|
+
rubygems_version: 3.5.22
|
|
1029
|
+
signing_key:
|
|
1035
1030
|
specification_version: 4
|
|
1036
1031
|
summary: Blacklight provides a discovery interface for any Solr (http://lucene.apache.org/solr)
|
|
1037
1032
|
index.
|
|
@@ -1096,7 +1091,6 @@ test_files:
|
|
|
1096
1091
|
- spec/features/search_results_spec.rb
|
|
1097
1092
|
- spec/features/search_sort_spec.rb
|
|
1098
1093
|
- spec/features/search_spec.rb
|
|
1099
|
-
- spec/features/sitelinks_search_box_spec.rb
|
|
1100
1094
|
- spec/features/sms_spec.rb
|
|
1101
1095
|
- spec/fixtures/sample_solr_documents.yml
|
|
1102
1096
|
- spec/helpers/blacklight/configuration_helper_behavior_spec.rb
|
|
@@ -1130,13 +1124,11 @@ test_files:
|
|
|
1130
1124
|
- spec/models/blacklight/document/dublin_core_spec.rb
|
|
1131
1125
|
- spec/models/blacklight/document_spec.rb
|
|
1132
1126
|
- spec/models/blacklight/facet_paginator_spec.rb
|
|
1133
|
-
- spec/models/blacklight/facet_search_builder_spec.rb
|
|
1134
1127
|
- spec/models/blacklight/icon_spec.rb
|
|
1135
1128
|
- spec/models/blacklight/search_builder_spec.rb
|
|
1136
1129
|
- spec/models/blacklight/solr/default_filter_query_builder_spec.rb
|
|
1137
1130
|
- spec/models/blacklight/solr/document_spec.rb
|
|
1138
1131
|
- spec/models/blacklight/solr/facet_paginator_spec.rb
|
|
1139
|
-
- spec/models/blacklight/solr/facet_search_builder_behavior_spec.rb
|
|
1140
1132
|
- spec/models/blacklight/solr/repository_spec.rb
|
|
1141
1133
|
- spec/models/blacklight/solr/request_spec.rb
|
|
1142
1134
|
- spec/models/blacklight/solr/response/facets_spec.rb
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# The Facetable module can be included onto classes that need to initialize a FacetSearchService.
|
|
4
|
-
# There are two dependencies you must provide on the including class. Typically these
|
|
5
|
-
# would be provided by Blacklight::Controller
|
|
6
|
-
# 1. search_state
|
|
7
|
-
# 2. blacklight_config
|
|
8
|
-
#
|
|
9
|
-
# Additionally, the including class may override the facet_search_service_context method to provide
|
|
10
|
-
# further context to the SearchService. For example you could override this to provide the
|
|
11
|
-
# currently signed in user.
|
|
12
|
-
module Blacklight::Facetable
|
|
13
|
-
extend ActiveSupport::Concern
|
|
14
|
-
|
|
15
|
-
included do
|
|
16
|
-
# Which class to use for the search service. You can subclass SearchService if you
|
|
17
|
-
# want to override any of the methods (e.g. SearchService#fetch)
|
|
18
|
-
class_attribute :facet_search_service_class
|
|
19
|
-
self.facet_search_service_class = Blacklight::FacetSearchService
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
# @return [Blacklight::FacetSearchService]
|
|
23
|
-
def facet_search_service
|
|
24
|
-
facet_search_service_class.new(config: blacklight_config, search_state: search_state, user_params: search_state.to_h, **facet_search_service_context)
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
# Override this method on the class that includes Blacklight::Facetable to provide more context to the search service if necessary.
|
|
28
|
-
# For example, if your search builder needs to be aware of the current user, override this method to return a hash including the current user.
|
|
29
|
-
# Then the search builder could use some property about the current user to construct a constraint on the search.
|
|
30
|
-
# @return [Hash] a hash of context information to pass through to the search service
|
|
31
|
-
def facet_search_service_context
|
|
32
|
-
search_service_context
|
|
33
|
-
end
|
|
34
|
-
end
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# FacetSearchService returns a facet list from the repository. This is for drawing the "more facets" modal
|
|
4
|
-
module Blacklight
|
|
5
|
-
class FacetSearchService
|
|
6
|
-
def initialize(config:, search_state:, search_builder_class: config.facet_search_builder_class, **context)
|
|
7
|
-
@blacklight_config = config
|
|
8
|
-
@search_state = search_state
|
|
9
|
-
@user_params = @search_state.params
|
|
10
|
-
@search_builder_class = search_builder_class
|
|
11
|
-
@context = context
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
# The blacklight_config + controller are accessed by the search_builder
|
|
15
|
-
attr_reader :blacklight_config, :context
|
|
16
|
-
|
|
17
|
-
def search_builder
|
|
18
|
-
search_builder_class.new(self)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def search_state_class
|
|
22
|
-
@search_state.class
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
##
|
|
26
|
-
# Get the solr response when retrieving only a single facet field
|
|
27
|
-
# @return [Blacklight::Solr::Response] the solr response
|
|
28
|
-
def facet_field_response(facet_field, extra_controller_params = {})
|
|
29
|
-
query = search_builder.with(search_state).facet(facet_field)
|
|
30
|
-
repository.search(params: query.merge(extra_controller_params))
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def facet_suggest_response(facet_field, facet_suggestion_query, extra_controller_params = {})
|
|
34
|
-
query = search_builder.with(search_state).facet(facet_field).facet_suggestion_query(facet_suggestion_query)
|
|
35
|
-
repository.search(params: query.merge(extra_controller_params))
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
private
|
|
39
|
-
|
|
40
|
-
attr_reader :search_builder_class, :search_state
|
|
41
|
-
|
|
42
|
-
delegate :repository, to: :blacklight_config
|
|
43
|
-
end
|
|
44
|
-
end
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
<script type="application/ld+json">
|
|
2
|
-
{
|
|
3
|
-
"@context": "http://schema.org",
|
|
4
|
-
"@type": "WebSite",
|
|
5
|
-
"url": "<%= root_url %>",
|
|
6
|
-
"potentialAction": {
|
|
7
|
-
"@type": "SearchAction",
|
|
8
|
-
"target": "<%= root_url %>?q={search_term_string}",
|
|
9
|
-
"query-input": "required name=search_term_string"
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
</script>
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Blacklight
|
|
4
|
-
##
|
|
5
|
-
# Blacklight's SearchBuilder converts blacklight request parameters into
|
|
6
|
-
# query parameters appropriate for search index. It does so by evaluating a
|
|
7
|
-
# chain of processing methods to populate a result hash (see {#to_hash}).
|
|
8
|
-
class AbstractSearchBuilder
|
|
9
|
-
class_attribute :default_processor_chain
|
|
10
|
-
self.default_processor_chain = []
|
|
11
|
-
|
|
12
|
-
attr_reader :processor_chain, :search_state, :blacklight_params
|
|
13
|
-
|
|
14
|
-
# @overload initialize(scope)
|
|
15
|
-
# @param [Object] scope scope the scope where the filter methods reside in.
|
|
16
|
-
# @overload initialize(processor_chain, scope)
|
|
17
|
-
# @param [List<Symbol>,TrueClass] processor_chain options a list of filter methods to run or true, to use the default methods
|
|
18
|
-
# @param [Object] scope the scope where the filter methods reside in.
|
|
19
|
-
def initialize(*options)
|
|
20
|
-
case options.size
|
|
21
|
-
when 1
|
|
22
|
-
@processor_chain = default_processor_chain.dup
|
|
23
|
-
@scope = options.first
|
|
24
|
-
when 2
|
|
25
|
-
@processor_chain, @scope = options
|
|
26
|
-
else
|
|
27
|
-
raise ArgumentError, "wrong number of arguments. (#{options.size} for 1..2)"
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
@blacklight_params = {}
|
|
31
|
-
search_state_class = @scope.try(:search_state_class) || Blacklight::SearchState
|
|
32
|
-
@search_state = search_state_class.new(@blacklight_params, @scope&.blacklight_config, @scope)
|
|
33
|
-
@additional_filters = {}
|
|
34
|
-
@merged_params = {}
|
|
35
|
-
@reverse_merged_params = {}
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
delegate :blacklight_config, to: :scope
|
|
39
|
-
|
|
40
|
-
##
|
|
41
|
-
# Set the parameters to pass through the processor chain
|
|
42
|
-
def with(blacklight_params_or_search_state = {})
|
|
43
|
-
params_will_change!
|
|
44
|
-
@search_state = blacklight_params_or_search_state.is_a?(Blacklight::SearchState) ? blacklight_params_or_search_state : @search_state.reset(blacklight_params_or_search_state)
|
|
45
|
-
@blacklight_params = @search_state.params.dup
|
|
46
|
-
self
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
# sets the facet that this query pertains to, for the purpose of facet pagination
|
|
50
|
-
def facet=(value)
|
|
51
|
-
params_will_change!
|
|
52
|
-
@facet = value
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
# @param [Object] value
|
|
56
|
-
def facet(value = nil)
|
|
57
|
-
if value
|
|
58
|
-
self.facet = value
|
|
59
|
-
return self
|
|
60
|
-
end
|
|
61
|
-
@facet
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
##
|
|
65
|
-
# Merge additional, repository-specific parameters
|
|
66
|
-
def merge(extra_params, &)
|
|
67
|
-
if extra_params
|
|
68
|
-
params_will_change!
|
|
69
|
-
@merged_params.merge!(extra_params.to_hash, &)
|
|
70
|
-
end
|
|
71
|
-
self
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
##
|
|
75
|
-
# "Reverse merge" additional, repository-specific parameters
|
|
76
|
-
def reverse_merge(extra_params, &)
|
|
77
|
-
if extra_params
|
|
78
|
-
params_will_change!
|
|
79
|
-
@reverse_merged_params.reverse_merge!(extra_params.to_hash, &)
|
|
80
|
-
end
|
|
81
|
-
self
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
delegate :[], :key?, to: :to_hash
|
|
85
|
-
|
|
86
|
-
# a solr query method
|
|
87
|
-
# @return [Blacklight::Solr::Response] the solr response object
|
|
88
|
-
def to_hash
|
|
89
|
-
return @params unless params_need_update?
|
|
90
|
-
|
|
91
|
-
@params = processed_parameters
|
|
92
|
-
.reverse_merge(@reverse_merged_params)
|
|
93
|
-
.merge(@merged_params)
|
|
94
|
-
.tap { clear_changes }
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
alias query to_hash
|
|
98
|
-
alias to_h to_hash
|
|
99
|
-
|
|
100
|
-
delegate :search_field, to: :search_state
|
|
101
|
-
|
|
102
|
-
private
|
|
103
|
-
|
|
104
|
-
attr_reader :scope
|
|
105
|
-
|
|
106
|
-
def should_add_field_to_request? _field_name, field
|
|
107
|
-
field.include_in_request || (field.include_in_request.nil? && blacklight_config.add_field_configuration_to_solr_request)
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
def request
|
|
111
|
-
Blacklight::Solr::Request.new
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
# The CatalogController #index and #facet actions use this.
|
|
115
|
-
# Solr parameters can come from a number of places. From lowest
|
|
116
|
-
# precedence to highest:
|
|
117
|
-
# 1. General defaults in blacklight config (are trumped by)
|
|
118
|
-
# 2. defaults for the particular search field identified by params[:search_field] (are trumped by)
|
|
119
|
-
# 3. certain parameters directly on input HTTP query params
|
|
120
|
-
# * not just any parameter is grabbed willy nilly, only certain ones are allowed by HTTP input)
|
|
121
|
-
# * for legacy reasons, qt in http query does not over-ride qt in search field definition default.
|
|
122
|
-
# 4. extra parameters passed in as argument.
|
|
123
|
-
#
|
|
124
|
-
# spellcheck.q will be supplied with the [:q] value unless specifically
|
|
125
|
-
# specified otherwise.
|
|
126
|
-
#
|
|
127
|
-
# Incoming parameter :f is mapped to :fq solr parameter.
|
|
128
|
-
#
|
|
129
|
-
# @return a params hash for searching solr.
|
|
130
|
-
def processed_parameters
|
|
131
|
-
request.tap do |request_parameters|
|
|
132
|
-
processor_chain.each do |method_name|
|
|
133
|
-
send(method_name, request_parameters)
|
|
134
|
-
end
|
|
135
|
-
end
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
def params_will_change!
|
|
139
|
-
@dirty = true
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
def params_changed?
|
|
143
|
-
!!@dirty
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
def clear_changes
|
|
147
|
-
@dirty = false
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
def params_need_update?
|
|
151
|
-
params_changed? || @params.nil?
|
|
152
|
-
end
|
|
153
|
-
end
|
|
154
|
-
end
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Blacklight
|
|
4
|
-
class FacetSearchBuilder < AbstractSearchBuilder
|
|
5
|
-
def facet_suggestion_query=(value)
|
|
6
|
-
params_will_change!
|
|
7
|
-
@facet_suggestion_query = value
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def facet_suggestion_query(value = nil)
|
|
11
|
-
if value
|
|
12
|
-
self.facet_suggestion_query = value
|
|
13
|
-
return self
|
|
14
|
-
end
|
|
15
|
-
@facet_suggestion_query
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Blacklight::Solr
|
|
4
|
-
module FacetSearchBuilderBehavior
|
|
5
|
-
extend ActiveSupport::Concern
|
|
6
|
-
|
|
7
|
-
included do
|
|
8
|
-
include Blacklight::Solr::SearchBuilderBehavior
|
|
9
|
-
self.default_processor_chain = [:default_solr_parameters,
|
|
10
|
-
:add_search_field_default_parameters,
|
|
11
|
-
:add_query_to_solr,
|
|
12
|
-
:add_facet_fq_to_solr,
|
|
13
|
-
:add_facetting_to_solr,
|
|
14
|
-
:add_solr_fields_to_query,
|
|
15
|
-
:add_additional_filters,
|
|
16
|
-
:add_facet_paging_to_solr,
|
|
17
|
-
:add_facet_suggestion_parameters]
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def add_facet_paging_to_solr(solr_params)
|
|
21
|
-
return if facet.blank?
|
|
22
|
-
|
|
23
|
-
facet_config = blacklight_config.facet_fields[facet]
|
|
24
|
-
|
|
25
|
-
solr_params[:rows] = 0
|
|
26
|
-
|
|
27
|
-
limit = if solr_params["facet.limit"]
|
|
28
|
-
solr_params["facet.limit"].to_i
|
|
29
|
-
else
|
|
30
|
-
facet_config.fetch(:more_limit, blacklight_config.default_more_limit)
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
page = search_state.facet_page
|
|
34
|
-
sort = search_state.facet_sort
|
|
35
|
-
prefix = search_state.facet_prefix
|
|
36
|
-
offset = (page - 1) * limit
|
|
37
|
-
|
|
38
|
-
if facet_config.json
|
|
39
|
-
add_solr_facet_json_params(solr_parameters, facet, facet_config, limit: limit + 1, offset: offset, sort: sort, prefix: prefix)
|
|
40
|
-
return
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
# Now override with our specific things for fetching facet values
|
|
44
|
-
facet_ex = facet_config.respond_to?(:ex) ? facet_config.ex : nil
|
|
45
|
-
solr_params[:'facet.field'] = with_ex_local_param(facet_ex, facet_config.field)
|
|
46
|
-
|
|
47
|
-
# Need to set as f.facet_field.facet.* to make sure we
|
|
48
|
-
# override any field-specific default in the solr request handler.
|
|
49
|
-
solr_params[:"f.#{facet_config.field}.facet.limit"] = limit + 1
|
|
50
|
-
solr_params[:"f.#{facet_config.field}.facet.offset"] = offset
|
|
51
|
-
solr_params[:"f.#{facet_config.field}.facet.sort"] = sort if sort
|
|
52
|
-
solr_params[:"f.#{facet_config.field}.facet.prefix"] = prefix if prefix
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def add_facet_suggestion_parameters(solr_params)
|
|
56
|
-
return if facet.blank? || facet_suggestion_query.blank?
|
|
57
|
-
|
|
58
|
-
solr_params[:'facet.contains'] = facet_suggestion_query[0..50]
|
|
59
|
-
solr_params[:'facet.contains.ignoreCase'] = true
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
end
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
RSpec.describe 'Sitelinks search box' do
|
|
4
|
-
it 'is home page' do
|
|
5
|
-
visit root_path
|
|
6
|
-
expect(page).to have_css 'script[type="application/ld+json"]', visible: :hidden
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
it 'on search page' do
|
|
10
|
-
visit search_catalog_path q: 'book'
|
|
11
|
-
expect(page).to have_no_css 'script[type="application/ld+json"]', visible: :hidden
|
|
12
|
-
end
|
|
13
|
-
end
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
RSpec.describe Blacklight::FacetSearchBuilder, :api do
|
|
4
|
-
subject(:builder) { described_class.new processor_chain, scope }
|
|
5
|
-
|
|
6
|
-
let(:processor_chain) { [] }
|
|
7
|
-
let(:blacklight_config) { Blacklight::Configuration.new }
|
|
8
|
-
let(:scope) { double blacklight_config: blacklight_config, search_state_class: nil }
|
|
9
|
-
|
|
10
|
-
describe "#facet_suggestion_query" do
|
|
11
|
-
it "is nil if no value is set" do
|
|
12
|
-
expect(subject.facet_suggestion_query).to be_nil
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
it "sets facet_suggestion_query value" do
|
|
16
|
-
expect(subject.facet_suggestion_query('antel').facet_suggestion_query).to eq 'antel'
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|