codeplant/simple-navigation

Second level only rendered for currently selected branch

Closed this issue · 8 comments

This is similar to a previous report I gave, but it's actually a different issue.

Here's my config file, in config/dashboard_navigation.rb

SimpleNavigation::Configuration.run do |navigation|
  navigation.items do |primary|
    primary.item :reports, 'Reports', reports_stores_url do |sub_nav| 
      sub_nav.item :reports_cms, '<i class="fa fa-bar-chart"></i> CMS Report'.html_safe, reports_stores_url, if: -> { can? :read, CmsStatistic }
    end

    primary.item :devices, 'Devices', devices_url do |sub_nav| 
      sub_nav.item :devices_list, '<i class="fa fa-desktop"></i> Manage'.html_safe, devices_url, if: -> { can? :read, Device }
    end

    primary.item :stores_and_groups, 'Stores &amp; Groups', groups_url do |sub_nav| 
      sub_nav.item :stores_and_groups_groups, '<i class="fa fa-users"></i> Groups'.html_safe, groups_url, if: -> { can? :manage, Group }
      sub_nav.item :stores_and_groups_stores, '<i class="fa fa-building"></i> Stores'.html_safe, stores_url, if: -> { can? :manage, Store }
      sub_nav.item :stores_and_groups_stores_map, '<i class="fa fa-map"></i> Stores map'.html_safe, stores_map_url, if: -> { can? :manage, Store }
    end
    primary.item :cms, 'CMS', cms_topics_url do |sub_nav| 
      sub_nav.item :cms_surveys, '<i class="fa fa-homework"></i> Surveys'.html_safe, questionnaires_surveys_list_url, if: -> { can? :manage, Questionnaire }
      sub_nav.item :cms_assessments, '<i class="fa fa-homework"></i> Assessments'.html_safe, questionnaires_assessments_list_url, if: -> { can? :manage, Questionnaire }
      sub_nav.item :cms_training, '<i class="fa fa-homework"></i> Training'.html_safe, questionnaires_training_list_url, if: -> { can? :manage, Questionnaire }
      sub_nav.item :cms_topics, '<i class="fa fa-book"></i> Topics'.html_safe, cms_topics_url, if: -> { can? :manage, Topic }
      sub_nav.item :cms_categories, '<i class="fa fa-book"></i> Categories'.html_safe, cms_categories_url, if: -> { can? :manage, Category }
    end
    primary.item :advertising, 'Advertising', campaigns_url do |sub_nav| 
      sub_nav.item :advertising_advertisers, '<i class="fa fa-user"></i> Advertisers'.html_safe, advertisers_url, if: -> { can? :read, Advertiser }
      sub_nav.item :advertising_creatives, '<i class="fa fa-play"></i> Creatives'.html_safe, creatives_url, if: -> { can? :read, Creative }
      sub_nav.item :advertising_creative_exceptions, '<i class="fa fa-exclamation-triangle"></i> Creative exceptions'.html_safe, creative_exceptions_url, if: -> { can? :read, CreativeException }
      sub_nav.item :advertising_campaigns, '<i class="fa fa-calendar-plus-o"></i> Campaigns'.html_safe, campaigns_url, if: -> { can? :read, Campaign }
      sub_nav.item :advertising_ad_roll_templates, '<i class="fa fa-refresh"></i> Ad Roll Templates'.html_safe, ad_roll_templates_url, if: -> { can? :read, AdRollTemplate }
    end
    primary.item :administration, 'Administration', dashboard_users_url do |sub_nav| 
      sub_nav.item :administration_users, '<i class="fa fa-users"></i> Dashboard Users'.html_safe, dashboard_users_url, if: -> { can? :manage, User }
    end
  end

  navigation.name_generator = Proc.new do |name, item|

    if item.key == :'reports'
      "<i class='fa fa-bar-chart'></i> <span class='nav-label'>#{name}</span><span class='fa arrow'></span>".html_safe
    elsif item.key == :'cms'
      "<i class='fa fa-book'></i> <span class='nav-label'>#{name}</span><span class='fa arrow'></span>".html_safe
    elsif item.key == :'advertising'
      "<i class='fa fa-tv'></i> <span class='nav-label'>#{name}</span><span class='fa arrow'></span>".html_safe
    elsif item.key == :'administration'
      "<i class='fa fa-gears'></i> <span class='nav-label'>#{name}</span><span class='fa arrow'></span>".html_safe
    elsif item.key == :'devices'
      "<i class='fa fa-desktop'></i> <span class='nav-label'>#{name}</span><span class='fa arrow'></span>".html_safe
    elsif item.key == :'stores_and_groups'
      "<i class='fa fa-building'></i> <span class='nav-label'>#{name}</span><span class='fa arrow'></span>".html_safe
    else
      name
    end
  end
end

I have a custom renderer, placed at app/navigation_renderers/dashboard_renderer.rb, with the following code:

