blacklight 7.8.1 → 7.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/app/assets/stylesheets/blacklight/_facets.scss +20 -4
  4. data/app/components/blacklight/facet_item_pivot_component.rb +84 -0
  5. data/app/helpers/blacklight/facets_helper_behavior.rb +12 -5
  6. data/app/helpers/blacklight/render_constraints_helper_behavior.rb +2 -2
  7. data/app/models/blacklight/icon.rb +5 -9
  8. data/app/models/concerns/blacklight/document.rb +0 -10
  9. data/app/presenters/blacklight/facet_item_presenter.rb +1 -1
  10. data/app/views/catalog/_constraints.html.erb +1 -1
  11. data/app/views/catalog/_facet_pivot.html.erb +3 -18
  12. data/config/locales/blacklight.ar.yml +3 -0
  13. data/config/locales/blacklight.de.yml +3 -0
  14. data/config/locales/blacklight.en.yml +3 -0
  15. data/config/locales/blacklight.es.yml +3 -0
  16. data/config/locales/blacklight.fr.yml +3 -0
  17. data/config/locales/blacklight.hu.yml +3 -0
  18. data/config/locales/blacklight.it.yml +3 -0
  19. data/config/locales/blacklight.nl.yml +3 -0
  20. data/config/locales/blacklight.pt-BR.yml +3 -0
  21. data/config/locales/blacklight.sq.yml +3 -0
  22. data/config/locales/blacklight.zh.yml +3 -0
  23. data/lib/blacklight/configuration.rb +35 -8
  24. data/lib/generators/blacklight/templates/catalog_controller.rb +1 -1
  25. data/package-lock.json +4 -4
  26. data/package.json +1 -1
  27. data/spec/components/blacklight/facet_item_pivot_component_spec.rb +66 -0
  28. data/spec/features/facets_spec.rb +20 -0
  29. data/spec/models/blacklight/configuration_spec.rb +4 -0
  30. data/spec/models/blacklight/icon_spec.rb +5 -13
  31. data/spec/spec_helper.rb +1 -0
  32. metadata +5 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 797fccb08c32206cbf11ab04efa5b980456a8a1ff2f949940ce68b9b29843720
4
- data.tar.gz: 26608839399a44a7f33f4313337a35c5a064578daa0819cc845a601c9d058d3c
3
+ metadata.gz: bd2196992d71cdb76b3080eb944caa30d0534fd0b8954f641e50ba6287e00c75
4
+ data.tar.gz: 3d273772786614bae0a216a1be97b038d90f24c1ddea1aee25a3a993613bed97
5
5
  SHA512:
6
- metadata.gz: 2066cfd8c17650d43b39707f8d73c39745307eff3795875833f0a1e0c794ba92a8aae1aa061db59e5a39154332e0e5addcb3a4d4463894ccc641eee57ed40b7e
7
- data.tar.gz: 3403d40968957aadb62eba71caed870704c23bbebf93f98910bba9931ca136b80d79ba411cb1852a2a48bf227e3456fd1d91fc8ecd01b7b8aad852dbb3f4ab8e
6
+ metadata.gz: 57ea5cb5460c6eff4a4554f73c8da22552984a9860ccb116f251d8f799d057b9b864e15b722319548c390df4fa686a9f46a96be5972b56eef46d9271e3e37368
7
+ data.tar.gz: b364146ff5cec3708b246b917bf09cd11000e92e6e6d7103b363479c342091d1da759bc952718788476b83abd4b32c95365a52206337118ac8782f257e59376f
data/VERSION CHANGED
@@ -1 +1 @@
1
- 7.8.1
1
+ 7.9.0
@@ -150,10 +150,26 @@
150
150
 
151
151
  .pivot-facet {
152
152
  @extend .list-unstyled;
153
+ @extend .py-1;
154
+ @extend .px-4;
155
+ }
156
+
157
+ .facet-leaf-node {
158
+ margin-left: 1rem;
159
+ padding-right: 1rem;
160
+ margin-top: -1.5rem;
161
+ }
153
162
 
