Skip to content

Commit

Permalink
Refactor BlacklightHelper into a DocumentPresenter. Fixes #782
Browse files Browse the repository at this point in the history
  • Loading branch information
jcoyne committed Feb 18, 2014
1 parent 227589b commit f57b8e3
Show file tree
Hide file tree
Showing 5 changed files with 412 additions and 64 deletions.
82 changes: 21 additions & 61 deletions app/helpers/blacklight/blacklight_helper_behavior.rb
Original file line number Diff line number Diff line change
Expand Up @@ -201,10 +201,7 @@ def render_index_field_value *args
document = args.shift || options[:document]

field = args.shift || options[:field]
field_config = index_fields(document)[field]
value = options[:value] || get_field_values(document, field, field_config, options)

render_field_value value, field_config
presenter(document).render_index_field_value field, options
end

##
Expand Down Expand Up @@ -257,10 +254,7 @@ def render_document_show_field_value *args
document = args.shift || options[:document]

field = args.shift || options[:field]
field_config = document_show_fields(document)[field]
value = options[:value] || get_field_values(document, field, field_config, options)

render_field_value value, field_config
presenter(document).render_document_show_field_value field, options
end

##
Expand All @@ -271,7 +265,7 @@ def render_document_show_field_value *args
# @return [String]
def document_heading document=nil
document ||= @document
render_field_value(document[blacklight_config.view_config(:show).title_field] || document.id)
presenter(document).document_heading
end

##
Expand All @@ -284,11 +278,7 @@ def document_heading document=nil
def document_show_html_title document=nil
document ||= @document

if blacklight_config.view_config(:show).html_title_field
render_field_value(document[blacklight_config.view_config(:show).html_title_field])
else
document_heading document
end
presenter(document).document_show_html_title
end

##
Expand All @@ -310,7 +300,7 @@ def render_document_heading(*args)

tag ||= :h4

content_tag(tag, render_field_value(document_heading(document)), :itemprop => "name")
content_tag(tag, presenter(document).document_heading, :itemprop => "name")
end

##
Expand All @@ -329,55 +319,18 @@ def render_document_heading(*args)
# @param [Blacklight::Solr::Configuration::SolrField] solr field configuration
# @param [Hash] options additional options to pass to the rendering helpers
def get_field_values document, field, field_config, options = {}
# retrieving values
value = case
when (field_config and field_config.highlight)
# retrieve the document value from the highlighting response
document.highlight_field(field_config.field).map { |x| x.html_safe } if document.has_highlight_field? field_config.field
when (field_config and field_config.accessor)
# implicit method call
if field_config.accessor === true
document.send(field)
# arity-1 method call (include the field name in the call)
elsif !field_config.accessor.is_a?(Array) && document.method(field_config.accessor).arity != 0
document.send(field_config.accessor, field)
# chained method calls
else
Array(field_config.accessor).inject(document) do |result, method|
result.send(method)
end
end
else
# regular solr
document.get(field, :sep => nil) if field
end

# rendering values
case
when (field_config and field_config.helper_method)
send(field_config.helper_method, options.merge(:document => document, :field => field, :value => value))
when (field_config and field_config.link_to_search)
link_field = if field_config.link_to_search === true
field_config.field
else
field_config.link_to_search
end

Array(value).map do |v|
link_to render_field_value(v, field_config), search_action_path(add_facet_params(link_field, v, {}))
end if field
else
value
end
presenter(document).get_field_values field, field_config, options
end

##
# Render a value (or array of values) from a field
#
# @deprecated Use DocumentPresenter instead
# @param [String] value or list of values to display
# @param [Blacklight::Solr::Configuration::SolrField] solr field configuration
# @return [String]
def render_field_value value=nil, field_config=nil
Deprecation.warn self, "render_field_value is deprecated. Use DocumentPresenter.render_field_value instead"
safe_values = Array(value).collect { |x| x.respond_to?(:force_encoding) ? x.force_encoding("UTF-8") : x }

if field_config and field_config.itemprop
Expand All @@ -392,6 +345,7 @@ def render_field_value value=nil, field_config=nil
#
# @return [String]
def field_value_separator
Deprecation.warn self, "field_value_separator is deprecated. Use DocumentPresenter.field_value_separator instead"
', '
end

Expand Down Expand Up @@ -544,12 +498,7 @@ def document_partial_path_templates
# @option opts [Proc] :label Evaluate the given proc
# @option opts [String] :label Render the given string
def render_document_index_label doc, opts = {}
label = nil
label ||= doc.get(opts[:label], :sep => nil) if opts[:label].instance_of? Symbol
label ||= opts[:label].call(doc, opts) if opts[:label].instance_of? Proc
label ||= opts[:label] if opts[:label].is_a? String
label ||= doc.id
render_field_value label
presenter(doc).render_document_index_label opts
end

##
Expand Down Expand Up @@ -582,4 +531,15 @@ def render_bookmarks_control?
has_user_authentication_provider? and current_or_guest_user.present?
end

##
# Returns a document presenter for the given document
def presenter(document)
presenter_class.new(document, self)
end

##
# Override this method if you want to use a different presenter class
def presenter_class
Blacklight::DocumentPresenter
end
end
7 changes: 4 additions & 3 deletions lib/blacklight.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ module Blacklight

autoload :User, 'blacklight/user'

