blacklight-hierarchy 3.0.0 → 4.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +53 -0
  3. data/.travis.yml +1 -1
  4. data/Gemfile +5 -0
  5. data/README.md +36 -9
  6. data/app/assets/javascripts/blacklight/hierarchy/hierarchy.js +7 -7
  7. data/app/assets/stylesheets/blacklight/hierarchy/hierarchy.scss +50 -10
  8. data/app/components/blacklight/hierarchy/facet_field_component.html.erb +18 -0
  9. data/app/components/blacklight/hierarchy/facet_field_component.rb +33 -0
  10. data/app/components/blacklight/hierarchy/facet_field_list_component.html.erb +12 -0
  11. data/app/components/blacklight/hierarchy/facet_field_list_component.rb +72 -0
  12. data/app/components/blacklight/hierarchy/qfacet_value_component.html.erb +1 -0
  13. data/app/components/blacklight/hierarchy/qfacet_value_component.rb +26 -0
  14. data/app/components/blacklight/hierarchy/selected_qfacet_value_component.html.erb +4 -0
  15. data/app/components/blacklight/hierarchy/selected_qfacet_value_component.rb +19 -0
  16. data/app/helpers/blacklight/hierarchy_helper.rb +65 -19
  17. data/app/models/hierarchical_facet_item.rb +1 -0
  18. data/app/views/blacklight/hierarchy/_facet_hierarchy.html.erb +5 -1
  19. data/blacklight-hierarchy.gemspec +3 -3
  20. data/config/locales/blacklight-hierarchy.ar.yml +4 -0
  21. data/config/locales/blacklight-hierarchy.en.yml +4 -0
  22. data/lib/blacklight/hierarchy/engine.rb +2 -0
  23. data/lib/blacklight/hierarchy/version.rb +1 -1
  24. data/package.json +3 -2
  25. data/spec/features/basic_spec.rb +4 -5
  26. data/spec/helpers/hierarchy_helper_spec.rb +10 -1
  27. data/spec/test_app_templates/lib/generators/test_app_generator.rb +8 -0
  28. metadata +34 -25
  29. data/app/assets/images/collapsed.png +0 -0
  30. data/app/assets/images/expanded.png +0 -0
  31. data/app/views/blacklight/hierarchy/_facet_hierarchy_item.html.erb +0 -25
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 301106611145298332bcd99baa46b594bb6e81cfbb91c67c144ad67ea82ffd4e
4
- data.tar.gz: 3de7c9ffe277ba90bc6e3cfd1518f0dd1b91234399c5de0bfa37ed821da23cf3
3
+ metadata.gz: d7bacf2b0748d1154d75223505d631c5d38edd91a1bb72f514bd0809fb57cce8
4
+ data.tar.gz: 752c9cb4ba854489493681452862fcbb8dd332d0a1c505c849890f2ae0d85184
5
5
  SHA512:
6
- metadata.gz: 49ed3184d67352e89bcf78badd554617c9a8618f2bf0ddb4260ec68d43e003604b05b5874a19d2bf5d2d5ac59f0c555f302a6630dd4ca9258ca81269936095ac
7
- data.tar.gz: 33cff3c6d664380a251c8956f1de68be41c297067385babbd628b55e61a3e046adf8239a6b5ac04a6d33e861512a122c6601e8ffc9389e5b5e01b54b73e684de
6
+ metadata.gz: baf85f7b64a20872faa888b8513d82b469757325a0da6dfa597f653f8040059413cb42f8a9cd8ec41636529a335b4c7247173a16447d85ee1f81adee91ae6a07
7
+ data.tar.gz: 966af183ac26d3db3346018af9bff71e714d5dbc22af73664fc4bab5d8eba816cec2c564408c4dd050685c1cc14d52f13b09c14b50d98c3f5e4495174490cb29
@@ -0,0 +1,53 @@
1
+ # This workflow uses actions that are not certified by GitHub.
2
+ # They are provided by a third-party and are governed by
3
+ # separate terms of service, privacy policy, and support
4
+ # documentation.
5
+ # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
6
+ # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
7
+
8
+ name: CI
9
+
10
+ on:
11
+ push:
12
+ branches: [ master ]
13
+ pull_request:
14
+ branches: [ master ]
15
+
16
+ jobs:
17
+ test:
18
+ runs-on: ubuntu-latest
19
+ strategy:
20
+ matrix:
21
+ ruby: [2.6, 2.7]
22
+ steps:
23
+ - uses: actions/checkout@v2
24
+ - name: Set up Ruby
25
+ uses: ruby/setup-ruby@v1
26
+ with:
27
+ ruby-version: ${{ matrix.ruby }}
28
+ - name: Install dependencies
29
+ run: bundle install
30
+ - name: Run tests
31
+ run: bundle exec rake ci
32
+ env:
33
+ ENGINE_CART_RAILS_OPTIONS: '--skip-git --skip-listen --skip-spring --skip-keeps --skip-action-cable --skip-coffee --skip-test'
34
+ test_rails5:
35
+ runs-on: ubuntu-latest
36
+ strategy:
37
+ matrix:
38
+ ruby: [2.5, 2.6]
39
+ steps:
40
+ - uses: actions/checkout@v2
41
+ - name: Set up Ruby
42
+ uses: ruby/setup-ruby@v1
43
+ with:
44
+ ruby-version: ${{ matrix.ruby }}
45
+ - name: Install dependencies
46
+ run: bundle install
47
+ env:
48
+ RAILS_VERSION: 5.2.4.2
49
+ - name: Run tests
50
+ run: bundle exec rake ci
51
+ env:
52
+ RAILS_VERSION: 5.2.4.2
53
+ ENGINE_CART_RAILS_OPTIONS: '--skip-git --skip-listen --skip-spring --skip-keeps --skip-action-cable --skip-coffee --skip-test'
@@ -1,7 +1,7 @@
1
1
  language: ruby