154
- ul, .pivot-facet {
155
- @extend .list-unstyled;
156
- @extend .py-1;
157
- @extend .px-3;
163
+ .facet-toggle-handle {
164
+ margin: 0;
165
+ margin-left: -5px;
166
+ padding: 0;
167
+
168
+ &.collapsed {
169
+ .show { display: block; }
170
+ .hide { display: none; }
158
171
  }
172
+
173
+ .show { display: none; }
174
+ .hide { display: block; }
159
175
  }
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Blacklight
4
+ # Render facet items and any subtree
5
+ class FacetItemPivotComponent < ::ViewComponent::Base
6
+ # Somewhat arbitrary number; the only important thing is that
7
+ # it is bigger than the number of leaf nodes in any collapsing
8
+ # pivot facet on the page.
9
+ ID_COUNTER_MAX = 2**20 - 1
10
+
11
+ # Mint a (sufficiently) unique identifier, so we can associate
12
+ # the expand/collapse control with labels
13
+ def self.mint_id
14
+ @id_counter = ((@id_counter || 0) + 1) % ID_COUNTER_MAX
15
+
16
+ # We convert the ID to hex for markup compactness
17
+ @id_counter.to_s(16)
18
+ end
19
+
20
+ with_collection_parameter :facet_item
21
+
22
+ def initialize(facet_item:, wrapping_element: 'li', suppress_link: false, collapsing: nil)
23
+ @facet_item = facet_item
24
+ @wrapping_element = wrapping_element
25
+ @suppress_link = suppress_link
26
+ @collapsing = collapsing.nil? ? facet_item.facet_config.collapsing : collapsing
27
+ @icons = { show: '⊞', hide: '⊟' }.merge(facet_item.facet_config.icons || {})
28
+ end
29
+
30
+ def call
31
+ facet = Blacklight::FacetItemComponent.new(facet_item: @facet_item, wrapping_element: nil, suppress_link: @suppress_link)
32
+
33
+ id = "h-#{self.class.mint_id}" if @collapsing && has_items?
34
+
35
+ content_tag @wrapping_element, role: 'treeitem' do
36
+ concat facet_toggle_button(id) if has_items? && @collapsing
37
+ concat content_tag('span', render_component(facet), class: "facet-values #{'facet-leaf-node' if has_items? && @collapsing}", id: id && "#{id}_label")
38
+
39
+ if has_items?
40
+ concat(content_tag('ul', class: "pivot-facet list-unstyled #{'collapse' if @collapsing}", id: id, role: 'group') do
41
+ render_component(
42
+ self.class.with_collection(
43
+ @facet_item.items.map { |i| facet_item_presenter(i) }
44
+ )
45
+ )
46
+ end)
47
+ end
48
+ end
49
+ end
50
+
51
+ private
52
+
53
+ def has_items?
54
+ @facet_item.items.present?
55
+ end
56
+
57
+ def facet_toggle_button(id)
58
+ content_tag 'button', class: 'btn facet-toggle-handle collapsed',
59
+ data: { toggle: 'collapse', target: "##{id}" },
60
+ aria: { expanded: false, controls: id, describedby: "#{id}_label" } do
61
+ concat toggle_icon(:show)
62
+ concat toggle_icon(:hide)
63
+ end
64
+ end
65
+
66
+ def toggle_icon(type)
67
+ content_tag 'span', class: type do
68
+ concat @icons[type]
69
+ concat content_tag('span', t(type, scope: 'blacklight.search.facets.pivot'), class: 'sr-only')
70
+ end
71
+ end
72
+
73
+ # This is a little convoluted in Blacklight 7 in order to maintain backwards-compat
74
+ # with overrides of deprecated helpers. In 8.x, we can just call Component#render_in
75
+ # and call it a day
76
+ def render_component(component)
77
+ @view_context.render(component)
78
+ end
79
+
80
+ def facet_item_presenter(facet_item)
81
+ Blacklight::FacetItemPresenter.new(facet_item, @facet_item.facet_config, @view_context, @facet_item.facet_field, @facet_item.search_state)
82
+ end
83
+ end
84
+ end
@@ -81,7 +81,11 @@ module Blacklight::FacetsHelperBehavior
81
81
  return unless should_render_facet?(display_facet, field_config)
82
82
  end
83
83
  options = options.dup
84
- options[:partial] ||= facet_partial_name(display_facet)
84
+
85
+ Deprecation.silence(Blacklight::FacetsHelperBehavior) do
86
+ options[:partial] ||= facet_partial_name(display_facet)
87
+ end
88
+
85
89
  options[:layout] ||= "facet_layout" unless options.key?(:layout)
86
90
  options[:locals] ||= {}
87
91
  options[:locals][:field_name] ||= display_facet.name
@@ -97,13 +101,12 @@ module Blacklight::FacetsHelperBehavior
97
101
  # to filter undesireable facet items so they don't appear in the UI
98
102
  def render_facet_limit_list(paginator, facet_field, wrapping_element = :li)
99
103
  facet_config ||= facet_configuration_for_field(facet_field)
100
- component = facet_config.fetch(:item_component, Blacklight::FacetItemComponent)
101
104
 
102
105
  collection = paginator.items.map do |item|
103
106
  facet_item_presenter(facet_config, item, facet_field)
104
107
  end
105
108
 
106
- render(component.with_collection(collection, wrapping_element: wrapping_element))
109
+ render(facet_item_component_class(facet_config).with_collection(collection, wrapping_element: wrapping_element))
107
110
  end
108
111
  deprecation_deprecate :render_facet_limit_list
109
112
 
@@ -288,8 +291,12 @@ module Blacklight::FacetsHelperBehavior
288
291
  end
289
292
 
290
293
  def facet_item_component(facet_config, facet_item, facet_field, **args)
291
- component = facet_config.fetch(:item_component, Blacklight::FacetItemComponent)
292
- component.new(facet_item: facet_item_presenter(facet_config, facet_item, facet_field), **args).with_view_context(self)
294
+ facet_item_component_class(facet_config).new(facet_item: facet_item_presenter(facet_config, facet_item, facet_field), **args).with_view_context(self)
295
+ end
296
+
297
+ def facet_item_component_class(facet_config)
298
+ default_component = facet_config.pivot ? Blacklight::FacetItemPivotComponent : Blacklight::FacetItemComponent
299
+ facet_config.fetch(:item_component, default_component)
293
300
  end
294
301
 
295
302
  # We can't use .deprecation_deprecate here, because the new components need to
@@ -18,7 +18,7 @@ module Blacklight::RenderConstraintsHelperBehavior
18
18
  search_state = convert_to_search_state(params_or_search_state)
19
19
  search_state.has_constraints?
20
20
  end
21
- deprecation_deprecate :query_has_constraints?
21
+ deprecation_deprecate query_has_constraints?: 'use search_state#has_constraints?'
22
22
 
23
23
  ##
24
24
  # Render the actual constraints, not including header or footer
@@ -50,7 +50,7 @@ module Blacklight::RenderConstraintsHelperBehavior
50
50
  return "".html_safe if search_state.query_param.blank?
51
51
 
52
52
  Deprecation.silence(Blacklight::RenderConstraintsHelperBehavior) do
53
- render_constraint_element(constraint_query_label(search_state),
53
+ render_constraint_element(constraint_query_label(search_state.params),
54
54
  search_state.query_param,
55
55
  classes: ["query"],
56
56
  remove: remove_constraint_url(search_state))
@@ -26,17 +26,12 @@ module Blacklight
26
26
  def svg
27
27
  svg = ng_xml.at_xpath('svg')
28
28
  svg['role'] = role
29
- svg['aria-labelledby'] = unique_id if label
30
- svg.add_child("<title id='#{unique_id}'>#{icon_label}</title>") if label
29
+ svg.prepend_child("<title>#{icon_label}</title>") if label
31
30
  ng_xml.to_xml
32
31
  end
33
32
 
34
33
  def icon_label
35
- I18n.translate("blacklight.icon.#{icon_name_context}", default: "#{icon_name} icon")
36
- end
37
-
38
- def unique_id
39
- @unique_id ||= "bl-icon-#{icon_name_context}-#{SecureRandom.hex(8)}"
34
+ I18n.translate("blacklight.icon.#{icon_name_context}", default: icon_name.to_s.titleize)
40
35
  end
41
36
 
42
37
  ##
@@ -44,7 +39,8 @@ module Blacklight
44
39
  def options
45
40
  {
46
41
  class: classes,
47
- "aria-hidden": (true if aria_hidden)
42
+ "aria-hidden": (true if aria_hidden),
43
+ "aria-label": (icon_label if label)
48
44
  }
49
45
  end
50
46
 
@@ -79,7 +75,7 @@ module Blacklight
79
75
  end
80
76
 
81
77
  def classes
82
- " blacklight-icons #{@classes} ".strip
78
+ " blacklight-icons blacklight-icon-#{icon_name} #{@classes} ".strip
83
79
  end
84
80
  end
85
81
  end
@@ -16,16 +16,6 @@ require 'globalid'
16
16
  # transformation formats.
17
17
  #
18
18
  module Blacklight::Document
19
- autoload :ActiveModelShim, 'blacklight/document/active_model_shim'
20
- autoload :SchemaOrg, 'blacklight/document/schema_org'
21
- autoload :CacheKey, 'blacklight/document/cache_key'
22
- autoload :DublinCore, 'blacklight/document/dublin_core'
23
- autoload :Email, 'blacklight/document/email'
24
- autoload :SemanticFields, 'blacklight/document/semantic_fields'
25
- autoload :Sms, 'blacklight/document/sms'
26
- autoload :Extensions, 'blacklight/document/extensions'
27
- autoload :Export, 'blacklight/document/export'
28
-
29
19
  extend ActiveSupport::Concern
30
20
  include Blacklight::Document::SchemaOrg
31
21
  include Blacklight::Document::SemanticFields
@@ -4,7 +4,7 @@ module Blacklight
4
4
  class FacetItemPresenter
5
5
  attr_reader :facet_item, :facet_config, :view_context, :search_state, :facet_field
6
6
 
7
- delegate :hits, to: :facet_item
7
+ delegate :hits, :items, to: :facet_item
8
8
 
9
9
  def initialize(facet_item, facet_config, view_context, facet_field, search_state = view_context.search_state)
10
10
  @facet_item = facet_item
@@ -1,4 +1,4 @@
1
- <% if query_has_constraints? %>
1
+ <% if Deprecation.silence(Blacklight::RenderConstraintsHelperBehavior) { query_has_constraints? } %>
2
2
  <div id="appliedParams" class="clearfix constraints-container">
3
3
  <h2 class="sr-only"><%= t('blacklight.search.search_constraints_header') %></h2>
4
4
 
@@ -1,18 +1,3 @@
1
- <ul class="pivot-facet list-unstyled">
2
- <% display_facet.items.each do |item| -%>
3
- <li>
4
- <span class="facet-values">
5
- <% if facet_in_params?(field_name, item) %>
6
- <%= render_selected_facet_value(field_name, item) %>
7
- <% else %>
8
- <%= render_facet_value(field_name, item) %>
9
- <% end -%>
10
- </span>
11
-
12
- <% unless item.items.blank? %>
13
- <%= render 'facet_pivot', display_facet: item, field_name: field_name %>
14
- <% end %>
15
- </li>
16
- <% end %>
17
-
18
- </ul>
1
+ <%= render(Blacklight::FacetFieldListComponent.new(
2
+ facet_field: facet_field_presenter(facet_field.merge(item_component: Blacklight::FacetItemPivotComponent), display_facet),
3
+ layout: false)) %>
@@ -214,6 +214,9 @@ ar:
214
214
  remove: '[إزالة]'
215
215
  missing: "[غير موجود]"
216
216
  all: الكل
217
+ pivot:
218
+ show: فتح
219
+ hide: "إغلاق"
217
220
  group:
218
221
  more: 'المزيد »'
219
222
  filters:
@@ -194,6 +194,9 @@ de:
194
194
  selected:
195
195
  remove: '[entfernen]'
196
196
  missing: [fehlt]
197
+ pivot:
198
+ show: Öffnen
199
+ hide: Schließen
197
200
  group:
198
201
  more: 'mehr »'
199
202
  filters:
@@ -194,6 +194,9 @@ en:
194
194
  remove: '[remove]'
195
195
  missing: "[Missing]"
196
196
  all: All
197
+ pivot:
198
+ show: Show
199
+ hide: Hide
197
200
  group:
198
201
  more: 'more »'
199
202
  filters:
@@ -194,6 +194,9 @@ es:
194
194
  selected:
195
195
  remove: '[borrar]'
196
196
  missing: '[Falta]'
197
+ pivot:
198
+ show: Abierto
199
+ hide: Cerrar
197
200
  group:
198
201
  more: 'más »'
199
202
  filters:
@@ -197,6 +197,9 @@ fr:
197
197
  selected:
198
198
  remove: '[ X ]'
199
199
  missing: '[manquante]'
200
+ pivot:
201
+ show: Ouvrir
202
+ hide: Fermer
200
203
  group:
201
204
  more: 'plus »'
202
205
  filters:
@@ -194,6 +194,9 @@ hu:
194
194
  selected:
195
195
  remove: '[eltávolítás]'
196
196
  missing: "[Hiányzó]"
197
+ pivot:
198
+ show: Megnyitás
199
+ hide: Bezárás
197
200
  group:
198
201
  more: 'több »'
199
202
  filters:
@@ -194,6 +194,9 @@ it:
194
194
  selected:
195
195
  remove: '[cancella]'
196
196
  missing: [Mancante]
197
+ pivot:
198
+ show: Apri
199
+ hide: Chiudi
197
200
  group:
198
201
  more: 'altri »'
199
202
  filters:
@@ -194,6 +194,9 @@ nl:
194
194
  selected:
195
195
  remove: '[verwijder]'
196
196
  missing: "[Ontbrekend]"
197
+ pivot:
198
+ show: Openen
199
+ hide: Sluiten
197
200
  group:
198
201
  more: 'meer »'
199
202
  filters:
@@ -195,6 +195,9 @@ pt-BR:
195
195
  selected:
196
196
  remove: '[remover]'
197
197
  missing: [Ausência]
198
+ pivot:
199
+ show: Abrir
200
+ hide: Fechar
198
201
  group:
199
202
  more: 'mais »'
200
203
  filters:
@@ -194,6 +194,9 @@ sq:
194
194
  selected:
195
195
  remove: '[fshije]'
196
196
  missing: "[Mungon]"
197
+ pivot:
198
+ show: Hape
199
+ hide: "Mbylle"
197
200
  group:
198
201
  more: 'më shumë »'
199
202
  filters:
@@ -194,6 +194,9 @@ zh:
194
194
  selected:
195
195
  remove: '[删除]'
196
196
  missing: "[未找到]"
197
+ pivot:
198
+ show: 打开
199
+ hide: 关
197
200
  group:
198
201
  more: '更多 »'
199
202
  filters:
@@ -282,15 +282,10 @@ module Blacklight
282
282
  # Provide a 'deep copy' of Blacklight::Configuration that can be modified without effecting
283
283
  # the original Blacklight::Configuration instance.
284
284
  #
285
- # Rails 4.x provides `#deep_dup`, but it aggressively `#dup`'s class names
286
- # too. These model names should not be `#dup`'ed or we might break ActiveModel::Naming.
285
+ # Note: Rails provides `#deep_dup`, but it aggressively `#dup`'s class names too, turning them
286
+ # into anonymous class instances.
287
287
  def deep_copy
288
- deep_dup.tap do |copy|
289
- %w(repository_class response_model document_model document_presenter_class search_builder_class facet_paginator_class).each do |klass|
290
- # Don't copy if nil, so as not to prematurely autoload default classes
291
- copy.send("#{klass}=", send(klass)) unless fetch(klass.to_sym, nil).nil?
292
- end
293
- end
288
+ deep_transform_values_in_object(self, &method(:_deep_copy))
294
289
  end
295
290
 
296
291
  # builds a copy for the provided controller class
@@ -402,5 +397,37 @@ module Blacklight
402
397
  yield(config) if block_given?
403
398
  config_hash[name] = config
404
399
  end
400
+
401
+ # Provide custom duplication for certain types of configuration (intended for use in e.g. deep_transform_values)
402
+ def _deep_copy(value)
403
+ case value
404
+ when Module then value
405
+ when NestedOpenStructWithHashAccess then value.class.new(value.nested_class, deep_transform_values_in_object(value.to_h, &method(:_deep_copy)))
406
+ when OpenStruct then value.class.new(deep_transform_values_in_object(value.to_h, &method(:_deep_copy)))
407
+ else
408
+ value.dup
409
+ end
410
+ end
411
+
412
+ # This is a little shim to support Rails 6 (which has Hash#deep_transform_values) and
413
+ # earlier versions (which use our backport). Once we drop support for Rails 6, this
414
+ # can go away.
415
+ def deep_transform_values_in_object(object, &block)
416
+ return object.deep_transform_values(&block) if object.respond_to?(:deep_transform_values)
417
+
418
+ _deep_transform_values_in_object(object, &block)
419
+ end
420
+
421
+ # Ported from Rails 6
422
+ def _deep_transform_values_in_object(object, &block)
423
+ case object
424
+ when Hash
425
+ object.transform_values { |value| _deep_transform_values_in_object(value, &block) }
426
+ when Array
427
+ object.map { |e| _deep_transform_values_in_object(e, &block) }
428
+ else
429
+ yield(object)
430
+ end
431
+ end
405
432
  end
406
433
  end
@@ -84,7 +84,7 @@ class <%= controller_name.classify %>Controller < ApplicationController
84
84
  config.add_facet_field 'subject_geo_ssim', label: 'Region'
85
85
  config.add_facet_field 'subject_era_ssim', label: 'Era'
86
86
 
87
- config.add_facet_field 'example_pivot_field', label: 'Pivot Field', :pivot => ['format', 'language_ssim']
87
+ config.add_facet_field 'example_pivot_field', label: 'Pivot Field', pivot: ['format', 'language_ssim'], collapsing: true
88
88
 
89
89
  config.add_facet_field 'example_query_facet_field', label: 'Publish Date', :query => {
90
90
  :years_5 => { label: 'within 5 Years', fq: "pub_date_ssim:[#{Time.zone.now.year - 5 } TO *]" },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blacklight-frontend",
3
- "version": "7.1.0",
3
+ "version": "7.7.0",
4
4
  "lockfileVersion": 1,
5
5
  "requires": true,
6
6
  "dependencies": {
@@ -1884,9 +1884,9 @@
1884
1884
  "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
1885
1885
  },
1886
1886
  "jquery": {
1887
- "version": "3.4.1",
1888
- "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.4.1.tgz",
1889
- "integrity": "sha512-36+AdBzCL+y6qjw5Tx7HgzeGCzC81MDDgaUP8ld2zhx58HdqXGoBd+tHdrBMiyjGQs0Hxs/MLZTu/eHNJJuWPw=="
1887
+ "version": "3.5.1",
1888
+ "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.5.1.tgz",
1889
+ "integrity": "sha512-XwIBPqcMn57FxfT+Go5pzySnm4KWkT1Tv7gjrpT1srtf8Weynl6R273VJ5GjkRb51IzMp5nbaPjJXMWeju2MKg=="
1890
1890
  },
1891
1891
  "js-tokens": {
1892
1892
  "version": "4.0.0",
@@ -24,7 +24,7 @@
24
24
  "dependencies": {
25
25
  "bloodhound-js": "^1.2.3",
26
26
  "bootstrap": "^4.3.1",
27
- "jquery": "^3.4.1",
27
+ "jquery": "^3.5.1",
28
28
  "typeahead.js": "^0.11.1"
29
29
  }
30
30
  }
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Blacklight::FacetItemPivotComponent, type: :component do
6
+ subject(:render) do
7
+ render_inline(described_class.new(facet_item: facet_item))
8
+ end
9
+
10
+ let(:rendered) do
11
+ Capybara::Node::Simple.new(render)
12
+ end
13
+
14
+ let(:search_state) do
15
+ Blacklight::SearchState.new({}, Blacklight::Configuration.new)
16
+ end
17
+
18
+ let(:facet_item) do
19
+ instance_double(
20
+ Blacklight::FacetItemPresenter,
21
+ facet_config: Blacklight::Configuration::FacetField.new(key: 'z'),
22
+ facet_field: 'z',
23
+ label: 'x',
24
+ hits: 10,
25
+ href: '/catalog?f[z]=x',
26
+ selected?: false,
27
+ search_state: search_state,
28
+ items: [OpenStruct.new(value: 'x:1', hits: 5)]
29
+ )
30
+ end
31
+
32
+ it 'links to the facet and shows the number of hits' do
33
+ expect(rendered).to have_selector 'li'
34
+ expect(rendered).to have_link 'x', href: '/catalog?f[z]=x'
35
+ expect(rendered).to have_selector '.facet-count', text: '10'
36
+ end
37
+
38
+ it 'has the facet hierarchy' do
39
+ puts render
40
+ expect(rendered).to have_selector 'li ul.pivot-facet'
41
+ expect(rendered).to have_link 'x:1', href: /f%5Bz%5D%5B%5D=x%3A1/
42
+ end
43
+
44
+ context 'with a selected facet' do
45
+ let(:facet_item) do
46
+ instance_double(
47
+ Blacklight::FacetItemPresenter,
48
+ facet_config: Blacklight::Configuration::FacetField.new,
49
+ facet_field: 'z',
50
+ label: 'x',
51
+ hits: 10,
52
+ href: '/catalog',
53
+ selected?: true,
54
+ search_state: search_state,
55
+ items: []
56
+ )
57
+ end
58
+
59
+ it 'links to the facet and shows the number of hits' do
60
+ expect(rendered).to have_selector 'li'
61
+ expect(rendered).to have_selector '.selected', text: 'x'
62
+ expect(rendered).to have_link '[remove]', href: '/catalog'
63
+ expect(rendered).to have_selector '.selected.facet-count', text: '10'
64
+ end
65
+ end
66
+ end
@@ -67,6 +67,26 @@ RSpec.describe "Facets" do
67
67
  expect(page).to have_css('#facet-format', visible: true) # assert that it didn't re-collapse
68
68
  end
69
69
 
70
+ it 'is able to expand pivot facets when javascript is enabled', js: true do
71
+ visit root_path
72
+
73
+ within('#facets .facets-header') do
74
+ page.find('button.navbar-toggler').click
75
+ end
76
+
77
+ page.find('h3.facet-field-heading button', text: 'Pivot Field').click
78
+
79
+ within '#facet-example_pivot_field' do
80
+ expect(page).to have_css('.facet-leaf-node', text: 'Book 30')
81
+ expect(page).not_to have_css('.facet-select', text: 'Tibetan')
82
+ page.find('.facet-toggle-handle').click
83
+ click_link 'Tibetan'
84
+ end
85
+
86
+ expect(page).to have_css('.constraint-value', text: 'Format Book')
87
+ expect(page).to have_css('.constraint-value', text: 'Language Tibetan')
88
+ end
89
+
70
90
  describe 'heading button focus with Firefox' do
71
91
  before do
72
92
  Capybara.current_driver = :selenium_headless
@@ -189,14 +189,18 @@ RSpec.describe "Blacklight::Configuration", api: true do
189
189
  it "provides cloned copies of mutable data structures" do
190
190
  config.a = { value: 1 }
191
191
  config.b = [1, 2, 3]
192
+ config.c = Blacklight::Configuration::Field.new(key: 'c', value: %w[a b])
192
193
 
193
194
  config_copy.a[:value] = 2
194
195
  config_copy.b << 5
196
+ config_copy.c.value << 'c'
195
197
 
196
198
  expect(config.a[:value]).to eq 1
197
199
  expect(config_copy.a[:value]).to eq 2
198
200
  expect(config.b).to match_array [1, 2, 3]
199
201
  expect(config_copy.b).to match_array [1, 2, 3, 5]
202
+ expect(config.c.value).to match_array %w[a b]
203
+ expect(config_copy.c.value).to match_array %w[a b c]
200
204
  end
201
205
  end
202
206
 
@@ -17,22 +17,14 @@ RSpec.describe Blacklight::Icon do
17
17
  end
18
18
  it 'adds title' do
19
19
  expect(Capybara.string(subject.svg))
20
- .to have_css 'title[id^="bl-icon-search-"]', text: 'search icon'
21
- end
22
- it 'adds aria-labelledby' do
23
- expect(Capybara.string(subject.svg))
24
- .to have_css 'svg[aria-labelledby^="bl-icon-search-"]'
20
+ .to have_css 'title', text: 'Search'
25
21
  end
26
22
  context 'when label is false' do
27
23
  subject { described_class.new(:search, classes: 'awesome', aria_hidden: true, label: false) }
28
24
 
29
25
  it 'does not add title' do
30
26
  expect(Capybara.string(subject.svg))
31
- .not_to have_css 'title', text: 'search icon'
32
- end
33
- it 'does not add aria-labelledby' do
34
- expect(Capybara.string(subject.svg))
35
- .not_to have_css 'svg[aria-labelledby^="bl-icon-search-"]'
27
+ .not_to have_css 'title', text: 'Search'
36
28
  end
37
29
  end
38
30
 
@@ -41,14 +33,14 @@ RSpec.describe Blacklight::Icon do
41
33
 
42
34
  it 'adds title' do
43
35
  expect(Capybara.string(subject.svg))
44
- .to have_css 'title[id^="bl-icon-search_foo-"]', text: 'search icon'
36
+ .to have_css 'title', text: 'Search'
45
37
  end
46
38
  end
47
39
  end
48
40
 
49
41
  describe '#options' do
50
42
  it 'applies options classes and default class' do
51
- expect(subject.options[:class]).to eq 'blacklight-icons awesome'
43
+ expect(subject.options[:class]).to eq 'blacklight-icons blacklight-icon-search awesome'
52
44
  end
53
45
  it 'applies options aria-hidden=true' do
54
46
  expect(subject.options[:'aria-hidden']).to be true
@@ -57,7 +49,7 @@ RSpec.describe Blacklight::Icon do
57
49
  subject { described_class.new(:view) }
58
50
 
59
51
  it 'applies default class with no options' do
60
- expect(subject.options[:class]).to eq 'blacklight-icons'
52
+ expect(subject.options[:class]).to eq 'blacklight-icons blacklight-icon-view'
61
53
  end
62
54
 
63
55
  it 'has no aria-hidden attribute with no options' do
@@ -25,6 +25,7 @@ require 'equivalent-xml'
25
25
  require 'webdrivers'
26
26
 
27
27
  Capybara.javascript_driver = :selenium_chrome_headless
28
+ Capybara.disable_animation = true
28
29
 
29
30
  # Requires supporting ruby files with custom matchers and macros, etc,
30
31
  # in spec/support/ and its subdirectories.
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: 7.8.1
4
+ version: 7.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonathan Rochkind
@@ -17,7 +17,7 @@ authors:
17
17
  autorequire:
18
18
  bindir: exe
19
19
  cert_chain: []
20
- date: 2020-06-01 00:00:00.000000000 Z
20
+ date: 2020-06-23 00:00:00.000000000 Z
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency
23
23
  name: rails
@@ -360,6 +360,7 @@ files:
360
360
  - app/components/blacklight/facet_field_list_component.rb
361
361
  - app/components/blacklight/facet_field_no_layout_component.rb
362
362
  - app/components/blacklight/facet_item_component.rb
363
+ - app/components/blacklight/facet_item_pivot_component.rb
363
364
  - app/controllers/bookmarks_controller.rb
364
365
  - app/controllers/catalog_controller.rb
365
366
  - app/controllers/concerns/blacklight/base.rb
@@ -624,6 +625,7 @@ files:
624
625
  - spec/components/blacklight/constraint_layout_component_spec.rb
625
626
  - spec/components/blacklight/facet_field_list_component_spec.rb
626
627
  - spec/components/blacklight/facet_item_component_spec.rb
628
+ - spec/components/blacklight/facet_item_pivot_component_spec.rb
627
629
  - spec/controllers/alternate_controller_spec.rb
628
630
  - spec/controllers/application_controller_spec.rb
629
631
  - spec/controllers/blacklight/base_spec.rb
@@ -780,6 +782,7 @@ test_files:
780
782
  - spec/components/blacklight/constraint_layout_component_spec.rb
781
783
  - spec/components/blacklight/facet_field_list_component_spec.rb
782
784
  - spec/components/blacklight/facet_item_component_spec.rb
785
+ - spec/components/blacklight/facet_item_pivot_component_spec.rb
783
786
  - spec/controllers/alternate_controller_spec.rb
784
787
  - spec/controllers/application_controller_spec.rb
785
788
  - spec/controllers/blacklight/base_spec.rb