module EffectiveMenusHelper def render_menu(menu, options = {}, &block) menu = Effective::Menu.find_by_title(menu) if menu.kind_of?(String) return "<ul class='nav navbar-nav'><li>Menu '#{menu}' does not exist</li></ul>".html_safe if !menu.present? if (effectively_editting? rescue false) options[:menu_id] = menu.id form_for(menu, :url => '/') { |form| options[:form] = form } end if block_given? && options[:form].blank? render_menu_items(menu.menu_items, options) { yield } else render_menu_items(menu.menu_items, options) end # if options[:for_editor] #else # Rails.cache.fetch(menu) { render_menu_items(menu.menu_items, options) } #end end def render_menu_items(items, options = {}, &block) if options[:form].present? && options[:form].kind_of?(ActionView::Helpers::FormBuilder) == false raise 'Expecting ActionView::Helpers::FormBuilder object for :form => option' end html = '' if options[:form] html << "<ul class='nav navbar-nav effective-menu #{options[:class]}'" html << " data-effective-menu-id='#{options[:menu_id] || 0}'" html << " data-effective-menu-expand-html=\"#{render(:partial => 'admin/menu_items/expand').gsub('"', "'").gsub("\n", '').gsub(' ', '')}\"" html << " data-effective-menu-new-html=\"#{render(:partial => 'admin/menu_items/new', :locals => { :item => Effective::MenuItem.new(), :form => options[:form] }).gsub('"', "'").gsub("\n", '').gsub(' ', '').gsub('[0]', '[:new]').gsub('_0_', '_:new_')}\"" maxdepth = ((options[:maxdepth].presence || EffectivePages.menu[:maxdepth].presence).to_i rescue 0) html << " data-effective-menu-maxdepth='#{maxdepth}'" if maxdepth > 0 html << ">" else html << "<ul class='nav navbar-nav#{' ' + options[:class].to_s if options[:class].present?}'>" end stack = [items.to_a.first] # A stack to keep track of rgt values. skip_to_lft = 0 # This lets us skip over nodes we don't have visible_for? permission to see items.each_with_index do |item, index| next if index == 0 # We always skip the first Root node # This allows us to skip over nodes we don't have permission to view next if item.lft < skip_to_lft if options[:form].blank? && !item.visible_for?(defined?(current_user) ? current_user : nil) skip_to_lft = item.rgt + 1 next end if stack.size > 1 html << "<ul class='dropdown-menu'>" if (item.rgt < stack.last.rgt) # Level down? while item.rgt > stack.last.rgt # Level up? stack.pop html << "</ul></li>" if (item.rgt > stack.last.rgt) end end # Render the <li>...</li> with carets only on top level dropdowns, not sub dropdowns html << render_menu_item(item, stack.size == 1, options) stack.push(item) end while stack.size > 0 item = stack.pop if stack.size == 0 # Very last one html << render(:partial => 'admin/menu_items/actions') if options[:form] html << (capture(&block) || '') if block_given? && !options[:form] html << '</ul>' elsif item.leaf? == false html << '</ul></li>' end end html.html_safe end private # This is where we actually build out an li item def render_menu_item(item, caret, options) html = "" url = ( if item.menuable.kind_of?(Effective::Page) effective_pages.page_path(item.menuable) elsif item.divider? nil elsif (item.special || '').end_with?('_path') self.send(item.special) rescue nil elsif item.url.present? item.url end ).presence || '#' classes = (item.classes || '').split(' ') classes << 'active' if EffectivePages.menu[:apply_active_class] && request.try(:fullpath) == url classes << 'divider' if item.divider? classes << 'dropdown' if item.dropdown? classes = classes.join(' ') if item.leaf? html << (classes.present? ? "<li class='#{classes}'>" : "<li>") if !item.divider? || options[:form] # Show the URL in edit mode, but not normally html << render_menu_item_anchor_tag(item, caret, url) end if options[:form] html << render(:partial => 'admin/menu_items/item', :locals => { :item => item, :form => options[:form] }) end html << "</li>" else html << (classes.present? ? "<li class='#{classes}'>" : "<li>") html << render_menu_item_anchor_tag(item, caret, url) if options[:form] html << render(:partial => 'admin/menu_items/item', :locals => { :item => item, :form => options[:form] }) end end html end def render_menu_item_anchor_tag(item, caret, url) new_window_html = (item.new_window? ? " target='_blank'" : "") if item.special == 'destroy_user_session_path' "<a href='#{url}' data-method='delete' data-no-turbolink='true'>#{item.title}</a>" elsif item.dropdown? ''.tap do |html| html << "<a href='#{url}' data-toggle='dropdown'#{new_window_html}>#{item.title}" html << "<span class='caret'></span>" if caret html << "</a>" end else "<a href='#{url}'#{new_window_html}>#{item.title}</a>" end end end