autoload :Controller, 'blacklight/controller'
autoload :Base, 'blacklight/base'
autoload :Catalog, 'blacklight/catalog'
autoload :Controller, 'blacklight/controller'
autoload :Base, 'blacklight/base'
autoload :Catalog, 'blacklight/catalog'
autoload :DocumentPresenter, 'blacklight/document_presenter'

autoload :Routes, 'blacklight/routes'

Expand Down
168 changes: 168 additions & 0 deletions lib/blacklight/document_presenter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
module Blacklight
class DocumentPresenter
include ActionView::Helpers::OutputSafetyHelper
include ActionView::Helpers::TagHelper

# @param [SolrDocument] document
# @param [ActionController::Base] controller scope for linking and generating urls
# @param [Blacklight::Configuration] configuration
def initialize(document, controller, configuration = controller.blacklight_config)
@document = document
@configuration = configuration
@controller = controller
end

##
# Get the value of the document's "title" field, or a placeholder
# value (if empty)
#
# @param [SolrDocument] document
# @return [String]
def document_heading
render_field_value(@document[@configuration.view_config(:show).title_field] || @document.id)
end

##
# Get the document's "title" to display in the <title> element.
# (by default, use the #document_heading)
#
# @see #document_heading
# @return [String]
def document_show_html_title
if @configuration.view_config(:show).html_title_field
render_field_value(@document[@configuration.view_config(:show).html_title_field])
else
document_heading
end
end

##
# Render a value (or array of values) from a field
#
# @param [String] value or list of values to display
# @param [Blacklight::Solr::Configuration::SolrField] solr field configuration
# @return [String]
def render_field_value value=nil, field_config=nil
safe_values = Array(value).collect { |x| x.respond_to?(:force_encoding) ? x.force_encoding("UTF-8") : x }

if field_config and field_config.itemprop
safe_values = safe_values.map { |x| content_tag :span, x, :itemprop => field_config.itemprop }
end

safe_join(safe_values, (field_config.separator if field_config) || field_value_separator)
end

##
# Render the document index heading
#
# @param [Hash] opts
# @option opts [Symbol] :label Render the given field from the document
# @option opts [Proc] :label Evaluate the given proc
# @option opts [String] :label Render the given string
def render_document_index_label opts = {}
label = nil
label ||= @document.get(opts[:label], :sep => nil) if opts[:label].instance_of? Symbol
label ||= opts[:label].call(@document, opts) if opts[:label].instance_of? Proc
label ||= opts[:label] if opts[:label].is_a? String
label ||= @document.id
render_field_value label
end

##
# Render the index field label for a document
#
# Allow an extention point where information in the document
# may drive the value of the field
# @param [String] field
# @param [Hash] opts
# @options opts [String] :value
def render_index_field_value field, options = {}
field_config = @configuration.index_fields[field]
value = options[:value] || get_field_values(field, field_config, options)

render_field_value value, field_config
end

##
# Render the show field value for a document
#
# Allow an extention point where information in the document
# may drive the value of the field
# @param [String] field
# @param [Hash] options
# @options opts [String] :value
def render_document_show_field_value field, options={}
field_config = @configuration.show_fields[field]
value = options[:value] || get_field_values(field, field_config, options)

render_field_value value, field_config
end

##
# Get the value for a document's field, and prepare to render it.
# - highlight_field
# - accessor
# - solr field
#
# Rendering:
# - helper_method
# - link_to_search
# TODO : maybe this should be merged with render_field_value, and the ugly signature
# simplified by pushing some of this logic into the "model"
# @param [SolrDocument] document
# @param [String] field name
# @param [Blacklight::Solr::Configuration::SolrField] solr field configuration
# @param [Hash] options additional options to pass to the rendering helpers
def get_field_values field, field_config, options = {}
# retrieving values
value = case
when (field_config and field_config.highlight)
# retrieve the document value from the highlighting response
@document.highlight_field(field_config.field).map { |x| x.html_safe } if @document.has_highlight_field? field_config.field
when (field_config and field_config.accessor)
# implicit method call
if field_config.accessor === true
@document.send(field)
# arity-1 method call (include the field name in the call)
elsif !field_config.accessor.is_a?(Array) && @document.method(field_config.accessor).arity != 0
@document.send(field_config.accessor, field)
# chained method calls
else
Array(field_config.accessor).inject(@document) do |result, method|
result.send(method)
end
end
else
# regular solr
@document.get(field, :sep => nil) if field
end

# rendering values
case
when (field_config and field_config.helper_method)
@controller.send(field_config.helper_method, options.merge(:document => @document, :field => field, :value => value))
when (field_config and field_config.link_to_search)
link_field = if field_config.link_to_search === true
field_config.field
else
field_config.link_to_search
end

Array(value).map do |v|
@controller.link_to render_field_value(v, field_config), @controller.search_action_path(@controller.add_facet_params(link_field, v, {}))
end if field
else
value
end
end

##
# Default separator to use in #render_field_value
#
# @return [String]
def field_value_separator
', '
end

end
end
3 changes: 3 additions & 0 deletions spec/helpers/blacklight_helper_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,9 @@ def mock_document_app_helper_url *args
end

describe "render_field_value" do
before do
Deprecation.stub(:warn)
end
it "should join and html-safe values" do
expect(helper.render_field_value(['a', 'b'])).to eq "a, b"
end
Expand Down
Loading

0 comments on commit f57b8e3

Please sign in to comment.