class DashboardRenderer < SimpleNavigation::Renderer::Base
  def render(item_container)
    if skip_if_empty? && item_container.empty?
      ''
    else
      tag = options[:ordered] ? :ol : :ul
      content = list_content(item_container)

      if item_container.level == 1
        content.html_safe
      else
        html_attributes = {class: 'nav nav-second-level collapse'}
        if content.empty?
          byebug
        end

        content_tag(tag, content, item_container.dom_attributes.merge(html_attributes))
      end
    end
  end

  private

  def list_content(item_container)
    item_container.items.map { |item|
      li_options = item.html_options.except(:link)
      li_content = tag_for(item)
      if include_sub_navigation?(item)
        li_content << render_sub_navigation_for(item)
      end
      content_tag(:li, li_content, li_options)
    }.join
  end

  def suppress_link?(item)
    item.sub_navigation && item.sub_navigation.level == 2
  end

  def tag_for(item)
    if suppress_link?(item)
      '<a href="">' + content_tag('span', item.name, link_options_for(item).except(:method)) + '</a>'
    else
      link_to(item.name, item.url, options_for(item))
    end
  end
end

Finally, my navigation template has this line, calling the renderer's main method:

              <%= render_navigation( context: :dashboard, renderer: DashboardRenderer ) %> 

When at my site's root URL, the resulting HTML is as follows (I print my own ul tags around this output)

    <li id="reports"><a href=""><span><i class="fa fa-bar-chart"></i> <span class="nav-label">Reports</span><span class="fa arrow"></span></span></a></li>
    <li id="devices"><a href=""><span><i class="fa fa-desktop"></i> <span class="nav-label">Devices</span><span class="fa arrow"></span></span></a></li>
    <li id="stores_and_groups"><a href=""><span><i class="fa fa-building"></i> <span class="nav-label">Stores &amp; Groups</span><span class="fa arrow"></span></span></a></li>
    <li id="cms"><a href=""><span><i class="fa fa-book"></i> <span class="nav-label">CMS</span><span class="fa arrow"></span></span></a></li>
    <li id="advertising"><a href=""><span><i class="fa fa-tv"></i> <span class="nav-label">Advertising</span><span class="fa arrow"></span></span></a></li>
    <li id="administration"><a href=""><span><i class="fa fa-gears"></i> <span class="nav-label">Administration</span><span class="fa arrow"></span></span></a></li>

If I manually go to a 2nd level URL, like cms/topics, I get this output:

<li id="reports"><a href=""><span><i class="fa fa-bar-chart"></i> <span class="nav-label">Reports</span><span class="fa arrow"></span></span></a></li>
    <li id="devices"><a href=""><span><i class="fa fa-desktop"></i> <span class="nav-label">Devices</span><span class="fa arrow"></span></span></a></li>
    <li id="stores_and_groups"><a href=""><span><i class="fa fa-building"></i> <span class="nav-label">Stores &amp; Groups</span><span class="fa arrow"></span></span></a></li>
    <li id="cms" class="selected">
        <a href=""><span class="selected"><i class="fa fa-book"></i> <span class="nav-label">CMS</span><span class="fa arrow"></span></span></a>
        <ul class="nav nav-second-level collapse">
            <li id="cms_surveys"><a href="http://dashboard/cms/questionnaire/survey"><i class="fa fa-homework"></i> Surveys</a></li>
            <li id="cms_assessments"><a href="http://dashboard/cms/questionnaire/assessment"><i class="fa fa-homework"></i> Assessments</a></li>
            <li id="cms_training"><a href="http://dashboard/cms/questionnaire/training"><i class="fa fa-homework"></i> Training</a></li>
            <li id="cms_topics" class="selected simple-navigation-active-leaf"><a class="selected" href="http://dashboard/cms/topics"><i class="fa fa-book"></i> Topics</a></li>
            <li id="cms_categories"><a href="http://dashboard/cms/categories"><i class="fa fa-book"></i> Categories</a></li>
        </ul>
    </li>
    <li id="advertising"><a href=""><span><i class="fa fa-tv"></i> <span class="nav-label">Advertising</span><span class="fa arrow"></span></span></a></li>
    <li id="administration"><a href=""><span><i class="fa fa-gears"></i> <span class="nav-label">Administration</span><span class="fa arrow"></span></span></a></li>

What am I doing wrong?

Thanks for answering on the other thread, it actually solved my problem. The solution was to call the renderer with expand_all: true.

andi commented

So what is wrong from your viewpoint? To me it looks like standard behaviour: on your root path it can't match any primary item (no url matches and no regex set to match) and when your move to /cms/topics it matches the cms primary item and expands it subnav...?

andi commented

ok

I can send you a link to the staging site so you can see the use case, if you want.

andi commented

so if this issue is still relevant, pls clarify what your expectation would be in your current setup if go to root path and to cms/topic path.

OK so in my scenario, the navigation's first level (Administration, CMS, Advertising etc.) don't have matching controllers or pages in my app, they are just groups for 2nd-level links. It makes no sense for them to have a URL.

So when I'm at the root level, none of them should be selected or expanded, but I should be able to expand each of them one at a time (the design includes an accordion-style bootstrap mechanism) to explore their sub-links.

When I click on one of the sub-links, I need that link's parent (the nav group it belongs to) to be both selected and expanded, and the sub-link to be selected, while all the other groups are collapsed, non-selected but expandable (their sub-links are rendered but hidden until the group is clicked).

With the code I have pasted above and the expand_all: true setting, this works exactly the way I want it to.

andi commented

Ok :-) So I will close this...

Thanks for your help Andi!