blacklight-hierarchy 4.2.0 → 5.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +53 -0
- data/README.md +1 -1
- data/app/assets/javascripts/blacklight/hierarchy/blacklight_hierarchy_controller.js +12 -0
- data/app/assets/javascripts/blacklight/hierarchy/hierarchy.js +8 -12
- data/app/components/blacklight/hierarchy/facet_field_component.html.erb +4 -3
- data/app/components/blacklight/hierarchy/facet_field_component.rb +6 -1
- data/app/components/blacklight/hierarchy/facet_field_list_component.html.erb +2 -2
- data/app/components/blacklight/hierarchy/facet_field_list_component.rb +4 -25
- data/app/components/blacklight/hierarchy/selected_qfacet_value_component.html.erb +3 -2
- data/app/helpers/blacklight/hierarchy_helper.rb +19 -189
- data/app/models/blacklight/hierarchy/facet_tree.rb +42 -0
- data/blacklight-hierarchy.gemspec +1 -2
- data/lib/blacklight/hierarchy/version.rb +1 -1
- data/lib/generators/blacklight_hierarchy/templates/blacklight_hierarchy.js +9 -1
- data/package.json +2 -2
- data/spec/features/basic_spec.rb +2 -2
- data/spec/helpers/hierarchy_helper_spec.rb +7 -8
- metadata +8 -6
- data/.travis.yml +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5ea0e001e3224b9a048ae7926b34382fe198ca6e8fdf76c5162db41b9517275c
|
4
|
+
data.tar.gz: adc4876dacf6a6d1a7aace70b94b673b1f309923e3cf18c26ab580fb706273c1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e807065e18dade227ffacd4569aa6a63219319d75c5cfc30619fd9f831f482d612eeb8ec86518d966aed33a78dc3eacad9a777ed2410eb8a0e6506db6b848ab5
|
7
|
+
data.tar.gz: b14642993987dce24ce443efb75c1dccba8e2fea2118c5860f2b938a4c55b1ac3dc1a6292102c677e105b203589a470322166dfe0439544ba49573fba9d0334e
|
@@ -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://
|
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
|
|
@@ -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 = '
|
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
|
-
$(
|
17
|
-
|
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(
|
28
|
-
|
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);
|
@@ -1,5 +1,6 @@
|
|
1
|
-
<li class="<%= li_class %>" role="treeitem">
|
2
|
-
|
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? %>
|
3
4
|
<% if item.nil? %>
|
4
5
|
<%= key %>
|
5
6
|
<% elsif qfacet_selected? %>
|
@@ -9,7 +10,7 @@
|
|
9
10
|
<% end %>
|
10
11
|
|
11
12
|
<% unless subset.empty? %>
|
12
|
-
<ul role=\"group\">
|
13
|
+
<ul id="<%= ul_id %>" class="collapse" data-b-h-collapsible-target="list" role=\"group\">
|
13
14
|
<% subset.keys.sort.each do |subkey| %>
|
14
15
|
<%= render self.class.new(field_name: field_name, tree: subset[subkey], key: subkey) %>
|
15
16
|
<% end %>
|
@@ -20,13 +20,18 @@ module Blacklight
|
|
20
20
|
subset.empty? ? 'h-leaf' : 'h-node'
|
21
21
|
end
|
22
22
|
|
23
|
+
def controller_name
|
24
|
+
subset.empty? ? '' : 'b-h-collapsible'
|
25
|
+
end
|
26
|
+
|
27
|
+
|
23
28
|
def item
|
24
29
|
tree[:_]
|
25
30
|
end
|
26
31
|
|
27
32
|
def qfacet_selected?
|
28
33
|
config = helpers.facet_configuration_for_field(field_name)
|
29
|
-
helpers.search_state.
|
34
|
+
helpers.search_state.filter(config).include?(item.qvalue)
|
30
35
|
end
|
31
36
|
end
|
32
37
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
<%= render(@layout.new(facet_field: @facet_field)) do |component| %>
|
2
|
-
<% component.
|
2
|
+
<% component.label do %>
|
3
3
|
<%= @facet_field.label %>
|
4
4
|
<% end %>
|
5
|
-
<% component.
|
5
|
+
<% component.body do %>
|
6
6
|
<ul class="facet-hierarchy" role="tree">
|
7
7
|
<% tree.keys.sort.collect do |key| %>
|
8
8
|
<%= render Blacklight::Hierarchy::FacetFieldComponent.new(field_name: @facet_field.facet_field.field, tree: tree[key], key: key) %>
|
@@ -8,8 +8,11 @@ module Blacklight
|
|
8
8
|
# @param [Blacklight::Configuration::FacetField] as defined in controller with config.add_facet_field (and with :partial => 'blacklight/hierarchy/facet_hierarchy')
|
9
9
|
# @return [String] html for the facet tree
|
10
10
|
def tree
|
11
|
+
|
11
12
|
@tree ||= begin
|
12
|
-
facet_tree_for_prefix =
|
13
|
+
facet_tree_for_prefix = FacetTree.build(prefix: prefix,
|
14
|
+
facet_display: blacklight_config.facet_display,
|
15
|
+
facet_field: @facet_field)
|
13
16
|
facet_tree_for_prefix ? facet_tree_for_prefix[field_name] : nil
|
14
17
|
end
|
15
18
|
end
|
@@ -42,31 +45,7 @@ module Blacklight
|
|
42
45
|
@prefix ||= field_name.gsub("#{DELIMETER}#{field_name.split(/#{DELIMETER}/).last}", '')
|
43
46
|
end
|
44
47
|
|
45
|
-
|
46
48
|
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
49
|
end
|
71
50
|
end
|
72
51
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
<span class="selected"><%= render Blacklight::Hierarchy::QfacetValueComponent.new(field_name: field_name, item: item, suppress_link: true) %></span>
|
2
|
-
<%= link_to
|
3
|
-
<span class="
|
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>
|
4
5
|
<% end %>
|
@@ -1,206 +1,36 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Blacklight::HierarchyHelper
|
4
|
-
|
5
|
-
# lot of recursive tree-walking going on, it's an order of magnitude faster
|
6
|
-
# than either render(:partial) or content_tag
|
7
|
-
def render_facet_hierarchy_item(field_name, data, key)
|
8
|
-
item = data[:_]
|
9
|
-
subset = data.reject { |k, _v| !k.is_a?(String) }
|
10
|
-
|
11
|
-
li_class = subset.empty? ? 'h-leaf' : 'h-node'
|
12
|
-
id = SecureRandom.uuid
|
13
|
-
ul = ''
|
14
|
-
li = ''
|
15
|
-
li << facet_toggle_button(field_name, id) if subset.any?
|
16
|
-
li << if item.nil?
|
17
|
-
key
|
18
|
-
elsif qfacet_selected?(field_name, item)
|
19
|
-
render_selected_qfacet_value(field_name, item)
|
20
|
-
else
|
21
|
-
render_qfacet_value(field_name, item, id: id)
|
22
|
-
end
|
23
|
-
|
24
|
-
unless subset.empty?
|
25
|
-
subul = subset.keys.sort.collect do |subkey|
|
26
|
-
render_facet_hierarchy_item(field_name, subset[subkey], subkey)
|
27
|
-
end.join('')
|
28
|
-
ul = "<ul role=\"group\">#{subul}</ul>".html_safe
|
29
|
-
end
|
30
|
-
|
31
|
-
%(<li class="#{li_class}" role="treeitem">#{li.html_safe}#{ul.html_safe}</li>).html_safe
|
32
|
-
end
|
33
|
-
deprecation_deprecate :render_facet_hierarchy_item
|
34
|
-
|
35
|
-
def qfacet_selected?(field_name, item)
|
36
|
-
config = facet_configuration_for_field(field_name)
|
37
|
-
search_state.has_facet?(config, value: facet_value_for_facet_item(item.qvalue))
|
38
|
-
end
|
39
|
-
private :qfacet_selected?
|
40
|
-
|
41
|
-
# @param [Blacklight::Configuration::FacetField] as defined in controller with config.add_facet_field (and with :partial => 'blacklight/hierarchy/facet_hierarchy')
|
42
|
-
# @return [String] html for the facet tree
|
43
|
-
def render_hierarchy(bl_facet_field, delim = '_')
|
44
|
-
field_name = bl_facet_field.field
|
45
|
-
prefix = field_name.gsub("#{delim}#{field_name.split(/#{delim}/).last}", '')
|
46
|
-
facet_tree_for_prefix = facet_tree(prefix)
|
47
|
-
tree = facet_tree_for_prefix ? facet_tree_for_prefix[field_name] : nil
|
48
|
-
|
49
|
-
return '' unless tree
|
50
|
-
tree.keys.sort.collect do |key|
|
51
|
-
render_facet_hierarchy_item(field_name, tree[key], key)
|
52
|
-
end.join("\n").html_safe
|
53
|
-
end
|
54
|
-
deprecation_deprecate :render_hierarchy
|
55
|
-
|
56
|
-
def render_qfacet_value(facet_solr_field, item, options = {})
|
57
|
-
id = options.delete(:id)
|
58
|
-
facet_config = facet_configuration_for_field(facet_solr_field)
|
59
|
-
path_for_facet = facet_item_presenter(facet_config, item.qvalue, facet_solr_field).href
|
60
|
-
(link_to_unless(options[:suppress_link], item.value, path_for_facet, id: id, class: 'facet_select') + ' ' + render_facet_count(item.hits)).html_safe
|
61
|
-
end
|
62
|
-
deprecation_deprecate :render_qfacet_value
|
63
|
-
|
64
|
-
# Standard display of a SELECTED facet value, no link, special span with class, and 'remove' button.
|
65
|
-
def render_selected_qfacet_value(facet_solr_field, item)
|
66
|
-
remove_href = search_action_path(search_state.remove_facet_params(facet_solr_field, item.qvalue))
|
67
|
-
content_tag(:span, render_qfacet_value(facet_solr_field, item, suppress_link: true), class: 'selected') + ' ' +
|
68
|
-
link_to(content_tag(:span, '', class: 'glyphicon glyphicon-remove') +
|
69
|
-
content_tag(:span, '[remove]', class: 'sr-only'),
|
70
|
-
remove_href,
|
71
|
-
class: 'remove'
|
72
|
-
)
|
73
|
-
end
|
74
|
-
deprecation_deprecate :render_selected_qfacet_value
|
75
|
-
|
76
|
-
# @param [String] hkey - a key to access the rest of the hierarchy tree, as defined in controller config.facet_display[:hierarchy] declaration.
|
77
|
-
# e.g. if you had this in controller:
|
78
|
-
# config.facet_display = {
|
79
|
-
# :hierarchy => {
|
80
|
-
# 'wf' => [['wps','wsp','swp'], ':'],
|
81
|
-
# 'callnum_top' => [['facet'], '/'],
|
82
|
-
# 'exploded_tag' => [['ssim'], ':']
|
83
|
-
# }
|
84
|
-
# }
|
85
|
-
# then possible hkey values would be 'wf', 'callnum_top', and 'exploded_tag'.
|
86
|
-
#
|
87
|
-
# the key in the :hierarchy hash is the "prefix" for the solr field with the hierarchy info. the value
|
88
|
-
# in the hash is a list, where the first element is a list of suffixes, and the second element is the delimiter
|
89
|
-
# used to break up the sections of hierarchical data in the solr field being read. when joined, the prefix and
|
90
|
-
# suffix should form the field name. so, for example, 'wf_wps', 'wf_wsp', 'wf_swp', 'callnum_top_facet', and
|
91
|
-
# 'exploded_tag_ssim' would be the solr fields with blacklight-hierarchy related configuration according to the
|
92
|
-
# hash above. ':' would be the delimiter used in all of those fields except for 'callnum_top_facet', which would
|
93
|
-
# use '/'. exploded_tag_ssim might contain values like ['Book', 'Book : Multi-Volume Work'], and callnum_top_facet
|
94
|
-
# might contain values like ['LB', 'LB/2395', 'LB/2395/.C65', 'LB/2395/.C65/1991'].
|
95
|
-
# note: the suffixes (e.g. 'ssim' for 'exploded_tag' in the above example) can't have underscores, otherwise things break.
|
96
|
-
def facet_tree(hkey)
|
97
|
-
@facet_tree ||= {}
|
98
|
-
return @facet_tree[hkey] unless @facet_tree[hkey].nil?
|
99
|
-
return @facet_tree[hkey] unless blacklight_config.facet_display[:hierarchy] && blacklight_config.facet_display[:hierarchy][hkey]
|
100
|
-
@facet_tree[hkey] = {}
|
101
|
-
facet_config = blacklight_config.facet_display[:hierarchy][hkey]
|
102
|
-
split_regex = Regexp.new("\s*#{Regexp.escape(facet_config.length >= 2 ? facet_config[1] : ':')}\s*")
|
103
|
-
facet_config.first.each do |key|
|
104
|
-
# TODO: remove baked in notion of underscores being part of the blacklight facet field names
|
105
|
-
facet_field = [hkey, key].compact.join('_')
|
106
|
-
@facet_tree[hkey][facet_field] ||= {}
|
107
|
-
data = @response.aggregations[facet_field]
|
108
|
-
next if data.nil?
|
109
|
-
data.items.each do |facet_item|
|
110
|
-
path = facet_item.value.split(split_regex)
|
111
|
-
loc = @facet_tree[hkey][facet_field]
|
112
|
-
loc = loc[path.shift] ||= {} while path.length > 0
|
113
|
-
loc[:_] = HierarchicalFacetItem.new(facet_item.value, facet_item.value.split(split_regex).last, facet_item.hits)
|
114
|
-
end
|
115
|
-
end
|
116
|
-
@facet_tree[hkey]
|
117
|
-
end
|
118
|
-
deprecation_deprecate :facet_tree
|
119
|
-
|
120
|
-
def facet_toggle_button(field_name, described_by)
|
4
|
+
def facet_toggle_button(field_name, described_by, controls)
|
121
5
|
aria_label = I18n.t(
|
122
6
|
"blacklight.hierarchy.#{field_name}_toggle_aria_label",
|
123
7
|
default: :'blacklight.hierarchy.toggle_aria_label'
|
124
8
|
)
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
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
|
136
26
|
end
|
137
27
|
|
138
28
|
# --------------------------------------------------------------------------------------------------------------------------------
|
139
29
|
# below are methods pertaining to the "rotate" notion where you may want to look at the same tree data organized another way
|
140
30
|
# --------------------------------------------------------------------------------------------------------------------------------
|
141
31
|
|
142
|
-
# FIXME: remove baked in underscore separator in field name
|
143
|
-
def is_hierarchical?(field_name)
|
144
|
-
(prefix, order) = field_name.split(/_/, 2)
|
145
|
-
(list = blacklight_config.facet_display[:hierarchy][prefix]) && list.include?(order)
|
146
|
-
end
|
147
|
-
deprecation_deprecate :is_hierarchical?
|
148
|
-
|
149
|
-
def facet_order(prefix)
|
150
|
-
param_name = "#{prefix}_facet_order".to_sym
|
151
|
-
params[param_name] || blacklight_config.facet_display[:hierarchy][prefix].first
|
152
|
-
end
|
153
|
-
deprecation_deprecate :facet_order
|
154
|
-
|
155
32
|
def facet_after(prefix, order)
|
156
33
|
orders = blacklight_config.facet_display[:hierarchy][prefix]
|
157
34
|
orders[orders.index(order) + 1] || orders.first
|
158
35
|
end
|
159
|
-
|
160
|
-
# FIXME: remove baked in underscore separator in field name
|
161
|
-
def hide_facet?(field_name)
|
162
|
-
return false unless is_hierarchical?(field_name)
|
163
|
-
prefix = field_name.split(/_/).first
|
164
|
-
field_name != "#{prefix}_#{facet_order(prefix)}"
|
165
|
-
end
|
166
|
-
deprecation_deprecate :hide_facet?
|
167
|
-
|
168
|
-
|
169
|
-
# FIXME: remove baked in colon separator
|
170
|
-
def rotate_facet_value(val, from, to)
|
171
|
-
components = Hash[from.split(//).zip(val.split(/:/))]
|
172
|
-
new_values = components.values_at(*to.split(//))
|
173
|
-
new_values.pop while new_values.last.nil?
|
174
|
-
return nil if new_values.include?(nil)
|
175
|
-
new_values.compact.join(':')
|
176
|
-
end
|
177
|
-
deprecation_deprecate :rotate_facet_value
|
178
|
-
|
179
|
-
# FIXME: remove baked in underscore separator in field name
|
180
|
-
def rotate_facet_params(prefix, from, to, p = params.dup)
|
181
|
-
return p if from == to
|
182
|
-
from_field = "#{prefix}_#{from}"
|
183
|
-
to_field = "#{prefix}_#{to}"
|
184
|
-
p[:f] = (p[:f] || {}).dup # the command above is not deep in rails3, !@#$!@#$
|
185
|
-
p[:f][from_field] = (p[:f][from_field] || []).dup
|
186
|
-
p[:f][to_field] = (p[:f][to_field] || []).dup
|
187
|
-
p[:f][from_field].reject! { |v| p[:f][to_field] << rotate_facet_value(v, from, to); true }
|
188
|
-
p[:f].delete(from_field)
|
189
|
-
p[:f][to_field].compact!
|
190
|
-
p[:f].delete(to_field) if p[:f][to_field].empty?
|
191
|
-
p
|
192
|
-
end
|
193
|
-
deprecation_deprecate :rotate_facet_params
|
194
|
-
|
195
|
-
# FIXME: remove baked in underscore separator in field name
|
196
|
-
def render_facet_rotate(field_name)
|
197
|
-
return unless is_hierarchical?(field_name)
|
198
|
-
(prefix, order) = field_name.split(/_/, 2)
|
199
|
-
return if blacklight_config.facet_display[:hierarchy][prefix].length < 2
|
200
|
-
new_order = facet_after(prefix, order)
|
201
|
-
new_params = rotate_facet_params(prefix, order, new_order)
|
202
|
-
new_params["#{prefix}_facet_order"] = new_order
|
203
|
-
link_to image_tag('icons/rotate.png', title: new_order.upcase).html_safe, new_params, class: 'no-underline'
|
204
|
-
end
|
205
|
-
deprecation_deprecate :render_facet_rotate
|
206
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
|
@@ -18,8 +18,7 @@ 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
|
-
|
22
|
-
s.add_dependency 'blacklight', '~> 7.9'
|
21
|
+
s.add_dependency 'blacklight', '~> 7.18'
|
23
22
|
s.add_dependency 'rails', '>= 5.1', '< 7'
|
24
23
|
s.add_dependency 'deprecation'
|
25
24
|
|
@@ -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
|
-
"description": "[![Build Status](https://
|
3
|
+
"version": "5.2.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",
|
data/spec/features/basic_spec.rb
CHANGED
@@ -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')
|
@@ -1,12 +1,11 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe Blacklight::HierarchyHelper do
|
4
|
-
describe '#
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
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 }
|
11
10
|
end
|
12
11
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: blacklight-hierarchy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 5.2.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:
|
11
|
+
date: 2021-04-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: blacklight
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '7.
|
19
|
+
version: '7.18'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '7.
|
26
|
+
version: '7.18'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rails
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -150,15 +150,16 @@ 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"
|
156
157
|
- ".rubocop_todo.yml"
|
157
|
-
- ".travis.yml"
|
158
158
|
- Gemfile
|
159
159
|
- LICENSE
|
160
160
|
- README.md
|
161
161
|
- Rakefile
|
162
|
+
- app/assets/javascripts/blacklight/hierarchy/blacklight_hierarchy_controller.js
|
162
163
|
- app/assets/javascripts/blacklight/hierarchy/hierarchy.js
|
163
164
|
- app/assets/stylesheets/blacklight/hierarchy/hierarchy.scss
|
164
165
|
- app/components/blacklight/hierarchy/facet_field_component.html.erb
|
@@ -170,6 +171,7 @@ files:
|
|
170
171
|
- app/components/blacklight/hierarchy/selected_qfacet_value_component.html.erb
|
171
172
|
- app/components/blacklight/hierarchy/selected_qfacet_value_component.rb
|
172
173
|
- app/helpers/blacklight/hierarchy_helper.rb
|
174
|
+
- app/models/blacklight/hierarchy/facet_tree.rb
|
173
175
|
- app/models/hierarchical_facet_item.rb
|
174
176
|
- app/views/blacklight/hierarchy/_facet_hierarchy.html.erb
|
175
177
|
- blacklight-hierarchy.gemspec
|
@@ -207,7 +209,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
207
209
|
- !ruby/object:Gem::Version
|
208
210
|
version: '0'
|
209
211
|
requirements: []
|
210
|
-
rubygems_version: 3.1.
|
212
|
+
rubygems_version: 3.1.4
|
211
213
|
signing_key:
|
212
214
|
specification_version: 4
|
213
215
|
summary: Hierarchical Facets for Blacklight
|