blacklight-hierarchy 2.0.0 → 4.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.travis.yml +1 -1
- data/Gemfile +5 -0
- data/README.md +37 -10
- data/app/assets/javascripts/blacklight/hierarchy/hierarchy.js +7 -7
- data/app/assets/stylesheets/blacklight/hierarchy/hierarchy.scss +64 -13
- data/app/components/blacklight/hierarchy/facet_field_component.html.erb +18 -0
- data/app/components/blacklight/hierarchy/facet_field_component.rb +33 -0
- data/app/components/blacklight/hierarchy/facet_field_list_component.html.erb +12 -0
- data/app/components/blacklight/hierarchy/facet_field_list_component.rb +72 -0
- data/app/components/blacklight/hierarchy/qfacet_value_component.html.erb +1 -0
- data/app/components/blacklight/hierarchy/qfacet_value_component.rb +26 -0
- data/app/components/blacklight/hierarchy/selected_qfacet_value_component.html.erb +4 -0
- data/app/components/blacklight/hierarchy/selected_qfacet_value_component.rb +19 -0
- data/app/helpers/blacklight/hierarchy_helper.rb +52 -12
- data/app/models/hierarchical_facet_item.rb +1 -0
- data/app/views/blacklight/hierarchy/_facet_hierarchy.html.erb +5 -1
- data/blacklight-hierarchy.gemspec +5 -4
- data/config/locales/blacklight-hierarchy.ar.yml +4 -0
- data/config/locales/blacklight-hierarchy.en.yml +4 -0
- data/lib/blacklight/hierarchy/engine.rb +2 -0
- data/lib/blacklight/hierarchy/version.rb +1 -1
- data/package.json +25 -0
- data/spec/features/basic_spec.rb +4 -5
- data/spec/helpers/hierarchy_helper_spec.rb +10 -1
- data/spec/test_app_templates/lib/generators/test_app_generator.rb +8 -0
- metadata +36 -31
- data/app/assets/images/collapsed.png +0 -0
- data/app/assets/images/empty_marker.png +0 -0
- data/app/assets/images/expanded.png +0 -0
- data/app/assets/images/minus_arrow.png +0 -0
- data/app/assets/images/plus_arrow.png +0 -0
- data/app/views/blacklight/hierarchy/_facet_hierarchy_item.html.erb +0 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 79579c36f70d48f54d5968f3123e636b59dd5bcc267603967a4c161f991d1da8
|
4
|
+
data.tar.gz: c7046b2a00788761b9901cb625f4b845db1d91877cce3c09a07a76751bb84ea3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0e26f0a52342f53fe9e06c1c253dd46a44dbc2cce4590edeafe978e410b71f0471e2ec70b65844a5cd0bf3b1e30ae8e0be25c0733be739dd6f7508f0d16afc0b
|
7
|
+
data.tar.gz: 11d377fc4e98d6a7352b4db13c85d8ac3431531604ce55ed1185b2c2c7291f7e4df771954f3e3ddbfce73ed551212843416b4c0fecdd61d289eb8455e9ad387a
|
data/.travis.yml
CHANGED
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
@@ -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) [![
|
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)
|
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
|
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', :
|
54
|
-
config.add_facet_field 'queue_wsp', :
|
55
|
-
config.add_facet_field 'queue_swp', :
|
56
|
-
config.add_facet_field 'callnum_top', :
|
57
|
-
config.add_facet_field 'foo_trunk', :
|
58
|
-
config.add_facet_field 'foo_branch', :
|
59
|
-
config.add_facet_field 'foo_leaves', :
|
60
|
-
config.add_facet_field 'tag_facet', :
|
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
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
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,13 +1,64 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
1
|
+
$text-muted: #777 !default;
|
2
|
+
|
3
|
+
.facet-hierarchy {
|
4
|
+
list-style-type: none;
|
5
|
+
padding-left: 0;
|
6
|
+
|
7
|
+
ul {
|
8
|
+
border-bottom: 0;
|
9
|
+
list-style-type: none;
|
10
|
+
padding-bottom: 0;
|
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;
|
34
|
+
}
|
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
|
+
|
57
|
+
.h-node {
|
58
|
+
cursor: pointer;
|
59
|
+
}
|
60
|
+
|
61
|
+
.remove {
|
62
|
+
color: $text-muted;
|
63
|
+
}
|
64
|
+
}
|
@@ -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.has_facet?(config, value: 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,3 +1,5 @@
|
|
1
|
+
require 'deprecation'
|
2
|
+
|
1
3
|
module Blacklight::HierarchyHelper
|
2
4
|
# Putting bare HTML strings in a helper sucks. But in this case, with a
|
3
5
|
# lot of recursive tree-walking going on, it's an order of magnitude faster
|
@@ -7,24 +9,34 @@ module Blacklight::HierarchyHelper
|
|
7
9
|
subset = data.reject { |k, _v| !k.is_a?(String) }
|
8
10
|
|
9
11
|
li_class = subset.empty? ? 'h-leaf' : 'h-node'
|
12
|
+
id = SecureRandom.uuid
|
10
13
|
ul = ''
|
11
|
-
li =
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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
|
18
23
|
|
19
24
|
unless subset.empty?
|
20
25
|
subul = subset.keys.sort.collect do |subkey|
|
21
26
|
render_facet_hierarchy_item(field_name, subset[subkey], subkey)
|
22
27
|
end.join('')
|
23
|
-
ul = "<ul>#{subul}</ul>".html_safe
|
28
|
+
ul = "<ul role=\"group\">#{subul}</ul>".html_safe
|
24
29
|
end
|
25
30
|
|
26
|
-
%(<li class="#{li_class}">#{li.html_safe}#{ul.html_safe}</li>).html_safe
|
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))
|
27
38
|
end
|
39
|
+
private :qfacet_selected?
|
28
40
|
|
29
41
|
# @param [Blacklight::Configuration::FacetField] as defined in controller with config.add_facet_field (and with :partial => 'blacklight/hierarchy/facet_hierarchy')
|
30
42
|
# @return [String] html for the facet tree
|
@@ -39,10 +51,15 @@ module Blacklight::HierarchyHelper
|
|
39
51
|
render_facet_hierarchy_item(field_name, tree[key], key)
|
40
52
|
end.join("\n").html_safe
|
41
53
|
end
|
54
|
+
deprecation_deprecate :render_hierarchy
|
42
55
|
|
43
56
|
def render_qfacet_value(facet_solr_field, item, options = {})
|
44
|
-
|
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
|
45
61
|
end
|
62
|
+
deprecation_deprecate :render_qfacet_value
|
46
63
|
|
47
64
|
# Standard display of a SELECTED facet value, no link, special span with class, and 'remove' button.
|
48
65
|
def render_selected_qfacet_value(facet_solr_field, item)
|
@@ -54,8 +71,7 @@ module Blacklight::HierarchyHelper
|
|
54
71
|
class: 'remove'
|
55
72
|
)
|
56
73
|
end
|
57
|
-
|
58
|
-
HierarchicalFacetItem = Struct.new :qvalue, :value, :hits
|
74
|
+
deprecation_deprecate :render_selected_qfacet_value
|
59
75
|
|
60
76
|
# @param [String] hkey - a key to access the rest of the hierarchy tree, as defined in controller config.facet_display[:hierarchy] declaration.
|
61
77
|
# e.g. if you had this in controller:
|
@@ -99,6 +115,23 @@ module Blacklight::HierarchyHelper
|
|
99
115
|
end
|
100
116
|
@facet_tree[hkey]
|
101
117
|
end
|
118
|
+
deprecation_deprecate :facet_tree
|
119
|
+
|
120
|
+
def facet_toggle_button(field_name, described_by)
|
121
|
+
aria_label = I18n.t(
|
122
|
+
"blacklight.hierarchy.#{field_name}_toggle_aria_label",
|
123
|
+
default: :'blacklight.hierarchy.toggle_aria_label'
|
124
|
+
)
|
125
|
+
|
126
|
+
# For Rails 5.2 support all options must be symbols. See https://github.com/rails/rails/issues/39813
|
127
|
+
tag.button(:'aria-expanded' => 'false',
|
128
|
+
:'aria-label' => aria_label,
|
129
|
+
:'aria-describedby' => described_by,
|
130
|
+
class: 'toggle-handle') do
|
131
|
+
tag.span(Blacklight::Hierarchy::Engine.config.closed_icon, :'aria-hidden' => 'true', class: 'closed') +
|
132
|
+
tag.span(Blacklight::Hierarchy::Engine.config.opened_icon, :'aria-hidden' => 'true', class: 'opened')
|
133
|
+
end
|
134
|
+
end
|
102
135
|
|
103
136
|
# --------------------------------------------------------------------------------------------------------------------------------
|
104
137
|
# below are methods pertaining to the "rotate" notion where you may want to look at the same tree data organized another way
|
@@ -109,11 +142,13 @@ module Blacklight::HierarchyHelper
|
|
109
142
|
(prefix, order) = field_name.split(/_/, 2)
|
110
143
|
(list = blacklight_config.facet_display[:hierarchy][prefix]) && list.include?(order)
|
111
144
|
end
|
145
|
+
deprecation_deprecate :is_hierarchical?
|
112
146
|
|
113
147
|
def facet_order(prefix)
|
114
148
|
param_name = "#{prefix}_facet_order".to_sym
|
115
149
|
params[param_name] || blacklight_config.facet_display[:hierarchy][prefix].first
|
116
150
|
end
|
151
|
+
deprecation_deprecate :facet_order
|
117
152
|
|
118
153
|
def facet_after(prefix, order)
|
119
154
|
orders = blacklight_config.facet_display[:hierarchy][prefix]
|
@@ -126,6 +161,8 @@ module Blacklight::HierarchyHelper
|
|
126
161
|
prefix = field_name.split(/_/).first
|
127
162
|
field_name != "#{prefix}_#{facet_order(prefix)}"
|
128
163
|
end
|
164
|
+
deprecation_deprecate :hide_facet?
|
165
|
+
|
129
166
|
|
130
167
|
# FIXME: remove baked in colon separator
|
131
168
|
def rotate_facet_value(val, from, to)
|
@@ -135,6 +172,7 @@ module Blacklight::HierarchyHelper
|
|
135
172
|
return nil if new_values.include?(nil)
|
136
173
|
new_values.compact.join(':')
|
137
174
|
end
|
175
|
+
deprecation_deprecate :rotate_facet_value
|
138
176
|
|
139
177
|
# FIXME: remove baked in underscore separator in field name
|
140
178
|
def rotate_facet_params(prefix, from, to, p = params.dup)
|
@@ -150,6 +188,7 @@ module Blacklight::HierarchyHelper
|
|
150
188
|
p[:f].delete(to_field) if p[:f][to_field].empty?
|
151
189
|
p
|
152
190
|
end
|
191
|
+
deprecation_deprecate :rotate_facet_params
|
153
192
|
|
154
193
|
# FIXME: remove baked in underscore separator in field name
|
155
194
|
def render_facet_rotate(field_name)
|
@@ -161,4 +200,5 @@ module Blacklight::HierarchyHelper
|
|
161
200
|
new_params["#{prefix}_facet_order"] = new_order
|
162
201
|
link_to image_tag('icons/rotate.png', title: new_order.upcase).html_safe, new_params, class: 'no-underline'
|
163
202
|
end
|
203
|
+
deprecation_deprecate :render_facet_rotate
|
164
204
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
HierarchicalFacetItem = Struct.new :qvalue, :value, :hits
|
@@ -1,3 +1,7 @@
|
|
1
|
-
|
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,14 +18,15 @@ 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 '
|
23
|
-
s.add_dependency '
|
21
|
+
# A version of blacklight with view_component is required
|
22
|
+
s.add_dependency 'blacklight', '~> 7.9'
|
23
|
+
s.add_dependency 'rails', '>= 5.1', '< 7'
|
24
|
+
s.add_dependency 'deprecation'
|
24
25
|
|
25
26
|
s.add_development_dependency 'rsolr'
|
26
27
|
s.add_development_dependency 'rspec-rails'
|
27
28
|
s.add_development_dependency 'sqlite3'
|
28
|
-
s.add_development_dependency 'engine_cart', '~>
|
29
|
+
s.add_development_dependency 'engine_cart', '~> 2.3'
|
29
30
|
s.add_development_dependency 'capybara'
|
30
31
|
s.add_development_dependency 'coveralls'
|
31
32
|
end
|
data/package.json
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
{
|
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)",
|
5
|
+
"main": "app/assets/javascripts/blacklight/hierarchy/hierarchy.js",
|
6
|
+
"files": [
|
7
|
+
"app/assets/javascripts/blacklight/hierarchy/*.js",
|
8
|
+
"app/assets/stylesheets/blacklight/hierarchy/*.scss"
|
9
|
+
],
|
10
|
+
"repository": {
|
11
|
+
"type": "git",
|
12
|
+
"url": "git+https://github.com/sul-dlss/blacklight-hierarchy.git"
|
13
|
+
},
|
14
|
+
"author": "",
|
15
|
+
"license": "Apache-2.0",
|
16
|
+
"bugs": {
|
17
|
+
"url": "https://github.com/sul-dlss/blacklight-hierarchy/issues"
|
18
|
+
},
|
19
|
+
"homepage": "https://github.com/sul-dlss/blacklight-hierarchy#readme",
|
20
|
+
"devDependencies": { },
|
21
|
+
"dependencies": {
|
22
|
+
"blacklight-frontend": ">=7.1.0-alpha",
|
23
|
+
"jquery": ">=3.0"
|
24
|
+
}
|
25
|
+
}
|
data/spec/features/basic_spec.rb
CHANGED
@@ -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
|
-
|
103
|
-
config.add_facet_field '
|
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',
|
123
|
-
config.add_facet_field 'my_top_facet', label: 'Slash Delim',
|
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: 2.
|
4
|
+
version: 4.2.1
|
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: 2020-07-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
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: '
|
19
|
+
version: '7.9'
|
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: '
|
26
|
+
version: '7.9'
|
33
27
|
- !ruby/object:Gem::Dependency
|
34
|
-
name:
|
28
|
+
name: rails
|
35
29
|
requirement: !ruby/object:Gem::Requirement
|
36
30
|
requirements:
|
37
31
|
- - ">="
|
38
32
|
- !ruby/object:Gem::Version
|
39
|
-
version: '
|
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: '
|
43
|
+
version: '5.1'
|
44
|
+
- - "<"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '7'
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
|
-
name:
|
48
|
+
name: deprecation
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|
50
50
|
requirements:
|
51
|
-
- - "
|
51
|
+
- - ">="
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version: '
|
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: '
|
60
|
+
version: '0'
|
61
61
|
- !ruby/object:Gem::Dependency
|
62
62
|
name: rsolr
|
63
63
|
requirement: !ruby/object:Gem::Requirement
|
@@ -106,14 +106,14 @@ dependencies:
|
|
106
106
|
requirements:
|
107
107
|
- - "~>"
|
108
108
|
- !ruby/object:Gem::Version
|
109
|
-
version: '
|
109
|
+
version: '2.3'
|
110
110
|
type: :development
|
111
111
|
prerelease: false
|
112
112
|
version_requirements: !ruby/object:Gem::Requirement
|
113
113
|
requirements:
|
114
114
|
- - "~>"
|
115
115
|
- !ruby/object:Gem::Version
|
116
|
-
version: '
|
116
|
+
version: '2.3'
|
117
117
|
- !ruby/object:Gem::Dependency
|
118
118
|
name: capybara
|
119
119
|
requirement: !ruby/object:Gem::Requirement
|
@@ -159,17 +159,22 @@ files:
|
|
159
159
|
- LICENSE
|
160
160
|
- README.md
|
161
161
|
- Rakefile
|
162
|
-
- app/assets/images/collapsed.png
|
163
|
-
- app/assets/images/empty_marker.png
|
164
|
-
- app/assets/images/expanded.png
|
165
|
-
- app/assets/images/minus_arrow.png
|
166
|
-
- app/assets/images/plus_arrow.png
|
167
162
|
- app/assets/javascripts/blacklight/hierarchy/hierarchy.js
|
168
163
|
- app/assets/stylesheets/blacklight/hierarchy/hierarchy.scss
|
164
|
+
- app/components/blacklight/hierarchy/facet_field_component.html.erb
|
165
|
+
- app/components/blacklight/hierarchy/facet_field_component.rb
|
166
|
+
- app/components/blacklight/hierarchy/facet_field_list_component.html.erb
|
167
|
+
- app/components/blacklight/hierarchy/facet_field_list_component.rb
|
168
|
+
- app/components/blacklight/hierarchy/qfacet_value_component.html.erb
|
169
|
+
- app/components/blacklight/hierarchy/qfacet_value_component.rb
|
170
|
+
- app/components/blacklight/hierarchy/selected_qfacet_value_component.html.erb
|
171
|
+
- app/components/blacklight/hierarchy/selected_qfacet_value_component.rb
|
169
172
|
- app/helpers/blacklight/hierarchy_helper.rb
|
173
|
+
- app/models/hierarchical_facet_item.rb
|
170
174
|
- app/views/blacklight/hierarchy/_facet_hierarchy.html.erb
|
171
|
-
- app/views/blacklight/hierarchy/_facet_hierarchy_item.html.erb
|
172
175
|
- blacklight-hierarchy.gemspec
|
176
|
+
- config/locales/blacklight-hierarchy.ar.yml
|
177
|
+
- config/locales/blacklight-hierarchy.en.yml
|
173
178
|
- lib/blacklight-hierarchy.rb
|
174
179
|
- lib/blacklight/hierarchy.rb
|
175
180
|
- lib/blacklight/hierarchy/engine.rb
|
@@ -178,6 +183,7 @@ files:
|
|
178
183
|
- lib/generators/blacklight_hierarchy/install_generator.rb
|
179
184
|
- lib/generators/blacklight_hierarchy/templates/blacklight_hierarchy.js
|
180
185
|
- lib/generators/blacklight_hierarchy/templates/blacklight_hierarchy.scss
|
186
|
+
- package.json
|
181
187
|
- spec/features/basic_spec.rb
|
182
188
|
- spec/helpers/hierarchy_helper_spec.rb
|
183
189
|
- spec/spec_helper.rb
|
@@ -201,8 +207,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
201
207
|
- !ruby/object:Gem::Version
|
202
208
|
version: '0'
|
203
209
|
requirements: []
|
204
|
-
|
205
|
-
rubygems_version: 2.6.11
|
210
|
+
rubygems_version: 3.1.2
|
206
211
|
signing_key:
|
207
212
|
specification_version: 4
|
208
213
|
summary: Hierarchical Facets for Blacklight
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -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>
|