lib/simple_navigation/item.rb
module SimpleNavigation
# Represents an item in your navigation.
# Gets generated by the item method in the config-file.
class Item
attr_reader :key,
:name,
:sub_navigation,
:url,
:options
# see ItemContainer#item
#
# The subnavigation (if any) is either provided by a block or
# passed in directly as <tt>items</tt>
def initialize(container, key, name, url = nil, opts = {}, &sub_nav_block)
self.container = container
self.key = key
self.name = name.respond_to?(:call) ? name.call : name
self.url = url.respond_to?(:call) ? url.call : url
self.options = opts
setup_sub_navigation(options[:items], &sub_nav_block)
end
# Returns the item's name.
# If :apply_generator option is set to true (default),
# the name will be passed to the name_generator specified
# in the configuration.
#
def name(options = {})
options = { apply_generator: true }.merge(options)
if options[:apply_generator]
config.name_generator.call(@name, self)
else
@name
end
end
# Returns true if this navigation item should be rendered as 'selected'.
# An item is selected if
#
# * it has a subnavigation and one of its subnavigation items is selected or
# * its url matches the url of the current request (auto highlighting)
#
def selected?
@selected ||= selected_by_subnav? || selected_by_condition?
end
# Returns the html-options hash for the item, i.e. the options specified
# for this item in the config-file.
# It also adds the 'selected' class to the list of classes if necessary.
def html_options
html_opts = options.fetch(:html) { Hash.new }
html_opts[:id] ||= autogenerated_item_id
classes = [html_opts[:class], selected_class, active_leaf_class]
classes = classes.flatten.compact.join(' ')
html_opts[:class] = classes if classes && !classes.empty?
html_opts
end
# Returns the configured active_leaf_class if the item is the selected leaf,
# nil otherwise
def active_leaf_class
if !selected_by_subnav? && selected_by_condition?
config.active_leaf_class
end
end
# Returns the configured selected_class if the item is selected,
# nil otherwise
def selected_class
if selected?
container.selected_class || config.selected_class
end
end
# Returns the :highlights_on option as set at initialization
def highlights_on
@highlights_on ||= options[:highlights_on]
end
# Returns the :method option as set at initialization
def method
@method ||= options[:method]
end
# Returns the html attributes for the link as set with the :link_html option
# at initialization
def link_html_options
@link_html_options ||= options[:link_html]
end
protected
# Returns true if item has a subnavigation and
# the sub_navigation is selected
def selected_by_subnav?
sub_navigation && sub_navigation.selected?
end
# Returns true if the item's url matches the request's current url.
def selected_by_condition?
highlights_on ? selected_by_highlights_on? : selected_by_autohighlight?
end
# Returns true if both the item's url and the request's url are root_path
def root_path_match?
url == '/' && SimpleNavigation.request_path == '/'
end
# Returns the item's id which is added to the rendered output.
def autogenerated_item_id
config.id_generator.call(key) if config.autogenerate_item_ids
end
# Return true if auto_highlight is on for this item.
def auto_highlight?
config.auto_highlight && container.auto_highlight
end
private
attr_accessor :container
attr_writer :key,
:name,
:sub_navigation,
:url,
:options
def config
SimpleNavigation.config
end
def request_uri
SimpleNavigation.request_uri
end
def remove_anchors(url_with_anchors)
url_with_anchors && url_with_anchors.split('#').first
end
def remove_query_params(url_with_params)
url_with_params && url_with_params.split('?').first
end
def url_for_autohighlight
relevant_url = remove_anchors(self.url) if config.ignore_anchors_on_auto_highlight
relevant_url = remove_query_params(relevant_url) if config.ignore_query_params_on_auto_highlight
relevant_url
end
def selected_by_autohighlight?
return false unless auto_highlight?
return false unless self.url
root_path_match? ||
(url_for_autohighlight && SimpleNavigation.current_page?(url_for_autohighlight)) ||
autohighlight_by_subpath?
end
def autohighlight_by_subpath?
config.highlight_on_subpath && selected_by_subpath?
end
def selected_by_highlights_on?
case highlights_on
when Regexp then !!(request_uri =~ highlights_on)
when Proc then highlights_on.call
when :subpath then selected_by_subpath?
else
fail ArgumentError, ':highlights_on must be a Regexp, Proc or :subpath'
end
end
def selected_by_subpath?
escaped_url = Regexp.escape(url_for_autohighlight)
!!(request_uri =~ /^#{escaped_url}(\/|$||\?)/i)
end
def setup_sub_navigation(items = nil, &sub_nav_block)
return unless sub_nav_block || items
self.sub_navigation = ItemContainer.new(container.level + 1)
if sub_nav_block
sub_nav_block.call sub_navigation
else
sub_navigation.items = items
end
end
end
end