module SimpleNavigation # Holds the Items for a navigation 'level' (either the primary_navigation or a sub_navigation). class ItemContainer attr_reader :items attr_accessor :renderer, :dom_id, :dom_class def initialize #:nodoc: @items = [] @renderer = Configuration.instance.renderer end # Creates a new navigation item. # # The key is a symbol which uniquely defines your navigation item in the scope of the primary_navigation or the sub_navigation. # # The name will be displayed in the rendered navigation. This can also be a call to your I18n-framework. # # The url is the address that the generated item points to. You can also use url_helpers (named routes, restful routes helper, url_for etc.) # # The options can be used to specify the following things: # * html_attributes - will be included in the rendered navigation item (e.g. id, class etc.) # * :if - Specifies a proc to call to determine if the item should # be rendered (e.g. :if => Proc.new { current_user.admin? }). The # proc should evaluate to a true or false value and is evaluated in the context of the view. # * :unless - Specifies a proc to call to determine if the item should not # be rendered (e.g. :unless => Proc.new { current_user.admin? }). The # proc should evaluate to a true or false value and is evaluated in the context of the view. # # The block - if specified - will hold the item's sub_navigation. def item(key, name, url, options={}, &block) (@items << Item.new(key, name, url, options, block)) if should_add_item?(options) end # Returns the Item with the specified key, nil otherwise. def [](navi_key) items.find {|i| i.key == navi_key} end # Renders the items in this ItemContainer using the configured renderer. # # Set include_sub_navigation to true if you want to nest the sub_navigation into the active primary_navigation def render(current_navigation, include_sub_navigation=false, current_sub_navigation=nil) self.renderer.new(current_navigation, current_sub_navigation).render(self, include_sub_navigation) end private # partially borrowed from ActionSupport::Callbacks def should_add_item?(options) #:nodoc: [options.delete(:if)].flatten.compact.all? { |m| evaluate_method(m) } && ![options.delete(:unless)].flatten.compact.any? { |m| evaluate_method(m) } end # partially borrowed from ActionSupport::Callbacks def evaluate_method(method) #:nodoc: case method when Proc, Method method.call else raise ArgumentError, ":if or :unless must be procs or lambdas" end end end end