module CamaleonCms::Frontend::NavMenuHelper # draw nav menu as html list # key: slug for nav menu # to register this, go to admin -> appearance -> menus # (DEPRECATED) def get_nav_menu(key = 'main_menu', class_name = "navigation") draw_menu({menu_slug: key, container_class: class_name}) end # draw menu as an html # default configurations is for bootstrap support def draw_menu(args = {}) args_def = { menu_slug: 'main_menu', #slug for the menu container: 'ul', #type of container for the menu container_id: '', #container id for the menu container_class: 'nav navbar-nav nav-menu', #container class for the menu item_container: 'li', #type of container for the items item_current: 'current-menu-item', #class for current menu item item_class: 'menu-item', # class for all menu items item_class_parent:"dropdown", # class for all menu items that contain sub items sub_container: 'ul', #type of container for sub items sub_class: 'dropdown-menu', # class for sub container callback_item: lambda{|args| }, # callback executed for each item (args = { menu_item, link, level, settings, has_children, link_attrs = "", index}). # menu_item: (Object) Menu object # link: (Hash) link data: {link: '', name: ''} # level: (Integer) current level # has_children: (boolean) if this item contain sub menus # settings: (Hash) menu settings # index: (Integer) Index Position of this menu # link_attrs: (String) Here you can add your custom attrs for current link, sample: id='my_id' data-title='#{args[:link][:name]}' # item_container_attrs: (String) Here you can add your custom attrs for link container. # In settings you can change the values for this item, like after, before, ..: # sample: lambda{|args| args[:settings][:after] = "" if args[:has_children]; args[:link_attrs] = "id='#{menu_item.id}'"; } # sample: lambda{|args| args[:settings][:before] = "" if args[:level] == 0 && args[:index] == 0; } before: '', # content before link text after: '', # content after link text link_current: 'current-link', # class for current menu link link_before: '', # content before link link_after: '', # content after link link_class: 'menu_link', # class for all menu links link_class_parent:"dropdown-toggle", # class for all menu links that contain sub items levels: -1, # max of levels to recover, -1 => return all levels container_prepend: '', # content prepend for menu container container_append: '' # content append for menu container } args = args_def.merge(args) nav_menu = current_site.nav_menus.find_by_slug(args[:menu_slug]) nav_menu = current_site.nav_menus.first unless nav_menu.present? html = "<#{args[:container]} class='#{args[:container_class]}' id='#{args[:container_id]}'>#{args[:container_prepend]}{__}#{args[:container_append]}#{args[:container]}>" if nav_menu.present? html = html.sub("{__}", cama_menu_draw_items(args, nav_menu.children.reorder(:term_order))) else html = html.sub("{__}", "") end html end # draw menu items def cama_menu_draw_items(args, nav_menu, level = 0) html = "" parent_current = false index = 0 nav_menu.eager_load(:metas).each do |nav_menu_item| _args = args.dup data_nav_item = _get_link_nav_menu(nav_menu_item) next if data_nav_item == false _is_current = data_nav_item[:current] || site_current_path == data_nav_item[:link] || site_current_path == data_nav_item[:link].sub(".html", "") has_children = nav_menu_item.have_children? && (args[:levels] == -1 || (args[:levels] != -1 && level <= args[:levels])) r = { menu_item: nav_menu_item.decorate, link: data_nav_item, level: level, settings: _args, has_children: has_children, link_attrs: '', item_container_attrs: '', index: index } args[:callback_item].call(r) _args = r[:settings] if has_children html_children, current_children = cama_menu_draw_items(args, nav_menu_item.children.reorder(:term_order), level + 1) else html_children, current_children = "", false end parent_current = true if _is_current || current_children html += "<#{_args[:item_container]} #{r[:item_container_attrs]} class='#{_args[:item_class]} #{_args[:item_class_parent] if has_children} #{"#{_args[:item_current]}" if _is_current} #{"current-menu-ancestor" if current_children }'>#{_args[:link_before]} #{_args[:before]}#{data_nav_item[:name]}#{_args[:after]} #{_args[:link_after]} #{ html_children } #{_args[:item_container]}>" index += 1 end if level == 0 html else html = "<#{args[:sub_container]} class='#{args[:sub_class]} #{"parent-#{args[:item_current]}" if parent_current} level-#{level}'>#{html}#{args[:sub_container]}>" [html, parent_current] end end # filter and parse all menu items visible for current user and adding the flag for current_parent or current_item # max_levels: max levels to iterate # return an multidimensional array with all items until level 'max_levels' # internal_level: ingnore (managed by internal recursion) def cama_menu_parse_items(items, max_levels=-1, internal_level=0) res, is_current_parent, levels = [], false, [0] items.reorder(:term_order).each_with_index do |nav_menu_item, index| data_nav_item = _get_link_nav_menu(nav_menu_item) next if data_nav_item == false _is_current = data_nav_item[:current] || site_current_path == data_nav_item[:link] || site_current_path == data_nav_item[:link].sub(".html", "") has_children = nav_menu_item.have_children? has_children = false if max_levels > 0 && max_levels == internal_level data_nav_item[:label] = data_nav_item[:name] data_nav_item[:url] = data_nav_item[:link] r = { menu_item: nav_menu_item.decorate, level: internal_level, has_children: has_children, index: index, current_item: _is_current, current_parent: false, levels: 0 }.merge(data_nav_item.except(:current, :name, :link)) if has_children r[:children], _is_current_parent, r[:levels] = cama_menu_parse_items(nav_menu_item.children, max_levels, internal_level + 1) if _is_current_parent is_current_parent = true r[:current_parent] = true end r[:levels] = r[:levels] + 1 end is_current_parent = true if r[:current_item] levels << r[:levels] res << r end if internal_level == 0 res else [res, is_current_parent, levels.max] end end #******************* BREADCRUMBS ******************* # draw the breadcrumb as html list def breadcrumb_draw res = [] @_front_breadcrumb.each_with_index do |item, index| if @_front_breadcrumb.size == (index+1) #last menu res << "