module BreadcrumbTrail # A Builder that is used by # {ActionController::HelperMethods#render_breadcrumbs}. This should # be subclassed and implemented. # # @abstract class Builder # Initialize the builder. # # @param context [ActionView::Base] The base of the view being # rendered. # @param breadcrumbs [Array] The breadcrumbs to # render. # @param options [Hash] The options for the builder. def initialize(context, breadcrumbs, options = {}, &block) @context = context @breadcrumbs = breadcrumbs @options = options @block = block end # Renders the breadcrumbs using the builder. However, since this # is the base, it raises an error. # # @raise [NotImplementedError] # @return [String] def call raise NotImplementedError end end # Used along with a block given to the initializer, this renders # the breadcrumbs. class BlockBuilder < Builder # Creates a buffer, and iterates over every breadcrumb, yielding # the breadcrumb to the block given on initialization. # # @return [String] def call buffer = ActiveSupport::SafeBuffer.new @breadcrumbs.each do |breadcrumb| buffer << @block.call(breadcrumb.computed(@context)) end buffer end end # Creates a structure of HTML elements to render the breadcrumbs. class HTMLBuilder < Builder include ActionView::Helpers # Renders the breadcrumbs in HTML tags. If no options were # provided on initialization, it uses defaults. # # @option @options [String] :outer ("ol") The outer tag element # to use. # @option @options [String] :inner ("li") The inner tag element # to use. # @option @options [Hash] :outer_options (nil) The outer tag # element attributes to use. Things like `class="some-class"` # are best placed here. # @option @options [Hash] :inner_options (nil) The inner tag # element attributes to use. Things like `class="some-class"` # are best placed here. # @return [String] def call outer_tag = @options.fetch(:outer, "ol") inner_tag = @options.fetch(:inner, "li") outer = tag(outer_tag, @options.fetch(:outer_options, nil), true) if outer_tag inner = tag(inner_tag, @options.fetch(:inner_options, nil), true) if inner_tag buffer = ActiveSupport::SafeBuffer.new buffer.safe_concat(outer) if outer_tag @breadcrumbs.each do |breadcrumb| buffer.safe_concat(inner) if inner_tag buffer << link_to(breadcrumb.computed_name(@context), breadcrumb.computed_path(@context), breadcrumb.options) buffer.safe_concat("") if inner_tag end buffer.safe_concat("") if outer_tag buffer end end end