2
2
  sudo: false
3
3
  rvm:
4
- - 2.5.1
4
+ - 2.7.1
5
5
 
6
6
  env:
7
7
  global:
data/Gemfile CHANGED
@@ -31,6 +31,11 @@ else
31
31
  gem 'rails', ENV['RAILS_VERSION']
32
32
  end
33
33
  end
34
+
35
+ case ENV['RAILS_VERSION']
36
+ when /^5.[12]/, /^6.0/
37
+ gem 'sass-rails', '~> 5.0'
38
+ end
34
39
  end
35
40
  # END ENGINE_CART BLOCK
36
41
  eval_gemfile File.expand_path("spec/test_app_templates/Gemfile.extra", File.dirname(__FILE__))
data/README.md CHANGED
@@ -46,18 +46,18 @@ You can skip as many levels as you'd like, as long as the "leaf" values are inde
46
46
 
47
47
  **Note**: If you use Solr's built-in [PathHierarchyTokenizerFactory](http://wiki.apache.org/solr/AnalyzersTokenizersTokenFilters#solr.PathHierarchyTokenizerFactory), you can index the entire depth by supplying only the leaf nodes. Otherwise you are expected to build the permutations yourself before loading.
48
48
 
49
- In your Blacklight controller configuration (usually `CatalogController`), tell Blacklight to render the facet using the hierarchy partial.
49
+ In your Blacklight controller configuration (usually `CatalogController`), tell Blacklight to render the facet using the hierarchy component.
50
50
 
51
51
 
52
52
  ```ruby
53
- config.add_facet_field 'queue_wps', :label => 'Queue Status', :partial => 'blacklight/hierarchy/facet_hierarchy'
54
- config.add_facet_field 'queue_wsp', :label => 'Queue Status', :partial => 'blacklight/hierarchy/facet_hierarchy'
55
- config.add_facet_field 'queue_swp', :label => 'Queue Status', :partial => 'blacklight/hierarchy/facet_hierarchy'
56
- config.add_facet_field 'callnum_top', :label => 'Callnumber', :partial => 'blacklight/hierarchy/facet_hierarchy'
57
- config.add_facet_field 'foo_trunk', :label => 'Foo L1', :partial => 'blacklight/hierarchy/facet_hierarchy'
58
- config.add_facet_field 'foo_branch', :label => 'Foo L2', :partial => 'blacklight/hierarchy/facet_hierarchy'
59
- config.add_facet_field 'foo_leaves', :label => 'Foo L3', :partial => 'blacklight/hierarchy/facet_hierarchy'
60
- config.add_facet_field 'tag_facet', :label => 'Tag', :partial => 'blacklight/hierarchy/facet_hierarchy'
53
+ config.add_facet_field 'queue_wps', label: 'Queue Status', component: Blacklight::Hierarchy::FacetFieldListComponent
54
+ config.add_facet_field 'queue_wsp', label: 'Queue Status', component: Blacklight::Hierarchy::FacetFieldListComponent
55
+ config.add_facet_field 'queue_swp', label: 'Queue Status', component: Blacklight::Hierarchy::FacetFieldListComponent
56
+ config.add_facet_field 'callnum_top', label: 'Callnumber', component: Blacklight::Hierarchy::FacetFieldListComponent
57
+ config.add_facet_field 'foo_trunk', label: 'Foo L1', component: Blacklight::Hierarchy::FacetFieldListComponent
58
+ config.add_facet_field 'foo_branch', label: 'Foo L2', component: Blacklight::Hierarchy::FacetFieldListComponent
59
+ config.add_facet_field 'foo_leaves', label: 'Foo L3', component: Blacklight::Hierarchy::FacetFieldListComponent
60
+ config.add_facet_field 'tag_facet', label: 'Tag', component: Blacklight::Hierarchy::FacetFieldListComponent
61
61
  ```
62
62
 
63
63
  Add your hierarchy-specific options to the controller configuration:
@@ -83,6 +83,33 @@ Facet fields should be added for each permutation of hierarchy key and term valu
83
83
  config.facet_display[:hierarchy].each{ |k,v| puts "#{k}_#{v}" }
