Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow show tools to be moved to the header, closes #2316 #3277

Merged
merged 1 commit into from
Aug 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions app/assets/stylesheets/blacklight/_bookmark.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ label.toggle-bookmark {
min-width: 8.5em;
}

/* override for line 3.
Creates weird spacing in toolbar when min-width is set to 8rem */
.header-tools label.toggle-bookmark {
min-width: 2rem;
}

.bookmark-toggle {
.no-js & {
input[type="submit"] {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<%= render applied_params_component %>
<div class="<%= header_container_classes %>">
<div class="<%= pagination_container_classes %>">
<%= render pagination_component %>
</div>
<%= render_header_tools %>
</div>
85 changes: 85 additions & 0 deletions app/components/blacklight/document/page_header_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# frozen_string_literal: true

module Blacklight
module Document
# Render the start over and prev/next displays
class PageHeaderComponent < Blacklight::Component
attr_reader :document, :blacklight_config, :search_context, :search_session

delegate :blacklight_config, to: :helpers

def initialize(document:, search_context:, search_session:)
super
@search_context = search_context
@search_session = search_session
@document = document
end

def render?
search_context.present? || search_session.present? || has_header_tools?
dnoneill marked this conversation as resolved.
Show resolved Hide resolved
end

def applied_params_component
return unless blacklight_config.track_search_session.applied_params_component

blacklight_config.track_search_session.applied_params_component.new
end

def pagination_component
return unless blacklight_config.track_search_session.item_pagination_component

blacklight_config.track_search_session.item_pagination_component.new(search_context: search_context, search_session: search_session, current_document: document)
dnoneill marked this conversation as resolved.
Show resolved Hide resolved
end

def has_header_tools?
header_actions.any? || show_header_tools_component
end

def pagination_container_classes
has_header_tools? ? 'col-12 col-md-6 ms-auto' : ''
end

def header_container_classes
has_header_tools? ? 'row pagination-search-widgets pb-2' : 'pagination-search-widgets'
end

def header_actions
actions = helpers.filter_partials(blacklight_config.view_config(:show).header_actions, { document: document })
actions.map { |_k, v| v }
end

def show_header_tools_component
blacklight_config.view_config(:show).show_header_tools_component
end

def default_action_component_render
render Blacklight::Document::ActionsComponent.new(document: document,
tag: action_component_tag,
classes: classes,
link_classes: link_classes,
actions: header_actions,
url_opts: Blacklight::Parameters.sanitize(params.to_unsafe_h))
end

def action_component_tag
'div'
end

def classes
'd-inline-flex header-tools align-items-center col-12 col-md-6 ms-auto justify-content-md-end'
end

def link_classes
'btn btn-outline-primary ms-2'
end

def render_header_tools
return unless has_header_tools?

return render show_header_tools_component.new(document: document) if show_header_tools_component

default_action_component_render
end
end
end
end
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
<div class='pagination-search-widgets'>
<div class="search-context page-links">
<%= link_to_previous_document %> |

<div class="page-links">
<%= link_to_previous_document %> |
<%= item_page_entry_info %> |

<%= item_page_entry_info %> |

<%= link_to_next_document %>
</div>
<%= link_to_next_document %>
</div>
8 changes: 4 additions & 4 deletions app/helpers/blacklight/component_helper_behavior.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ def document_actions(document, options: {})
filter_partials(blacklight_config.view_config(:show).document_actions, { document: document }.merge(options)).map { |_k, v| v }
end

def filter_partials(partials, options)
partials.select { |_, config| blacklight_configuration_context.evaluate_if_unless_configuration config, options }
end

private

def render_filtered_partials(partials, options = {})
Expand All @@ -52,9 +56,5 @@ def render_filtered_partials(partials, options = {})
end
safe_join(content, "\n") unless block_given?
end

def filter_partials(partials, options)
partials.select { |_, config| blacklight_configuration_context.evaluate_if_unless_configuration config, options }
end
end
end
2 changes: 1 addition & 1 deletion app/views/catalog/_show_main_content.html.erb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<%= render blacklight_config.track_search_session.item_pagination_component.new(search_context: @search_context, search_session: search_session, current_document: @document) if blacklight_config.track_search_session.item_pagination_component %>
<%= render blacklight_config.view_config(:show).document_header_component.new(document: @document, search_context: @search_context, search_session: search_session) %>
<% @page_title = t('blacklight.search.show.title', document_title: document_presenter(@document).html_title, application_name: application_name).html_safe %>
<% content_for(:head) { render_link_rel_alternates } %>

Expand Down
2 changes: 0 additions & 2 deletions app/views/catalog/show.html.erb
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
<%= render blacklight_config.track_search_session.applied_params_component.new if blacklight_config.track_search_session.applied_params_component %>

<%= render 'show_main_content' %>

<% content_for(:sidebar) do %>
Expand Down
21 changes: 20 additions & 1 deletion lib/blacklight/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,8 @@ def initialized_default_configuration?
# in Blacklight 9, the default show_tools_component configuration will
# be Blacklight::Document::ShowToolsComponent
show_tools_component: nil,
show_header_tools_component: nil,
document_header_component: Blacklight::Document::PageHeaderComponent,
sidebar_component: Blacklight::Document::SidebarComponent,
display_type_field: nil,
# the "field access" key to use to look up the document display fields
Expand All @@ -211,7 +213,8 @@ def initialized_default_configuration?
route: nil,
# partials to render for each document(see #render_document_partials)
partials: [],
document_actions: NestedOpenStructWithHashAccess.new(ToolConfig)
document_actions: NestedOpenStructWithHashAccess.new(ToolConfig),
header_actions: NestedOpenStructWithHashAccess.new(ToolConfig)
)

# @!attribute action_mapping
Expand Down Expand Up @@ -558,6 +561,22 @@ def add_show_tools_partial(name, opts = {})
add_action(show.document_actions, name, opts)
klass && ActionBuilder.new(klass, name, opts).build
end

# Add a partial to the show page header when rendering a document.
# @!macro partial_if_unless
# @param name [String] the name of the document partial
# @param opts [Hash]
# @option opts [Class] :component draw a component
# @option opts [String] :partial partial to draw if component is false
# @option opts [Symbol,Proc] :if render this action if the method identified by the symbol or the proc evaluates to true. The proc will receive the action configuration and the document or documents for the action.
# @option opts [Symbol,Proc] :unless render this action unless the method identified by the symbol or the proc evaluates to true. The proc will receive the action configuration and the document or documents for the action.
def add_show_header_tools_partial(name, opts = {})
opts[:partial] ||= 'document_action'

add_action(show.header_actions, name, opts)
klass && ActionBuilder.new(klass, name, opts).build
end

# rubocop:enable Layout/LineLength

# Add a tool for the search result list itself
Expand Down
92 changes: 92 additions & 0 deletions spec/components/blacklight/document/page_header_component_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Blacklight::Document::PageHeaderComponent, type: :component do
subject(:component) { described_class.new(document: document, search_context: search_context, search_session: current_search_session) }

let(:show_header_tools_component) { Class.new(Blacklight::Document::ShowToolsComponent) }

let(:view_context) { controller.view_context }
let(:render) do
component.render_in(view_context)
end

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

let(:document) { SolrDocument.new(id: 'x', title_tsim: 'Title') }

let(:blacklight_config) do
CatalogController.blacklight_config.deep_copy
end

# rubocop:disable RSpec/SubjectStub
before do
# Every call to view_context returns a different object. This ensures it stays stable.
allow(controller).to receive_messages(blacklight_config: blacklight_config)
allow(controller).to receive(:current_search_session).and_return(double(id: document.id))
controller.class.helper_method :current_search_session
allow(controller).to receive_messages(controller_name: 'catalog', link_to_previous_document: '', link_to_next_document: '')
allow(view_context).to receive_messages(search_context: search_context, search_session: current_search_session, current_search_session: current_search_session)
allow(component).to receive(:render).and_call_original
allow(component).to receive(:render).with(an_instance_of(show_header_tools_component)).and_return('tool component content')
replace_hash = { 'application/_start_over.html.erb' => 'Start Over' }
if Rails.version.to_f >= 7.1
controller.prepend_view_path(RSpec::Rails::ViewExampleGroup::StubResolverCache.resolver_for(replace_hash))
else
view_context.view_paths.unshift(RSpec::Rails::ViewExampleGroup::StubResolverCache.resolver_for(replace_hash))
end
end
# rubocop:enable RSpec/SubjectStub

context "all variables are empty" do
let(:search_context) { nil }
let(:current_search_session) { {} }

it 'does not render' do
expect(rendered.native.inner_html).to be_blank
end

context 'has header tools' do
before do
blacklight_config.show.show_header_tools_component = show_header_tools_component
end

it 'renders the tools' do
expect(rendered).to have_text 'tool component content'
expect(rendered).to have_css '.row'
end
end
end

context "has pagination" do
let(:search_context) { { next: next_doc, prev: prev_doc } }
let(:prev_doc) { SolrDocument.new(id: '777') }
let(:next_doc) { SolrDocument.new(id: '888') }
let(:current_search_session) { { query_params: { q: 'abc' }, 'id' => '123', 'document_id' => document.id } }

it 'renders pagination' do
expect(rendered).to have_text 'Previous'
expect(rendered).to have_text 'Next'
expect(rendered).to have_text 'Start Over'
expect(rendered).to have_text 'Back to Search'
end

context 'has header tools' do
before do
blacklight_config.show.show_header_tools_component = show_header_tools_component
end

it 'renders the tools and pagination' do
expect(rendered).to have_text 'Previous'
expect(rendered).to have_text 'Next'
expect(rendered).to have_text 'Start Over'
expect(rendered).to have_text 'Back to Search'
expect(rendered).to have_text 'tool component content'
expect(rendered).to have_css '.row'
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
end

it "renders content" do
expect(render.css('.pagination-search-widgets').to_html).not_to be_blank
expect(render.css('.search-context.page-links').to_html).not_to be_blank
end

context "session and document are out of sync" do
Expand Down