Module | Cms::MenuHelper |
In: |
app/helpers/cms/menu_helper.rb
|
This will render generate an array-of-hashes tree structure based on the page, which can be passed to render_menu in order to generate a menu.
With no options passed, it will generate a structure that includes all the child sections of the root and then it will include the path of decendent sections all the way to the current page.
Hidden pages will not be included, but if the first page in a Section is hidden, it will be used as the URL for that Section. This is commonly done to have a page for a Section and avoid having duplicates in the navigation.
You can change the behavior with the following options, all of these are optional:
Assume you have the structure the NFL, which is NFL > Conference > Division > Team, with teams being a Page, everything else a Section. Also, assume we are on the Baltimore Ravens page. If you‘re not a footbal fan, see sports.yahoo.com/nfl/teams
menu_items # => [ { :id => "section_2", :url => "/buf", :name => "AFC", :children => [ { :id => "section_3", :url => "/buf", :name => "East" }, { :id => "section_4", :url => "/bal", :name => "North", :children => [ { :id => "page_5", :selected => true, :url => "/bal", :name => "Baltimore Ravens" }, { :id => "page_6", :url => "/cin", :name => "Cincinnati Bengals" }, { :id => "page_7", :url => "/cle", :name => "Cleveland Browns" }, { :id => "page_8", :url => "/pit", :name => "Pittsburgh Steelers" } ] }, { :id => "section_9", :url => "/hou", :name => "South" }, { :id => "section_10}", :url => "/den", :name => "West" } ] }, { :id => "section_11", :url => "/dal", :name => "NFC" } ] menu_items(:depth => 2, :show_all_siblings => true) # => [ { :id => "section_2", :url => "/buf", :name => "AFC", :children => [ { :id => "section_3", :url => "/buf", :name => "East" }, { :id => "section_4", :url => "/bal", :name => "North" }, { :id => "section_5", :url => "/hou", :name => "South" }, { :id => "section_6", :url => "/den", :name => "West" } ] }, { :id => "section_7", :url => "/dal", :name => "NFC", :children => [ { :id => "section_8", :url => "/dal", :name => "East" }, { :id => "section_9", :url => "/chi", :name => "North" }, { :id => "section_10", :url => "/atl", :name => "South" }, { :id => "section_11", :url => "/ari", :name => "West" } ] } ]
# File app/helpers/cms/menu_helper.rb, line 106 106: def menu_items(options = {}) 107: # Intialize parameters 108: selected_page = options[:page] || @page 109: return nil unless selected_page 110: 111: # Path to the section 112: if options.has_key?(:path) 113: section_for_path = Section.find_by_path(options[:path]) 114: raise "Could not find section for path '#{options[:path]}'" unless section_for_path 115: ancestors = section_for_path.ancestors(:include_self => true) 116: else 117: ancestors = selected_page.ancestors 118: end 119: 120: if options.has_key?(:from_top) 121: ancestors = ancestors[options[:from_top].to_i..-1] || [] 122: end 123: 124: depth = options.has_key?(:depth) ? options[:depth].to_i : 1.0/0 125: show_all_siblings = options[:show_all_siblings] || false 126: 127: # We are defining a recursive lambda that takes the top-level sections 128: fn = lambda do |section_nodes, current_depth| 129: section_nodes.map do |section_node| 130: node = section_node.node 131: 132: item = {} 133: item[:id] = "#{section_node.node_type.underscore}_#{section_node.node_id}" 134: 135: # If we are showing a section item, we want to use the path for the first page 136: page = section_node.section? ? node.first_page_or_link : node 137: if section_node.section? && page 138: item[:selected] = true if page.hidden? && selected_page == page 139: else 140: item[:selected] = true if selected_page == page 141: end 142: 143: item[:url] = page && page.path || '#' 144: item[:name] = node.name 145: item[:target] = "_blank" if page.respond_to?(:new_window?) && page.new_window? 146: 147: # Now if this is a section, we do the child nodes, 148: # but only if the show_all_siblings parameter is true, 149: # or if this section is one of the current page's ancestors 150: # and also if the current depth is less than the target depth 151: if section_node.section? && 152: current_depth < depth && 153: (show_all_siblings || ancestors.include?(node)) && 154: !node.visible_child_nodes.empty? 155: item[:children] = fn.call(node.visible_child_nodes, current_depth + 1) 156: end 157: 158: item 159: end 160: end 161: 162: if ancestors.empty? 163: [] 164: else 165: fn.call(ancestors.first.visible_child_nodes(:limit => options[:limit]), 1) 166: end 167: end
Renders a menu. There are two options, neither are required:
The items should be an array of hashes, in a tree. Each hash can have the following keys (name and url are required, others are optional):
Edge Cases:
If both @page and :items are nil/empty, this will return an empty string. This might happen if used on an CMS rendered page, where @page isn't set.
# File app/helpers/cms/menu_helper.rb, line 29 29: def render_menu(options = {}) 30: options[:items] ||= menu_items(options) 31: return "" unless options[:items] 32: 33: options[:partial] ||= "cms/menus/menu" 34: options[:id] ||= "menu" 35: options[:class] ||= "menu" 36: render :partial => options[:partial], :locals => { :items => options[:items], :css_id => options[:id], :css_class => options[:class] } 37: end