blacklight-hierarchy 4.1.0 → 5.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9ce7107c42527b0098cfbf8fc89cf72513f60c37ffd747e2dc72d7562cbc0cb0
4
- data.tar.gz: 0471c190b5e16bba1db3b5b5b4e5234f7f52f2eaf4604924aa6cc219f0b60126
3
+ metadata.gz: '05896464df5a8c0e3b6d878771afb366c74eb679a9acbb3cc91b48fc1ec21a67'
4
+ data.tar.gz: f6544b27132185268d971b49e634b6f83a4ad8986e78014f65cc121d233a7fb1
5
5
  SHA512:
6
- metadata.gz: 8f17e9a79fdb08d46e858b447d75624ea349960ee6f80a7c130bf58098c37844aeac5684ec8b0afa338c0d314ee864192d022ea98c2088f599718cf5ac506797
7
- data.tar.gz: a389b8951e4e93338f54a9b624a3f0f4cae267cd8a5f1de5296a3d2e13ac06bfc636808695b1fd8d2aa8e8e64faadc6680c888185cff03eb2bf1e1fd0b3b73af
6
+ metadata.gz: e239a2df4fac7caf7a0cce0917fd361c04c1a29ba904246275a592769ede706425cf8a4573c2734829f402f43555c76d3b8b393b6a645350644e4aabe60d5659
7
+ data.tar.gz: c727ad909a5820f59e4484ef3cf517ade8e48ec61646b943d79f1a52991e2eff290a73bc2033f00bfe62d418ddedc1ebb138fa9f246fc8713857cca1aff34028
@@ -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: [ main ]
13
+ pull_request:
14
+ branches: [ main ]
15
+
16
+ jobs:
17
+ test:
18
+ runs-on: ubuntu-latest
19
+ strategy:
20
+ matrix:
21
+ ruby: [2.7, 3.0]
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.7, 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'
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # Blacklight::Hierarchy
2
- [![Build Status](https://travis-ci.org/sul-dlss/blacklight-hierarchy.svg?branch=master)](https://travis-ci.org/sul-dlss/blacklight-hierarchy) [![Coverage Status](https://coveralls.io/repos/sul-dlss/blacklight-hierarchy/badge.png)](https://coveralls.io/r/sul-dlss/blacklight-hierarchy) [![Gem Version](https://badge.fury.io/rb/blacklight-hierarchy.svg)](http://badge.fury.io/rb/blacklight-hierarchy)
2
+ [![Build Status](https://github.com/sul-dlss/blacklight-hierarchy/workflows/CI/badge.svg)](https://github.com/sul-dlss/blacklight-hierarchy/actions?query=branch%3Amain) [![Coverage Status](https://coveralls.io/repos/sul-dlss/blacklight-hierarchy/badge.png)](https://coveralls.io/r/sul-dlss/blacklight-hierarchy) [![Gem Version](https://badge.fury.io/rb/blacklight-hierarchy.svg)](http://badge.fury.io/rb/blacklight-hierarchy)
3
3
 
4
4
  This plugin provides hierarchical facets for [Blacklight](https://github.com/projectblacklight/blacklight).
5
5
 
@@ -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:
@@ -106,6 +106,10 @@ en:
106
106
  toggle_aria_label: Toggle call number section
107
107
  ```
108
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
+
109
113
  ## Caveats
110
114
 
111
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.
@@ -0,0 +1,12 @@
1
+ import { Controller } from 'stimulus'
2
+
3
+ export default class extends Controller {
4
+ static targets = [ "list" ]
5
+ connect() {
6
+ this.element.classList.add("twiddle")
7
+ }
8
+
9
+ toggle() {
10
+ this.element.classList.toggle("twiddle-open")
11
+ }
12
+ }
@@ -8,27 +8,23 @@ Blacklight.onLoad(function(){
8
8
  Blacklight.hierarchical_facet_expand_contract
9
9
  );
10
10
  }
11
- Blacklight.do_hierarchical_facet_expand_contract_behavior.selector = 'li.h-node';
11
+ Blacklight.do_hierarchical_facet_expand_contract_behavior.selector = '[data-controller="b-h-collapsible"]';
12
+ Blacklight.do_hierarchical_facet_expand_contract_behavior.handle = '[data-action="click->b-h-collapsible#toggle"]';
13
+ Blacklight.do_hierarchical_facet_expand_contract_behavior.list = '[data-b-h-collapsible-target="list"]';
12
14
 
13
15
  Blacklight.hierarchical_facet_expand_contract = function() {
14
16
  var li = $(this);
17
+ li.addClass('twiddle');
15
18
 
16
- $('ul', this).each(function() {
17
- li.addClass('twiddle');
18
- if($('span.selected', this).length == 0){
19
- $(this).hide();
20
- } else {
19
+ $(Blacklight.do_hierarchical_facet_expand_contract_behavior.list, this).each(function() {
20
+ if($('span.selected', this).length != 0){
21
21
  li.addClass('twiddle-open');
22
- li.children('.toggle-handle').attr('aria-expanded', 'true');
23
22
  }
24
23
  });
25
24
 
26
25
  // attach the toggle behavior to the li tag
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();
26
+ li.children(Blacklight.do_hierarchical_facet_expand_contract_behavior.handle).click(function(e){
27
+ li.toggleClass('twiddle-open');
32
28
  });
33
29
  };
34
30
  })(jQuery);
@@ -0,0 +1,19 @@
1
+ <li class="<%= li_class %>" data-controller="<%= controller_name %>" role="treeitem">
2
+ <% ul_id = "b-h-#{SecureRandom.alphanumeric(10)}" %>
3
+ <%= helpers.facet_toggle_button(field_name, id, ul_id) if subset.any? %>
4
+ <% if item.nil? %>
5
+ <%= key %>
6
+ <% elsif qfacet_selected? %>
7
+ <%= render Blacklight::Hierarchy::SelectedQfacetValueComponent.new(field_name: field_name, item: item) %>
8
+ <% else %>
9
+ <%= render Blacklight::Hierarchy::QfacetValueComponent.new(field_name: field_name, item: item, id: id) %>
10
+ <% end %>
11
+
12
+ <% unless subset.empty? %>
13
+ <ul id="<%= ul_id %>" class="collapse" data-b-h-collapsible-target="list" role=\"group\">
14
+ <% subset.keys.sort.each do |subkey| %>
15
+ <%= render self.class.new(field_name: field_name, tree: subset[subkey], key: subkey) %>
16
+ <% end %>
17
+ </ul>
18
+ <% end %>
19
+ </li>
@@ -0,0 +1,38 @@
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 controller_name
24
+ subset.empty? ? '' : 'b-h-collapsible'
25
+ end
26
+
27
+
28
+ def item
29
+ tree[:_]
30
+ end
31
+
32
+ def qfacet_selected?
33
+ config = helpers.facet_configuration_for_field(field_name)
34
+ helpers.search_state.filter(config).include?(item.qvalue)
35
+ end
36
+ end
37
+ end
38
+ 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,51 @@
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
+
12
+ @tree ||= begin
13
+ facet_tree_for_prefix = FacetTree.build(prefix: prefix,
14
+ facet_display: blacklight_config.facet_display,
15
+ facet_field: @facet_field)
16
+ facet_tree_for_prefix ? facet_tree_for_prefix[field_name] : nil
17
+ end
18
+ end
19
+
20
+ def field_name
21
+ @facet_field.facet_field.field
22
+ end
23
+
24
+ # @return [String] a key to access the rest of the hierarchy tree, as defined in controller config.facet_display[:hierarchy] declaration.
25
+ # e.g. if you had this in controller:
26
+ # config.facet_display = {
27
+ # :hierarchy => {
28
+ # 'wf' => [['wps','wsp','swp'], ':'],
29
+ # 'callnum_top' => [['facet'], '/'],
30
+ # 'exploded_tag' => [['ssim'], ':']
31
+ # }
32
+ # }
33
+ # then possible hkey values would be 'wf', 'callnum_top', and 'exploded_tag'.
34
+ #
35
+ # the key in the :hierarchy hash is the "prefix" for the solr field with the hierarchy info. the value
36
+ # in the hash is a list, where the first element is a list of suffixes, and the second element is the delimiter
37
+ # used to break up the sections of hierarchical data in the solr field being read. when joined, the prefix and
38
+ # suffix should form the field name. so, for example, 'wf_wps', 'wf_wsp', 'wf_swp', 'callnum_top_facet', and
39
+ # 'exploded_tag_ssim' would be the solr fields with blacklight-hierarchy related configuration according to the
40
+ # hash above. ':' would be the delimiter used in all of those fields except for 'callnum_top_facet', which would
41
+ # use '/'. exploded_tag_ssim might contain values like ['Book', 'Book : Multi-Volume Work'], and callnum_top_facet
42
+ # might contain values like ['LB', 'LB/2395', 'LB/2395/.C65', 'LB/2395/.C65/1991'].
43
+ # note: the suffixes (e.g. 'ssim' for 'exploded_tag' in the above example) can't have underscores, otherwise things break.
44
+ def prefix
45
+ @prefix ||= field_name.gsub("#{DELIMETER}#{field_name.split(/#{DELIMETER}/).last}", '')
46
+ end
47
+
48
+ delegate :blacklight_config, to: :helpers
49
+ end
50
+ end
51
+ 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,5 @@
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="remove-icon" aria-hidden="true">✖</span>
4
+ <span class="sr-only"><%= t('blacklight.search.facets.selected.remove') %></span>
5
+ <% 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,186 +1,36 @@
1
- module Blacklight::HierarchyHelper
2
- # Putting bare HTML strings in a helper sucks. But in this case, with a
3
- # lot of recursive tree-walking going on, it's an order of magnitude faster
4
- # than either render(:partial) or content_tag
5
- def render_facet_hierarchy_item(field_name, data, key)
6
- item = data[:_]
7
- subset = data.reject { |k, _v| !k.is_a?(String) }
8
-
9
- li_class = subset.empty? ? 'h-leaf' : 'h-node'
10
- id = SecureRandom.uuid
11
- ul = ''
12
- li = ''
13
- li << facet_toggle_button(field_name, id) if subset.any?
14
- li << if item.nil?
15
- key
16
- elsif facet_in_params?(field_name, item.qvalue)
17
- render_selected_qfacet_value(field_name, item)
18
- else
19
- render_qfacet_value(field_name, item, id: id)
20
- end
21
-
22
- unless subset.empty?
23
- subul = subset.keys.sort.collect do |subkey|
24
- render_facet_hierarchy_item(field_name, subset[subkey], subkey)
25
- end.join('')
26
- ul = "<ul role=\"group\">#{subul}</ul>".html_safe
27
- end
28
-
29
- %(<li class="#{li_class}" role="treeitem">#{li.html_safe}#{ul.html_safe}</li>).html_safe
30
- end
31
-
32
- # @param [Blacklight::Configuration::FacetField] as defined in controller with config.add_facet_field (and with :partial => 'blacklight/hierarchy/facet_hierarchy')
33
- # @return [String] html for the facet tree
34
- def render_hierarchy(bl_facet_field, delim = '_')
35
- field_name = bl_facet_field.field
36
- prefix = field_name.gsub("#{delim}#{field_name.split(/#{delim}/).last}", '')
37
- facet_tree_for_prefix = facet_tree(prefix)
38
- tree = facet_tree_for_prefix ? facet_tree_for_prefix[field_name] : nil
39
-
40
- return '' unless tree
41
- tree.keys.sort.collect do |key|
42
- render_facet_hierarchy_item(field_name, tree[key], key)
43
- end.join("\n").html_safe
44
- end
45
-
46
- def render_qfacet_value(facet_solr_field, item, options = {})
47
- id = options.delete(:id)
48
- (link_to_unless(options[:suppress_link], item.value, path_for_facet(facet_solr_field, item.qvalue), id: id, class: 'facet_select') + ' ' + render_facet_count(item.hits)).html_safe
49
- end
50
-
51
- # Standard display of a SELECTED facet value, no link, special span with class, and 'remove' button.
52
- def render_selected_qfacet_value(facet_solr_field, item)
53
- remove_href = search_action_path(search_state.remove_facet_params(facet_solr_field, item.qvalue))
54
- content_tag(:span, render_qfacet_value(facet_solr_field, item, suppress_link: true), class: 'selected') + ' ' +
55
- link_to(content_tag(:span, '', class: 'glyphicon glyphicon-remove') +
56
- content_tag(:span, '[remove]', class: 'sr-only'),
57
- remove_href,
58
- class: 'remove'
59
- )
60
- end
61
-
62
- HierarchicalFacetItem = Struct.new :qvalue, :value, :hits
63
-
64
- # @param [String] hkey - a key to access the rest of the hierarchy tree, as defined in controller config.facet_display[:hierarchy] declaration.
65
- # e.g. if you had this in controller:
66
- # config.facet_display = {
67
- # :hierarchy => {
68
- # 'wf' => [['wps','wsp','swp'], ':'],
69
- # 'callnum_top' => [['facet'], '/'],
70
- # 'exploded_tag' => [['ssim'], ':']
71
- # }
72
- # }
73
- # then possible hkey values would be 'wf', 'callnum_top', and 'exploded_tag'.
74
- #
75
- # the key in the :hierarchy hash is the "prefix" for the solr field with the hierarchy info. the value
76
- # in the hash is a list, where the first element is a list of suffixes, and the second element is the delimiter
77
- # used to break up the sections of hierarchical data in the solr field being read. when joined, the prefix and
78
- # suffix should form the field name. so, for example, 'wf_wps', 'wf_wsp', 'wf_swp', 'callnum_top_facet', and
79
- # 'exploded_tag_ssim' would be the solr fields with blacklight-hierarchy related configuration according to the
80
- # hash above. ':' would be the delimiter used in all of those fields except for 'callnum_top_facet', which would
81
- # use '/'. exploded_tag_ssim might contain values like ['Book', 'Book : Multi-Volume Work'], and callnum_top_facet
82
- # might contain values like ['LB', 'LB/2395', 'LB/2395/.C65', 'LB/2395/.C65/1991'].
83
- # note: the suffixes (e.g. 'ssim' for 'exploded_tag' in the above example) can't have underscores, otherwise things break.
84
- def facet_tree(hkey)
85
- @facet_tree ||= {}
86
- return @facet_tree[hkey] unless @facet_tree[hkey].nil?
87
- return @facet_tree[hkey] unless blacklight_config.facet_display[:hierarchy] && blacklight_config.facet_display[:hierarchy][hkey]
88
- @facet_tree[hkey] = {}
89
- facet_config = blacklight_config.facet_display[:hierarchy][hkey]
90
- split_regex = Regexp.new("\s*#{Regexp.escape(facet_config.length >= 2 ? facet_config[1] : ':')}\s*")
91
- facet_config.first.each do |key|
92
- # TODO: remove baked in notion of underscores being part of the blacklight facet field names
93
- facet_field = [hkey, key].compact.join('_')
94
- @facet_tree[hkey][facet_field] ||= {}
95
- data = @response.aggregations[facet_field]
96
- next if data.nil?
97
- data.items.each do |facet_item|
98
- path = facet_item.value.split(split_regex)
99
- loc = @facet_tree[hkey][facet_field]
100
- loc = loc[path.shift] ||= {} while path.length > 0
101
- loc[:_] = HierarchicalFacetItem.new(facet_item.value, facet_item.value.split(split_regex).last, facet_item.hits)
102
- end
103
- end
104
- @facet_tree[hkey]
105
- end
1
+ # frozen_string_literal: true
106
2
 
107
- def facet_toggle_button(field_name, described_by)
3
+ module Blacklight::HierarchyHelper
4
+ def facet_toggle_button(field_name, described_by, controls)
108
5
  aria_label = I18n.t(
109
6
  "blacklight.hierarchy.#{field_name}_toggle_aria_label",
110
7
  default: :'blacklight.hierarchy.toggle_aria_label'
111
8
  )
112
- <<-HTML
113
- <button
114
- aria-expanded="false"
115
- aria-label="#{aria_label}"
116
- aria-describedby="#{described_by}"
117
- class="toggle-handle"
118
- >
119
- <span aria-hidden="true" class="closed">#{Blacklight::Hierarchy::Engine.config.closed_icon}</span>
120
- <span aria-hidden="true" class="opened">#{Blacklight::Hierarchy::Engine.config.opened_icon}</span>
121
- </button>
122
- HTML
9
+
10
+ # For Rails 5.2 support all options must be symbols. See https://github.com/rails/rails/issues/39813
11
+ tag.button(aria: {
12
+ expanded: 'false',
13
+ label: aria_label,
14
+ describedby: described_by,
15
+ controls: controls
16
+ },
17
+ data: {
18
+ action: 'click->b-h-collapsible#toggle',
19
+ toggle: 'collapse',
20
+ target: "##{controls}"
21
+ },
22
+ class: 'toggle-handle') do
23
+ tag.span(Blacklight::Hierarchy::Engine.config.closed_icon, :'aria-hidden' => 'true', class: 'closed') +
24
+ tag.span(Blacklight::Hierarchy::Engine.config.opened_icon, :'aria-hidden' => 'true', class: 'opened')
25
+ end
123
26
  end
124
27
 
125
28
  # --------------------------------------------------------------------------------------------------------------------------------
126
29
  # below are methods pertaining to the "rotate" notion where you may want to look at the same tree data organized another way
127
30
  # --------------------------------------------------------------------------------------------------------------------------------
128
31
 
129
- # FIXME: remove baked in underscore separator in field name
130
- def is_hierarchical?(field_name)
131
- (prefix, order) = field_name.split(/_/, 2)
132
- (list = blacklight_config.facet_display[:hierarchy][prefix]) && list.include?(order)
133
- end
134
-
135
- def facet_order(prefix)
136
- param_name = "#{prefix}_facet_order".to_sym
137
- params[param_name] || blacklight_config.facet_display[:hierarchy][prefix].first
138
- end
139
-
140
32
  def facet_after(prefix, order)
141
33
  orders = blacklight_config.facet_display[:hierarchy][prefix]
142
34
  orders[orders.index(order) + 1] || orders.first
143
35
  end
144
-
145
- # FIXME: remove baked in underscore separator in field name
146
- def hide_facet?(field_name)
147
- return false unless is_hierarchical?(field_name)
148
- prefix = field_name.split(/_/).first
149
- field_name != "#{prefix}_#{facet_order(prefix)}"
150
- end
151
-
152
- # FIXME: remove baked in colon separator
153
- def rotate_facet_value(val, from, to)
154
- components = Hash[from.split(//).zip(val.split(/:/))]
155
- new_values = components.values_at(*to.split(//))
156
- new_values.pop while new_values.last.nil?
157
- return nil if new_values.include?(nil)
158
- new_values.compact.join(':')
159
- end
160
-
161
- # FIXME: remove baked in underscore separator in field name
162
- def rotate_facet_params(prefix, from, to, p = params.dup)
163
- return p if from == to
164
- from_field = "#{prefix}_#{from}"
165
- to_field = "#{prefix}_#{to}"
166
- p[:f] = (p[:f] || {}).dup # the command above is not deep in rails3, !@#$!@#$
167
- p[:f][from_field] = (p[:f][from_field] || []).dup
168
- p[:f][to_field] = (p[:f][to_field] || []).dup
169
- p[:f][from_field].reject! { |v| p[:f][to_field] << rotate_facet_value(v, from, to); true }
170
- p[:f].delete(from_field)
171
- p[:f][to_field].compact!
172
- p[:f].delete(to_field) if p[:f][to_field].empty?
173
- p
174
- end
175
-
176
- # FIXME: remove baked in underscore separator in field name
177
- def render_facet_rotate(field_name)
178
- return unless is_hierarchical?(field_name)
179
- (prefix, order) = field_name.split(/_/, 2)
180
- return if blacklight_config.facet_display[:hierarchy][prefix].length < 2
181
- new_order = facet_after(prefix, order)
182
- new_params = rotate_facet_params(prefix, order, new_order)
183
- new_params["#{prefix}_facet_order"] = new_order
184
- link_to image_tag('icons/rotate.png', title: new_order.upcase).html_safe, new_params, class: 'no-underline'
185
- end
186
36
  end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Blacklight
4
+ module Hierarchy
5
+ class FacetTree
6
+ def self.build(prefix:, facet_display:, facet_field:)
7
+ new(prefix: prefix, facet_display: facet_display, facet_field: facet_field).build
8
+ end
9
+
10
+ def initialize(prefix:, facet_display:, facet_field:)
11
+ @prefix = prefix
12
+ @facet_config = facet_display.dig(:hierarchy, prefix)
13
+ @facet_field = facet_field
14
+ end
15
+
16
+ attr_reader :prefix, :facet_config, :data
17
+
18
+ def build
19
+ return unless facet_config
20
+ {}.tap do |tree|
21
+ facet_config.first.each do |key|
22
+ # TODO: remove baked in notion of underscores being part of the blacklight facet field names
23
+ facet_field = [prefix, key].compact.join('_')
24
+ tree[facet_field] ||= {}
25
+ data = @facet_field.display_facet
26
+ next if data.nil?
27
+ data.items.each do |facet_item|
28
+ path = facet_item.value.split(split_regex)
29
+ loc = tree[facet_field]
30
+ loc = loc[path.shift] ||= {} while path.length > 0
31
+ loc[:_] = HierarchicalFacetItem.new(facet_item.value, facet_item.value.split(split_regex).last, facet_item.hits)
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ def split_regex
38
+ @split_regex ||= Regexp.new("\s*#{Regexp.escape(facet_config.length >= 2 ? facet_config[1] : ':')}\s*")
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1 @@
1
+ HierarchicalFacetItem = Struct.new :qvalue, :value, :hits
@@ -1,3 +1,7 @@
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") %>
1
5
  <ul class="facet-hierarchy" role="tree">
2
6
  <%= render_hierarchy(facet_field) %>
3
7
  </ul>
@@ -18,10 +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
- # Most likely available for even earlier versions of Blacklight, but this is what I validated
22
- s.add_dependency 'blacklight', '> 6.20', '< 8.0'
21
+ s.add_dependency 'blacklight', '~> 7.13'
23
22
  s.add_dependency 'rails', '>= 5.1', '< 7'
24
- s.add_dependency 'jquery-rails'
23
+ s.add_dependency 'deprecation'
25
24
 
26
25
  s.add_development_dependency 'rsolr'
27
26
  s.add_development_dependency 'rspec-rails'
@@ -1,5 +1,5 @@
1
1
  module Blacklight
2
2
  module Hierarchy
3
- VERSION = '4.1.0'.freeze
3
+ VERSION = '5.1.0'.freeze
4
4
  end
5
5
  end
@@ -1 +1,9 @@
1
- //= require blacklight/hierarchy/hierarchy
1
+ //= require blacklight/hierarchy/hierarchy
2
+
3
+ // If you use Stimulus in your application you can remove the line above and require
4
+ // blacklight_hierarchy_controller instead:
5
+ //
6
+ // import BlacklightHierarchyController from 'blacklight-hierarchy/app/assets/javascripts/blacklight/hierarchy/blacklight_hierarchy_controller'
7
+ // import { Application } from 'stimulus'
8
+ // const application = Application.start()
9
+ // application.register("b-h-collapsible", BlacklightHierarchyController)
data/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "blacklight-hierarchy",
3
- "version": "4.1.0",
4
- "description": "[![Build Status](https://travis-ci.org/sul-dlss/blacklight-hierarchy.png?branch=master)](https://travis-ci.org/sul-dlss/blacklight-hierarchy)",
3
+ "version": "5.1.0",
4
+ "description": "[![Build Status](https://github.com/sul-dlss/blacklight-hierarchy/workflows/CI/badge.svg)](https://github.com/sul-dlss/blacklight-hierarchy/actions?query=branch%3Amain)",
5
5
  "main": "app/assets/javascripts/blacklight/hierarchy/hierarchy.js",
6
6
  "files": [
7
7
  "app/assets/javascripts/blacklight/hierarchy/*.js",
@@ -31,8 +31,8 @@ shared_examples 'catalog' do
31
31
 
32
32
  it 'should display the hierarchy' do
33
33
  visit '/'
34
- expect(page).to have_selector('li.h-node', text: 'a')
35
- expect(page).to have_selector('li.h-node > ul > li.h-node', text: 'b')
34
+ expect(page).to have_selector('li.h-node[data-controller="b-h-collapsible"]', text: 'a')
35
+ expect(page).to have_selector('li.h-node > ul > li.h-node[data-controller="b-h-collapsible"]', text: 'b')
36
36
  expect(page).to have_selector('li.h-node li.h-leaf', text: 'c 30')
37
37
  expect(page).to have_selector('li.h-node li.h-leaf', text: 'd 25')
38
38
  expect(page).to have_selector('li.h-node > ul > li.h-node', text: 'c')
@@ -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,11 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Blacklight::HierarchyHelper do
4
- describe '#render_hierarchy' do
5
- it 'should remove the _suffix from the field name' do
6
- field = OpenStruct.new(field: 'the_field_name_facet')
7
- expect(helper).to receive(:facet_tree).with('the_field_name').and_return({})
8
- helper.render_hierarchy(field)
9
- end
3
+ RSpec.describe Blacklight::HierarchyHelper do
4
+ describe '#facet_toggle_button' do
5
+ subject { helper.facet_toggle_button(field_name, described_by, 'randomtext123') }
6
+ let(:field_name) { 'exploded_tag_ssim' }
7
+ let(:described_by) { 'unique-string' }
8
+
9
+ it { is_expected.to be_html_safe }
10
10
  end
11
11
  end
metadata CHANGED
@@ -1,35 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: blacklight-hierarchy
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.0
4
+ version: 5.1.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: 2020-05-21 00:00:00.000000000 Z
11
+ date: 2021-04-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: blacklight
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">"
18
- - !ruby/object:Gem::Version
19
- version: '6.20'
20
- - - "<"
17
+ - - "~>"
21
18
  - !ruby/object:Gem::Version
22
- version: '8.0'
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: '6.20'
30
- - - "<"
24
+ - - "~>"
31
25
  - !ruby/object:Gem::Version
32
- version: '8.0'
26
+ version: '7.13'
33
27
  - !ruby/object:Gem::Dependency
34
28
  name: rails
35
29
  requirement: !ruby/object:Gem::Requirement
@@ -51,7 +45,7 @@ dependencies:
51
45
  - !ruby/object:Gem::Version
52
46
  version: '7'
53
47
  - !ruby/object:Gem::Dependency
54
- name: jquery-rails
48
+ name: deprecation
55
49
  requirement: !ruby/object:Gem::Requirement
56
50
  requirements:
57
51
  - - ">="
@@ -156,18 +150,29 @@ extensions: []
156
150
  extra_rdoc_files: []
157
151
  files:
158
152
  - ".coveralls.yml"
153
+ - ".github/workflows/ruby.yml"
159
154
  - ".gitignore"
160
155
  - ".rspec"
161
156
  - ".rubocop.yml"
162
157
  - ".rubocop_todo.yml"
163
- - ".travis.yml"
164
158
  - Gemfile
165
159
  - LICENSE
166
160
  - README.md
167
161
  - Rakefile
162
+ - app/assets/javascripts/blacklight/hierarchy/blacklight_hierarchy_controller.js
168
163
  - app/assets/javascripts/blacklight/hierarchy/hierarchy.js
169
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
170
173
  - app/helpers/blacklight/hierarchy_helper.rb
174
+ - app/models/blacklight/hierarchy/facet_tree.rb
175
+ - app/models/hierarchical_facet_item.rb
171
176
  - app/views/blacklight/hierarchy/_facet_hierarchy.html.erb
172
177
  - blacklight-hierarchy.gemspec
173
178
  - config/locales/blacklight-hierarchy.ar.yml
@@ -204,7 +209,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
204
209
  - !ruby/object:Gem::Version
205
210
  version: '0'
206
211
  requirements: []
207
- rubygems_version: 3.1.2
212
+ rubygems_version: 3.1.4
208
213
  signing_key:
209
214
  specification_version: 4
210
215
  summary: Hierarchical Facets for Blacklight
data/.travis.yml DELETED
@@ -1,8 +0,0 @@
1
- language: ruby
2
- sudo: false
3
- rvm:
4
- - 2.5.1
5
-
6
- env:
7
- global:
8
- - NOKOGIRI_USE_SYSTEM_LIBRARIES=true