84
84
  ```
85
85
 
86
+ ### Overriding the icon
87
+ The icon is available in an engine configuration. You can change them in an initializer in your app.
88
+
89
+ ```ruby
90
+ Blacklight::Hierarchy::Engine.config.closed_icon = '➕'
91
+ Blacklight::Hierarchy::Engine.config.opened_icon = '➖'
92
+
93
+ ```
94
+
95
+ ### Aria Labels
96
+ For screen reader purposes we have used "Toggle subgroup" as the aria-label attribute of the button. This is internationalized using rails' i18n feature.
97
+
98
+ The field name is used in the key to allow for facet specific aria labels or defaults back to the generic key/"Toggle subgroup" text.
99
+
100
+ ```yml
101
+ # config/locales/en.yml
102
+ en:
103
+ blacklight:
104
+ hierarchy:
105
+ format_ssim_toggle_aria_label: Toggle format section
106
+ toggle_aria_label: Toggle call number section
107
+ ```
108
+
109
+ ### Javascript
110
+
111
+ The javascript in this project requires jquery, but it's up to you to provide it in a way that best works for your project. You may consider the jquery-rails gem or if you use webpacker, you could use the jquery npm package.
112
+
86
113
  ## Caveats
87
114
 
88
115
  This code was ripped out of another project, and is still quite immature as a standalone project. Every effort has been made to make it as plug-and-play as possible, but it may stomp on Blacklight in unintended ways (e.g., ways that made sense in context of its former host app, but which aren't compatible with generic Blacklight). Proceed with caution, and report issues.
@@ -12,23 +12,23 @@ Blacklight.onLoad(function(){
12
12
 
13
13
  Blacklight.hierarchical_facet_expand_contract = function() {
14
14
  var li = $(this);
15
-
15
+
16
16
  $('ul', this).each(function() {
17
17
  li.addClass('twiddle');
18
18
  if($('span.selected', this).length == 0){
19
19
  $(this).hide();
20
20
  } else {
21
21
  li.addClass('twiddle-open');
22
+ li.children('.toggle-handle').attr('aria-expanded', 'true');
22
23
  }
23
24
  });
24
25
 
25
26
  // attach the toggle behavior to the li tag
26
- li.click(function(e){
27
- if (e.target == this) {
28
- // toggle the content
29
- $(this).toggleClass('twiddle-open');
30
- $(this).children('ul').slideToggle();
31
- }
27
+ li.children('.toggle-handle').click(function(e){
28
+ // toggle the content
29
+ $(this).attr('aria-expanded', $(this).attr('aria-expanded') === 'true' ? 'false' : 'true');
30
+ $(this).parent('li').toggleClass('twiddle-open');
31
+ $(this).parent('li').children('ul').slideToggle();
32
32
  });
33
33
  };
34
34
  })(jQuery);
@@ -1,23 +1,63 @@
1
- $text-muted: #777777 !default;
1
+ $text-muted: #777 !default;
2
2
 
3
3
  .facet-hierarchy {
4
- margin-left: -28px;
4
+ list-style-type: none;
5
+ padding-left: 0;
5
6
 
6
7
  ul {
7
- margin-left: 0;
8
- border-bottom: none;
8
+ border-bottom: 0;
9
+ list-style-type: none;
9
10
  padding-bottom: 0;
10
- li {
11
- margin-left: 8px;
11
+ padding-left: 1.3em;
12
+ }
13
+
14
+ .facet_select {
15
+ display: inline-block;
16
+ margin-bottom: 6px;
17
+ max-width: calc(100% - 5em);
18
+ }
19
+
20
+ .facet-count {
21
+ float: right;
22
+ }
23
+
24
+ .toggle-handle {
25
+ border: 0;
26
+ margin: 0;
27
+ min-width: 1em;
28
+ padding: 0;
29
+ vertical-align: top;
30
+
31
+ .closed,
32
+ .opened {
33
+ display: none;
12
34
  }
13
35
  }
36
+
37
+ .twiddle>.toggle-handle .closed {
38
+ display: inline;
39
+ }
40
+
41
+ .twiddle>.toggle-handle .opened {
42
+ display: none;
43
+ }
44
+
45
+ .twiddle-open>.toggle-handle .closed {
46
+ display: none;
47
+ }
48
+
49
+ .twiddle-open>.toggle-handle .opened {
50
+ display: inline;
51
+ }
52
+
53
+ .h-leaf {
54
+ padding-left: 1.3em;
55
+ }
56
+
14
57
  .h-node {
15
58
  cursor: pointer;
16
- list-style-image: asset_data_url("collapsed.png")
17
- }
18
- .h-node.twiddle-open {
19
- list-style-image: asset_data_url("expanded.png");
20
59
  }
60
+
21
61
  .remove {
22
62
  color: $text-muted;
23
63
  }
@@ -0,0 +1,18 @@
1
+ <li class="<%= li_class %>" role="treeitem">
2
+ <%= helpers.facet_toggle_button(field_name, id) if subset.any? %>
3
+ <% if item.nil? %>
4
+ <%= key %>
5
+ <% elsif qfacet_selected? %>
6
+ <%= render Blacklight::Hierarchy::SelectedQfacetValueComponent.new(field_name: field_name, item: item) %>
7
+ <% else %>
8
+ <%= render Blacklight::Hierarchy::QfacetValueComponent.new(field_name: field_name, item: item, id: id) %>
9
+ <% end %>
10
+
11
+ <% unless subset.empty? %>
12
+ <ul role=\"group\">
13
+ <% subset.keys.sort.each do |subkey| %>
14
+ <%= render self.class.new(field_name: field_name, tree: subset[subkey], key: subkey) %>
15
+ <% end %>
16
+ </ul>
17
+ <% end %>
18
+ </li>
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Blacklight
4
+ module Hierarchy
5
+ class FacetFieldComponent < ::ViewComponent::Base
6
+ def initialize(field_name:, tree:, key:)
7
+ @field_name = field_name
8
+ @tree = tree
9
+ @key = key
10
+ @id = SecureRandom.uuid
11
+ end
12
+
13
+ attr_reader :field_name, :tree, :key, :id
14
+
15
+ def subset
16
+ @subset ||= tree.reject { |k, _v| !k.is_a?(String) }
17
+ end
18
+
19
+ def li_class
20
+ subset.empty? ? 'h-leaf' : 'h-node'
21
+ end
22
+
23
+ def item
24
+ tree[:_]
25
+ end
26
+
27
+ def qfacet_selected?
28
+ config = helpers.facet_configuration_for_field(field_name)
29
+ helpers.search_state.filter(config).include?(item.qvalue)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,12 @@
1
+ <%= render(@layout.new(facet_field: @facet_field)) do |component| %>
2
+ <% component.with(:label) do %>
3
+ <%= @facet_field.label %>
4
+ <% end %>
5
+ <% component.with(:body) do %>
6
+ <ul class="facet-hierarchy" role="tree">
7
+ <% tree.keys.sort.collect do |key| %>
8
+ <%= render Blacklight::Hierarchy::FacetFieldComponent.new(field_name: @facet_field.facet_field.field, tree: tree[key], key: key) %>
9
+ <% end %>
10
+ </ul>
11
+ <% end %>
12
+ <% end %>
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Blacklight
4
+ module Hierarchy
5
+ class FacetFieldListComponent < Blacklight::FacetFieldListComponent
6
+ DELIMETER = '_'
7
+
8
+ # @param [Blacklight::Configuration::FacetField] as defined in controller with config.add_facet_field (and with :partial => 'blacklight/hierarchy/facet_hierarchy')
9
+ # @return [String] html for the facet tree
10
+ def tree
11
+ @tree ||= begin
12
+ facet_tree_for_prefix = facet_tree
13
+ facet_tree_for_prefix ? facet_tree_for_prefix[field_name] : nil
14
+ end
15
+ end
16
+
17
+ def field_name
18
+ @facet_field.facet_field.field
19
+ end
20
+
21
+ # @return [String] a key to access the rest of the hierarchy tree, as defined in controller config.facet_display[:hierarchy] declaration.
22
+ # e.g. if you had this in controller:
23
+ # config.facet_display = {
24
+ # :hierarchy => {
25
+ # 'wf' => [['wps','wsp','swp'], ':'],
26
+ # 'callnum_top' => [['facet'], '/'],
27
+ # 'exploded_tag' => [['ssim'], ':']
28
+ # }
29
+ # }
30
+ # then possible hkey values would be 'wf', 'callnum_top', and 'exploded_tag'.
31
+ #
32
+ # the key in the :hierarchy hash is the "prefix" for the solr field with the hierarchy info. the value
33
+ # in the hash is a list, where the first element is a list of suffixes, and the second element is the delimiter
34
+ # used to break up the sections of hierarchical data in the solr field being read. when joined, the prefix and
35
+ # suffix should form the field name. so, for example, 'wf_wps', 'wf_wsp', 'wf_swp', 'callnum_top_facet', and
36
+ # 'exploded_tag_ssim' would be the solr fields with blacklight-hierarchy related configuration according to the
37
+ # hash above. ':' would be the delimiter used in all of those fields except for 'callnum_top_facet', which would
38
+ # use '/'. exploded_tag_ssim might contain values like ['Book', 'Book : Multi-Volume Work'], and callnum_top_facet
39
+ # might contain values like ['LB', 'LB/2395', 'LB/2395/.C65', 'LB/2395/.C65/1991'].
40
+ # note: the suffixes (e.g. 'ssim' for 'exploded_tag' in the above example) can't have underscores, otherwise things break.
41
+ def prefix
42
+ @prefix ||= field_name.gsub("#{DELIMETER}#{field_name.split(/#{DELIMETER}/).last}", '')
43
+ end
44
+
45
+
46
+ delegate :blacklight_config, to: :helpers
47
+
48
+ def facet_tree
49
+ @facet_tree ||= {}
50
+ return @facet_tree[prefix] unless @facet_tree[prefix].nil?
51
+ return @facet_tree[prefix] unless blacklight_config.facet_display[:hierarchy] && blacklight_config.facet_display[:hierarchy][prefix]
52
+ @facet_tree[prefix] = {}
53
+ facet_config = blacklight_config.facet_display[:hierarchy][prefix]
54
+ split_regex = Regexp.new("\s*#{Regexp.escape(facet_config.length >= 2 ? facet_config[1] : ':')}\s*")
55
+ facet_config.first.each do |key|
56
+ # TODO: remove baked in notion of underscores being part of the blacklight facet field names
57
+ facet_field = [prefix, key].compact.join('_')
58
+ @facet_tree[prefix][facet_field] ||= {}
59
+ data = @facet_field.display_facet
60
+ next if data.nil?
61
+ data.items.each do |facet_item|
62
+ path = facet_item.value.split(split_regex)
63
+ loc = @facet_tree[prefix][facet_field]
64
+ loc = loc[path.shift] ||= {} while path.length > 0
65
+ loc[:_] = HierarchicalFacetItem.new(facet_item.value, facet_item.value.split(split_regex).last, facet_item.hits)
66
+ end
67
+ end
68
+ @facet_tree[prefix]
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1 @@
1
+ <%= link_to_unless suppress_link, item.value, path_for_facet, id: id, class: 'facet_select' %> <%= render_facet_count %>
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Blacklight
4
+ module Hierarchy
5
+ class QfacetValueComponent < ::ViewComponent::Base
6
+ def initialize(field_name:, item:, id: nil, suppress_link: false)
7
+ @field_name = field_name
8
+ @item = item
9
+ @id = id
10
+ @suppress_link = suppress_link
11
+ end
12
+
13
+ attr_reader :field_name, :item, :id, :suppress_link
14
+
15
+ def path_for_facet
16
+ facet_config = helpers.facet_configuration_for_field(field_name)
17
+ Blacklight::FacetItemPresenter.new(item.qvalue, facet_config, helpers, field_name).href
18
+ end
19
+
20
+ def render_facet_count
21
+ classes = "facet-count"
22
+ content_tag("span", t('blacklight.search.facets.count', number: number_with_delimiter(item.hits)), class: classes)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,4 @@
1
+ <span class="selected"><%= render Blacklight::Hierarchy::QfacetValueComponent.new(field_name: field_name, item: item, suppress_link: true) %></span>
2
+ <%= link_to remove_href, class: 'remove' do %>
3
+ <span class="glyphicon glyphicon-remove"></span><span class="sr-only">[remove]</span>
4
+ <% end %>
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Blacklight
4
+ module Hierarchy
5
+ # Standard display of a SELECTED facet value, no link, special span with class, and 'remove' button.
6
+ class SelectedQfacetValueComponent < ::ViewComponent::Base
7
+ def initialize(field_name:, item:)
8
+ @field_name = field_name
9
+ @item = item
10
+ end
11
+
12
+ attr_reader :field_name, :item
13
+
14
+ def remove_href
15
+ helpers.search_action_path(helpers.search_state.remove_facet_params(field_name, item.qvalue))
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,4 +1,8 @@
1
+ require 'deprecation'
2
+
1
3
  module Blacklight::HierarchyHelper
4
+ extend Deprecation
5
+
2
6
  # Putting bare HTML strings in a helper sucks. But in this case, with a
3
7
  # lot of recursive tree-walking going on, it's an order of magnitude faster
4
8
  # than either render(:partial) or content_tag
@@ -6,25 +10,37 @@ module Blacklight::HierarchyHelper
6
10
  item = data[:_]
7
11
  subset = data.reject { |k, _v| !k.is_a?(String) }
8
12
 
9
- li_class = subset.empty? ? 'h-leaf' : 'h-node'
10
- ul = ''
11
- li = if item.nil?
12
- key
13
- elsif facet_in_params?(field_name, item.qvalue)
14
- render_selected_qfacet_value(field_name, item)
15
- else
16
- render_qfacet_value(field_name, item)
17
- end
18
-
19
- unless subset.empty?
20
- subul = subset.keys.sort.collect do |subkey|
21
- render_facet_hierarchy_item(field_name, subset[subkey], subkey)
22
- end.join('')
23
- ul = "<ul>#{subul}</ul>".html_safe
13
+ Deprecation.silence(Blacklight::HierarchyHelper) do
14
+ li_class = subset.empty? ? 'h-leaf' : 'h-node'
15
+ id = SecureRandom.uuid
16
+ ul = ''
17
+ li = ''
18
+ li << facet_toggle_button(field_name, id) if subset.any?
19
+ li << if item.nil?
20
+ key
21
+ elsif qfacet_selected?(field_name, item)
22
+ render_selected_qfacet_value(field_name, item)
23
+ else
24
+ render_qfacet_value(field_name, item, id: id)
25
+ end
26
+
27
+ unless subset.empty?
28
+ subul = subset.keys.sort.collect do |subkey|
29
+ render_facet_hierarchy_item(field_name, subset[subkey], subkey)
30
+ end.join('')
31
+ ul = "<ul role=\"group\">#{subul}</ul>".html_safe
32
+ end
33
+
34
+ %(<li class="#{li_class}" role="treeitem">#{li.html_safe}#{ul.html_safe}</li>).html_safe
24
35
  end
36
+ end
37
+ deprecation_deprecate :render_facet_hierarchy_item
25
38
 
26
- %(<li class="#{li_class}">#{li.html_safe}#{ul.html_safe}</li>).html_safe
39
+ def qfacet_selected?(field_name, item)
40
+ config = facet_configuration_for_field(field_name)
41
+ search_state.has_facet?(config, value: facet_value_for_facet_item(item.qvalue))
27
42
  end
43
+ private :qfacet_selected?
28
44
 
29
45
  # @param [Blacklight::Configuration::FacetField] as defined in controller with config.add_facet_field (and with :partial => 'blacklight/hierarchy/facet_hierarchy')
30
46
  # @return [String] html for the facet tree
@@ -39,10 +55,17 @@ module Blacklight::HierarchyHelper
39
55
  render_facet_hierarchy_item(field_name, tree[key], key)
40
56
  end.join("\n").html_safe
41
57
  end
58
+ deprecation_deprecate :render_hierarchy
42
59
 
43
60
  def render_qfacet_value(facet_solr_field, item, options = {})
44
- (link_to_unless(options[:suppress_link], item.value, path_for_facet(facet_solr_field, item.qvalue), class: 'facet_select') + ' ' + render_facet_count(item.hits)).html_safe
61
+ Deprecation.silence(Blacklight::FacetsHelperBehavior) do
62
+ id = options.delete(:id)
63
+ facet_config = facet_configuration_for_field(facet_solr_field)
64
+ path_for_facet = facet_item_presenter(facet_config, item.qvalue, facet_solr_field).href
65
+ (link_to_unless(options[:suppress_link], item.value, path_for_facet, id: id, class: 'facet_select') + ' ' + render_facet_count(item.hits)).html_safe
66
+ end
45
67
  end
68
+ deprecation_deprecate :render_qfacet_value
46
69
 
47
70
  # Standard display of a SELECTED facet value, no link, special span with class, and 'remove' button.
48
71
  def render_selected_qfacet_value(facet_solr_field, item)
@@ -54,8 +77,7 @@ module Blacklight::HierarchyHelper
54
77
  class: 'remove'
55
78
  )
56
79
  end
57
-
58
- HierarchicalFacetItem = Struct.new :qvalue, :value, :hits
80
+ deprecation_deprecate :render_selected_qfacet_value
59
81
 
60
82
  # @param [String] hkey - a key to access the rest of the hierarchy tree, as defined in controller config.facet_display[:hierarchy] declaration.
61
83
  # e.g. if you had this in controller:
@@ -99,6 +121,23 @@ module Blacklight::HierarchyHelper
99
121
  end
100
122
  @facet_tree[hkey]
101
123
  end
124
+ deprecation_deprecate :facet_tree
125
+
126
+ def facet_toggle_button(field_name, described_by)
127
+ aria_label = I18n.t(
128
+ "blacklight.hierarchy.#{field_name}_toggle_aria_label",
129
+ default: :'blacklight.hierarchy.toggle_aria_label'
130
+ )
131
+
132
+ # For Rails 5.2 support all options must be symbols. See https://github.com/rails/rails/issues/39813
133
+ tag.button(:'aria-expanded' => 'false',
134
+ :'aria-label' => aria_label,
135
+ :'aria-describedby' => described_by,
136
+ class: 'toggle-handle') do
137
+ tag.span(Blacklight::Hierarchy::Engine.config.closed_icon, :'aria-hidden' => 'true', class: 'closed') +
138
+ tag.span(Blacklight::Hierarchy::Engine.config.opened_icon, :'aria-hidden' => 'true', class: 'opened')
139
+ end
140
+ end
102
141
 
103
142
  # --------------------------------------------------------------------------------------------------------------------------------
104
143
  # below are methods pertaining to the "rotate" notion where you may want to look at the same tree data organized another way
@@ -109,11 +148,13 @@ module Blacklight::HierarchyHelper
109
148
  (prefix, order) = field_name.split(/_/, 2)
110
149
  (list = blacklight_config.facet_display[:hierarchy][prefix]) && list.include?(order)
111
150
  end
151
+ deprecation_deprecate :is_hierarchical?
112
152
 
113
153
  def facet_order(prefix)
114
154
  param_name = "#{prefix}_facet_order".to_sym
115
155
  params[param_name] || blacklight_config.facet_display[:hierarchy][prefix].first
116
156
  end
157
+ deprecation_deprecate :facet_order
117
158
 
118
159
  def facet_after(prefix, order)
119
160
  orders = blacklight_config.facet_display[:hierarchy][prefix]
@@ -126,6 +167,8 @@ module Blacklight::HierarchyHelper
126
167
  prefix = field_name.split(/_/).first
127
168
  field_name != "#{prefix}_#{facet_order(prefix)}"
128
169
  end
170
+ deprecation_deprecate :hide_facet?
171
+
129
172
 
130
173
  # FIXME: remove baked in colon separator
131
174
  def rotate_facet_value(val, from, to)
@@ -135,6 +178,7 @@ module Blacklight::HierarchyHelper
135
178
  return nil if new_values.include?(nil)
136
179
  new_values.compact.join(':')
137
180
  end
181
+ deprecation_deprecate :rotate_facet_value
138
182
 
139
183
  # FIXME: remove baked in underscore separator in field name
140
184
  def rotate_facet_params(prefix, from, to, p = params.dup)
@@ -150,6 +194,7 @@ module Blacklight::HierarchyHelper
150
194
  p[:f].delete(to_field) if p[:f][to_field].empty?
151
195
  p
152
196
  end
197
+ deprecation_deprecate :rotate_facet_params
153
198
 
154
199
  # FIXME: remove baked in underscore separator in field name
155
200
  def render_facet_rotate(field_name)
@@ -161,4 +206,5 @@ module Blacklight::HierarchyHelper
161
206
  new_params["#{prefix}_facet_order"] = new_order
162
207
  link_to image_tag('icons/rotate.png', title: new_order.upcase).html_safe, new_params, class: 'no-underline'
163
208
  end
209
+ deprecation_deprecate :render_facet_rotate
164
210
  end
@@ -0,0 +1 @@
1
+ HierarchicalFacetItem = Struct.new :qvalue, :value, :hits
@@ -1,3 +1,7 @@
1
- <ul class="facet-hierarchy">
1
+ <% Deprecation.warn(self, "Calling the blacklight/hierarchy/facet_hierarchy partial is " \
2
+ "deprecated and will be removed in blacklight-hierarchy 5.0. Replace the facet config for '#{facet_field.key}':\n\n\t" \
3
+ ":partial => 'blacklight/hierarchy/facet_hierarchy'\n\nwith:\n\n\t" \
4
+ ":component => Blacklight::Hierarchy::FacetFieldListComponent\n\n") %>
5
+ <ul class="facet-hierarchy" role="tree">
2
6
  <%= render_hierarchy(facet_field) %>
3
7
  </ul>
@@ -18,9 +18,9 @@ Gem::Specification.new do |s|
18
18
  s.executables = s.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
19
  s.require_paths = ['lib']
20
20
 
21
- s.add_dependency 'rails', '>= 4.1', '< 6'
22
- s.add_dependency 'jquery-rails'
23
- s.add_dependency 'blacklight', '~> 7.0'
21
+ s.add_dependency 'blacklight', '~> 7.13'
22
+ s.add_dependency 'rails', '>= 5.1', '< 7'
23
+ s.add_dependency 'deprecation'
24
24
 
25
25
  s.add_development_dependency 'rsolr'
26
26
  s.add_development_dependency 'rspec-rails'
@@ -0,0 +1,4 @@
1
+ ar:
2
+ blacklight:
3
+ hierarchy:
4
+ toggle_aria_label: تبديل المجموعة الفرعية
@@ -0,0 +1,4 @@
1
+ en:
2
+ blacklight:
3
+ hierarchy:
4
+ toggle_aria_label: Toggle subgroup
@@ -4,6 +4,8 @@ require 'rails'
4
4
  module Blacklight
5
5
  module Hierarchy
6
6
  class Engine < Rails::Engine
7
+ config.closed_icon = '⊞'
8
+ config.opened_icon = '⊟'
7
9
  end
8
10
  end
9
11
  end
@@ -1,5 +1,5 @@
1
1
  module Blacklight
2
2
  module Hierarchy
3
- VERSION = '3.0.0'.freeze
3
+ VERSION = '4.3.0'.freeze
4
4
  end
5
5
  end
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "blacklight-hierarchy",
3
- "version": "3.0.0",
3
+ "version": "4.1.0",
4
4
  "description": "[![Build Status](https://travis-ci.org/sul-dlss/blacklight-hierarchy.png?branch=master)](https://travis-ci.org/sul-dlss/blacklight-hierarchy)",
5
5
  "main": "app/assets/javascripts/blacklight/hierarchy/hierarchy.js",
6
6
  "files": [
7
- "app/assets/javascripts/blacklight/hierarchy/*.js"
7
+ "app/assets/javascripts/blacklight/hierarchy/*.js",
8
+ "app/assets/stylesheets/blacklight/hierarchy/*.scss"
8
9
  ],
9
10
  "repository": {
10
11
  "type": "git",
@@ -99,9 +99,8 @@ describe 'config_1' do
99
99
  before do
100
100
  CatalogController.blacklight_config = Blacklight::Configuration.new
101
101
  CatalogController.configure_blacklight do |config|
102
- # config.add_facet_field 'rotate_tag_facet', :label => 'Tag', :partial => 'blacklight/hierarchy/facet_hierarchy'
103
- config.add_facet_field 'tag_facet', label: 'Tag', partial: 'blacklight/hierarchy/facet_hierarchy'
104
- config.add_facet_field 'my_top_facet', label: 'Slash Delim', partial: 'blacklight/hierarchy/facet_hierarchy'
102
+ config.add_facet_field 'tag_facet', label: 'Tag', component: Blacklight::Hierarchy::FacetFieldListComponent
103
+ config.add_facet_field 'my_top_facet', label: 'Slash Delim', component: Blacklight::Hierarchy::FacetFieldListComponent
105
104
  config.facet_display = {
106
105
  hierarchy: {
107
106
  # 'rotate' => [['tag' ], ':'], # this would work if config.add_facet_field was called rotate_tag_facet, instead of tag_facet, I think.
@@ -119,8 +118,8 @@ describe 'config_2' do
119
118
  before do
120
119
  CatalogController.blacklight_config = Blacklight::Configuration.new
121
120
  CatalogController.configure_blacklight do |config|
122
- config.add_facet_field 'tag_facet', label: 'Tag', partial: 'blacklight/hierarchy/facet_hierarchy'
123
- config.add_facet_field 'my_top_facet', label: 'Slash Delim', partial: 'blacklight/hierarchy/facet_hierarchy'
121
+ config.add_facet_field 'tag_facet', label: 'Tag', component: Blacklight::Hierarchy::FacetFieldListComponent
122
+ config.add_facet_field 'my_top_facet', label: 'Slash Delim', component: Blacklight::Hierarchy::FacetFieldListComponent
124
123
  config.facet_display = {
125
124
  hierarchy: {
126
125
  'tag' => [['facet']], # rely on default delim
@@ -1,11 +1,20 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Blacklight::HierarchyHelper do
3
+ RSpec.describe Blacklight::HierarchyHelper do
4
4
  describe '#render_hierarchy' do
5
5
  it 'should remove the _suffix from the field name' do
6
+ expect(Deprecation).to receive(:warn)
6
7
  field = OpenStruct.new(field: 'the_field_name_facet')
7
8
  expect(helper).to receive(:facet_tree).with('the_field_name').and_return({})
8
9
  helper.render_hierarchy(field)
9
10
  end
10
11
  end
12
+
13
+ describe '#facet_toggle_button' do
14
+ subject { helper.facet_toggle_button(field_name, described_by) }
15
+ let(:field_name) { 'exploded_tag_ssim' }
16
+ let(:described_by) { 'unique-string' }
17
+
18
+ it { is_expected.to be_html_safe }
19
+ end
11
20
  end
@@ -17,4 +17,12 @@ class TestAppGenerator < Rails::Generators::Base
17
17
  def run_hierarchy_install
18
18
  generate 'blacklight_hierarchy:install'
19
19
  end
20
+
21
+ def create_images_directory
22
+ run 'mkdir app/assets/images'
23
+ end
24
+
25
+ def add_js_reference
26
+ inject_into_file 'app/assets/config/manifest.js', "\n//= link application.js", after: '//= link_directory ../stylesheets .css'
27
+ end
20
28
  end
metadata CHANGED
@@ -1,63 +1,63 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: blacklight-hierarchy
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 4.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael B. Klein
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-11-20 00:00:00.000000000 Z
11
+ date: 2020-12-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: rails
14
+ name: blacklight
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '4.1'
20
- - - "<"
17
+ - - "~>"
21
18
  - !ruby/object:Gem::Version
22
- version: '6'
19
+ version: '7.13'
23
20
  type: :runtime
24
21
  prerelease: false
25
22
  version_requirements: !ruby/object:Gem::Requirement
26
23
  requirements:
27
- - - ">="
28
- - !ruby/object:Gem::Version
29
- version: '4.1'
30
- - - "<"
24
+ - - "~>"
31
25
  - !ruby/object:Gem::Version
32
- version: '6'
26
+ version: '7.13'
33
27
  - !ruby/object:Gem::Dependency
34
- name: jquery-rails
28
+ name: rails
35
29
  requirement: !ruby/object:Gem::Requirement
36
30
  requirements:
37
31
  - - ">="
38
32
  - !ruby/object:Gem::Version
39
- version: '0'
33
+ version: '5.1'
34
+ - - "<"
35
+ - !ruby/object:Gem::Version
36
+ version: '7'
40
37
  type: :runtime
41
38
  prerelease: false
42
39
  version_requirements: !ruby/object:Gem::Requirement
43
40
  requirements:
44
41
  - - ">="
45
42
  - !ruby/object:Gem::Version
46
- version: '0'
43
+ version: '5.1'
44
+ - - "<"
45
+ - !ruby/object:Gem::Version
46
+ version: '7'
47
47
  - !ruby/object:Gem::Dependency
48
- name: blacklight
48
+ name: deprecation
49
49
  requirement: !ruby/object:Gem::Requirement
50
50
  requirements:
51
- - - "~>"
51
+ - - ">="
52
52
  - !ruby/object:Gem::Version
53
- version: '7.0'
53
+ version: '0'
54
54
  type: :runtime
55
55
  prerelease: false
56
56
  version_requirements: !ruby/object:Gem::Requirement
57
57
  requirements:
58
- - - "~>"
58
+ - - ">="
59
59
  - !ruby/object:Gem::Version
60
- version: '7.0'
60
+ version: '0'
61
61
  - !ruby/object:Gem::Dependency
62
62
  name: rsolr
63
63
  requirement: !ruby/object:Gem::Requirement
@@ -150,6 +150,7 @@ extensions: []
150
150
  extra_rdoc_files: []
151
151
  files:
152
152
  - ".coveralls.yml"
153
+ - ".github/workflows/ruby.yml"
153
154
  - ".gitignore"
154
155
  - ".rspec"
155
156
  - ".rubocop.yml"
@@ -159,14 +160,22 @@ files:
159
160
  - LICENSE
160
161
  - README.md
161
162
  - Rakefile
162
- - app/assets/images/collapsed.png
163
- - app/assets/images/expanded.png
164
163
  - app/assets/javascripts/blacklight/hierarchy/hierarchy.js
165
164
  - app/assets/stylesheets/blacklight/hierarchy/hierarchy.scss
165
+ - app/components/blacklight/hierarchy/facet_field_component.html.erb
166
+ - app/components/blacklight/hierarchy/facet_field_component.rb
167
+ - app/components/blacklight/hierarchy/facet_field_list_component.html.erb
168
+ - app/components/blacklight/hierarchy/facet_field_list_component.rb
169
+ - app/components/blacklight/hierarchy/qfacet_value_component.html.erb
170
+ - app/components/blacklight/hierarchy/qfacet_value_component.rb
171
+ - app/components/blacklight/hierarchy/selected_qfacet_value_component.html.erb
172
+ - app/components/blacklight/hierarchy/selected_qfacet_value_component.rb
166
173
  - app/helpers/blacklight/hierarchy_helper.rb
174
+ - app/models/hierarchical_facet_item.rb
167
175
  - app/views/blacklight/hierarchy/_facet_hierarchy.html.erb
168
- - app/views/blacklight/hierarchy/_facet_hierarchy_item.html.erb
169
176
  - blacklight-hierarchy.gemspec
177
+ - config/locales/blacklight-hierarchy.ar.yml
178
+ - config/locales/blacklight-hierarchy.en.yml
170
179
  - lib/blacklight-hierarchy.rb
171
180
  - lib/blacklight/hierarchy.rb
172
181
  - lib/blacklight/hierarchy/engine.rb
@@ -199,7 +208,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
199
208
  - !ruby/object:Gem::Version
200
209
  version: '0'
201
210
  requirements: []
202
- rubygems_version: 3.0.3
211
+ rubygems_version: 3.1.4
203
212
  signing_key:
204
213
  specification_version: 4
205
214
  summary: Hierarchical Facets for Blacklight
@@ -1,25 +0,0 @@
1
- <%
2
- item = data[:_]
3
- subset = data.reject { |k,v| ! k.is_a?(String) }
4
- %>
5
-
6
- <li class="<%= subset.empty? ? 'h-leaf' : 'h-node' %>">
7
- <% if item.nil? %>
8
- <%= key %>
9
- <% else %>
10
- <% if facet_in_params?(field_name, item.qvalue) %>
11
- <%= render_selected_qfacet_value( field_name, item )%>
12
- <% else %>
13
- <%= render_qfacet_value(field_name, item) %>
14
- <% end %>
15
- <% end %>
16
- <% unless subset.empty? %>
17
- <ul>
18
- <%=
19
- raw(subset.keys.sort.collect { |subkey|
20
- render :partial => 'facet_hierarchy_item', :locals => { :field_name => field_name, :data => subset[subkey], :key => subkey }
21
- })
22
- %>
23
- </ul>
24
- <% end %>
25
- </li>