Skip to content

Commit

Permalink
Merge pull request #2296 from projectblacklight/pivot-component-and-c…
Browse files Browse the repository at this point in the history
…ollapse

Convert pivot facets to a component and add hierarchy expand/collapse
  • Loading branch information
jcoyne authored Jun 9, 2020
2 parents 5a84b63 + e683858 commit 49f5539
Show file tree
Hide file tree
Showing 20 changed files with 241 additions and 29 deletions.
24 changes: 20 additions & 4 deletions app/assets/stylesheets/blacklight/_facets.scss
Original file line number Diff line number Diff line change
Expand Up @@ -150,10 +150,26 @@

.pivot-facet {
@extend .list-unstyled;
@extend .py-1;
@extend .px-4;
}

.facet-leaf-node {
margin-left: 1rem;
padding-right: 1rem;
margin-top: -1.5rem;
}

ul, .pivot-facet {
@extend .list-unstyled;
@extend .py-1;
@extend .px-3;
.facet-toggle-handle {
margin: 0;
margin-left: -5px;
padding: 0;

&.collapsed {
.show { display: block; }
.hide { display: none; }
}

.show { display: none; }
.hide { display: block; }
}
84 changes: 84 additions & 0 deletions app/components/blacklight/facet_item_pivot_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# frozen_string_literal: true

module Blacklight
# Render facet items and any subtree
class FacetItemPivotComponent < ::ViewComponent::Base
# Somewhat arbitrary number; the only important thing is that
# it is bigger than the number of leaf nodes in any collapsing
# pivot facet on the page.
ID_COUNTER_MAX = 2**20 - 1

# Mint a (sufficiently) unique identifier, so we can associate
# the expand/collapse control with labels
def self.mint_id
@id_counter = ((@id_counter || 0) + 1) % ID_COUNTER_MAX

# We convert the ID to hex for markup compactness
@id_counter.to_s(16)
end

with_collection_parameter :facet_item

def initialize(facet_item:, wrapping_element: 'li', suppress_link: false, collapsing: nil)
@facet_item = facet_item
@wrapping_element = wrapping_element
@suppress_link = suppress_link
@collapsing = collapsing.nil? ? facet_item.facet_config.collapsing : collapsing
@icons = { show: '⊞', hide: '⊟' }.merge(facet_item.facet_config.icons || {})
end

def call
facet = Blacklight::FacetItemComponent.new(facet_item: @facet_item, wrapping_element: nil, suppress_link: @suppress_link)

id = "h-#{self.class.mint_id}" if @collapsing && has_items?

content_tag @wrapping_element, role: 'treeitem' do
concat facet_toggle_button(id) if has_items? && @collapsing
concat content_tag('span', render_component(facet), class: "facet-values #{'facet-leaf-node' if has_items? && @collapsing}", id: id && "#{id}_label")

if has_items?
concat(content_tag('ul', class: "pivot-facet list-unstyled #{'collapse' if @collapsing}", id: id, role: 'group') do
render_component(
self.class.with_collection(
@facet_item.items.map { |i| facet_item_presenter(i) }
)
)
end)
end
end
end

private

def has_items?
@facet_item.items.present?
end

def facet_toggle_button(id)
content_tag 'button', class: 'btn facet-toggle-handle collapsed',
data: { toggle: 'collapse', target: "##{id}" },
aria: { expanded: false, controls: id, describedby: "#{id}_label" } do
concat toggle_icon(:show)
concat toggle_icon(:hide)
end
end

def toggle_icon(type)
content_tag 'span', class: type do
concat @icons[type]
concat content_tag('span', t(type, scope: 'blacklight.search.facets.pivot'), class: 'sr-only')
end
end

# This is a little convoluted in Blacklight 7 in order to maintain backwards-compat
# with overrides of deprecated helpers. In 8.x, we can just call Component#render_in
# and call it a day
def render_component(component)
@view_context.render(component)
end

def facet_item_presenter(facet_item)
Blacklight::FacetItemPresenter.new(facet_item, @facet_item.facet_config, @view_context, @facet_item.facet_field, @facet_item.search_state)
end
end
end
17 changes: 12 additions & 5 deletions app/helpers/blacklight/facets_helper_behavior.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,11 @@ def render_facet_limit(display_facet, options = {})
return unless should_render_facet?(display_facet, field_config)
end
options = options.dup
options[:partial] ||= facet_partial_name(display_facet)

Deprecation.silence(Blacklight::FacetsHelperBehavior) do
options[:partial] ||= facet_partial_name(display_facet)
end

options[:layout] ||= "facet_layout" unless options.key?(:layout)
options[:locals] ||= {}
options[:locals][:field_name] ||= display_facet.name
Expand All @@ -97,13 +101,12 @@ def render_facet_limit(display_facet, options = {})
# to filter undesireable facet items so they don't appear in the UI
def render_facet_limit_list(paginator, facet_field, wrapping_element = :li)
facet_config ||= facet_configuration_for_field(facet_field)
component = facet_config.fetch(:item_component, Blacklight::FacetItemComponent)

collection = paginator.items.map do |item|
facet_item_presenter(facet_config, item, facet_field)
end

render(component.with_collection(collection, wrapping_element: wrapping_element))
render(facet_item_component_class(facet_config).with_collection(collection, wrapping_element: wrapping_element))
end
deprecation_deprecate :render_facet_limit_list

Expand Down Expand Up @@ -288,8 +291,12 @@ def facet_item_presenter(facet_config, facet_item, facet_field)
end

def facet_item_component(facet_config, facet_item, facet_field, **args)
component = facet_config.fetch(:item_component, Blacklight::FacetItemComponent)
component.new(facet_item: facet_item_presenter(facet_config, facet_item, facet_field), **args).with_view_context(self)
facet_item_component_class(facet_config).new(facet_item: facet_item_presenter(facet_config, facet_item, facet_field), **args).with_view_context(self)
end

def facet_item_component_class(facet_config)
default_component = facet_config.pivot ? Blacklight::FacetItemPivotComponent : Blacklight::FacetItemComponent
facet_config.fetch(:item_component, default_component)
end

# We can't use .deprecation_deprecate here, because the new components need to
Expand Down
2 changes: 1 addition & 1 deletion app/presenters/blacklight/facet_item_presenter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ module Blacklight
class FacetItemPresenter
attr_reader :facet_item, :facet_config, :view_context, :search_state, :facet_field

delegate :hits, to: :facet_item
delegate :hits, :items, to: :facet_item

def initialize(facet_item, facet_config, view_context, facet_field, search_state = view_context.search_state)
@facet_item = facet_item
Expand Down
21 changes: 3 additions & 18 deletions app/views/catalog/_facet_pivot.html.erb
Original file line number Diff line number Diff line change
@@ -1,18 +1,3 @@
<ul class="pivot-facet list-unstyled">
<% display_facet.items.each do |item| -%>
<li>
<span class="facet-values">
<% if facet_in_params?(field_name, item) %>
<%= render_selected_facet_value(field_name, item) %>
<% else %>
<%= render_facet_value(field_name, item) %>
<% end -%>
</span>

<% unless item.items.blank? %>
<%= render 'facet_pivot', display_facet: item, field_name: field_name %>
<% end %>
</li>
<% end %>

</ul>
<%= render(Blacklight::FacetFieldListComponent.new(
facet_field: facet_field_presenter(facet_field.merge(item_component: Blacklight::FacetItemPivotComponent), display_facet),
layout: false)) %>
3 changes: 3 additions & 0 deletions config/locales/blacklight.ar.yml
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,9 @@ ar:
remove: '[إزالة]'
missing: "[غير موجود]"
all: الكل
pivot:
show: فتح
hide: "إغلاق"
group:
more: 'المزيد »'
filters:
Expand Down
3 changes: 3 additions & 0 deletions config/locales/blacklight.de.yml
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,9 @@ de:
selected:
remove: '[entfernen]'
missing: [fehlt]
pivot:
show: Öffnen
hide: Schließen
group:
more: 'mehr »'
filters:
Expand Down
3 changes: 3 additions & 0 deletions config/locales/blacklight.en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,9 @@ en:
remove: '[remove]'
missing: "[Missing]"
all: All
pivot:
show: Show
hide: Hide
group:
more: 'more »'
filters:
Expand Down
3 changes: 3 additions & 0 deletions config/locales/blacklight.es.yml
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,9 @@ es:
selected:
remove: '[borrar]'
missing: '[Falta]'
pivot:
show: Abierto
hide: Cerrar
group:
more: 'más »'
filters:
Expand Down
3 changes: 3 additions & 0 deletions config/locales/blacklight.fr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,9 @@ fr:
selected:
remove: '[ X ]'
missing: '[manquante]'
pivot:
show: Ouvrir
hide: Fermer
group:
more: 'plus »'
filters:
Expand Down
3 changes: 3 additions & 0 deletions config/locales/blacklight.hu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,9 @@ hu:
selected:
remove: '[eltávolítás]'
missing: "[Hiányzó]"
pivot:
show: Megnyitás
hide: Bezárás
group:
more: 'több »'
filters:
Expand Down
3 changes: 3 additions & 0 deletions config/locales/blacklight.it.yml
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,9 @@ it:
selected:
remove: '[cancella]'
missing: [Mancante]
pivot:
show: Apri
hide: Chiudi
group:
more: 'altri »'
filters:
Expand Down
3 changes: 3 additions & 0 deletions config/locales/blacklight.nl.yml
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,9 @@ nl:
selected:
remove: '[verwijder]'
missing: "[Ontbrekend]"
pivot:
show: Openen
hide: Sluiten
group:
more: 'meer »'
filters:
Expand Down
3 changes: 3 additions & 0 deletions config/locales/blacklight.pt-BR.yml
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,9 @@ pt-BR:
selected:
remove: '[remover]'
missing: [Ausência]
pivot:
show: Abrir
hide: Fechar
group:
more: 'mais »'
filters:
Expand Down
3 changes: 3 additions & 0 deletions config/locales/blacklight.sq.yml
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,9 @@ sq:
selected:
remove: '[fshije]'
missing: "[Mungon]"
pivot:
show: Hape
hide: "Mbylle"
group:
more: 'më shumë »'
filters:
Expand Down
3 changes: 3 additions & 0 deletions config/locales/blacklight.zh.yml
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,9 @@ zh:
selected:
remove: '[删除]'
missing: "[未找到]"
pivot:
show: 打开
hide:
group:
more: '更多 »'
filters:
Expand Down
2 changes: 1 addition & 1 deletion lib/generators/blacklight/templates/catalog_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ class <%= controller_name.classify %>Controller < ApplicationController
config.add_facet_field 'subject_geo_ssim', label: 'Region'
config.add_facet_field 'subject_era_ssim', label: 'Era'
config.add_facet_field 'example_pivot_field', label: 'Pivot Field', :pivot => ['format', 'language_ssim']
config.add_facet_field 'example_pivot_field', label: 'Pivot Field', pivot: ['format', 'language_ssim'], collapsing: true
config.add_facet_field 'example_query_facet_field', label: 'Publish Date', :query => {
:years_5 => { label: 'within 5 Years', fq: "pub_date_ssim:[#{Time.zone.now.year - 5 } TO *]" },
Expand Down
66 changes: 66 additions & 0 deletions spec/components/blacklight/facet_item_pivot_component_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Blacklight::FacetItemPivotComponent, type: :component do
subject(:render) do
render_inline(described_class.new(facet_item: facet_item))
end

let(:rendered) do
Capybara::Node::Simple.new(render)
end

let(:search_state) do
Blacklight::SearchState.new({}, Blacklight::Configuration.new)
end

let(:facet_item) do
instance_double(
Blacklight::FacetItemPresenter,
facet_config: Blacklight::Configuration::FacetField.new(key: 'z'),
facet_field: 'z',
label: 'x',
hits: 10,
href: '/catalog?f[z]=x',
selected?: false,
search_state: search_state,
items: [OpenStruct.new(value: 'x:1', hits: 5)]
)
end

it 'links to the facet and shows the number of hits' do
expect(rendered).to have_selector 'li'
expect(rendered).to have_link 'x', href: '/catalog?f[z]=x'
expect(rendered).to have_selector '.facet-count', text: '10'
end

it 'has the facet hierarchy' do
puts render
expect(rendered).to have_selector 'li ul.pivot-facet'
expect(rendered).to have_link 'x:1', href: /f%5Bz%5D%5B%5D=x%3A1/
end

context 'with a selected facet' do
let(:facet_item) do
instance_double(
Blacklight::FacetItemPresenter,
facet_config: Blacklight::Configuration::FacetField.new,
facet_field: 'z',
label: 'x',
hits: 10,
href: '/catalog',
selected?: true,
search_state: search_state,
items: []
)
end

it 'links to the facet and shows the number of hits' do
expect(rendered).to have_selector 'li'
expect(rendered).to have_selector '.selected', text: 'x'
expect(rendered).to have_link '[remove]', href: '/catalog'
expect(rendered).to have_selector '.selected.facet-count', text: '10'
end
end
end
Loading

0 comments on commit 49f5539

Please sign in to comment.