dnyce
dnyce

Reputation: 415

Custom Renderer in Simple Navigation (Rails Gem)

I'm trying to create a custom renderer for the simple_navigation rails gem. So far, after reading through the tweaks made for the bootstrap version of the gem, I have been able to make some minor icon changes to my navigation but I'm completely stuck otherwise.

  1. I'm trying to add some set my renderer up to accommodate the markup found at this JSfiddle: http://jsfiddle.net/v5Yhc/

    <ul class="nav navbar-collapse collapse navbar-collapse-primary">
    
      <li class="active">
        <span class="glow"></span>
        <a href="dashboard.html">
            <i class="icon-dashboard icon-2x"></i>
            <span>Dashboard</span>
        </a>
      </li>
    
      <li class="dark-nav ">
        <span class="glow"></span>
    
        <a class="accordion-toggle collapsed " data-toggle="collapse" href="#yJ6h3Npe7C">
            <i class="icon-beaker icon-2x"></i>
                  <span>
                    UI Lab
                    <i class="icon-caret-down"></i>
                  </span>
        </a>
    
        <ul id="yJ6h3Npe7C" class="collapse ">  
          <li class="">
            <a href="../ui_lab/buttons.html">
                <i class="icon-hand-up"></i> Buttons
            </a>
          </li>
    
          <li class="">
            <a href="../ui_lab/general.html">
                <i class="icon-beaker"></i> General elements
            </a>
          </li>
    
          <li class="">
            <a href="../ui_lab/icons.html">
                <i class="icon-info-sign"></i> Icons
            </a>
          </li>
    
          <li class="">
            <a href="../ui_lab/grid.html">
                <i class="icon-th-large"></i> Grid
            </a>
          </li>
    
          <li class="">
            <a href="../ui_lab/tables.html">
                <i class="icon-table"></i> Tables
            </a>
          </li>
    
          <li class="">
            <a href="../ui_lab/widgets.html">
                <i class="icon-plus-sign-alt"></i> Widgets
            </a>
          </li>
        </ul>
      </li>
    
      <li class="">
        <span class="glow"></span>
        <a href="../forms/forms.html">
            <i class="icon-edit icon-2x"></i>
            <span>Forms</span>
        </a>
      </li>
    
      <li class="">
        <span class="glow"></span>
        <a href="../charts/charts.html">
            <i class="icon-bar-chart icon-2x"></i>
            <span>Charts</span>
        </a>
      </li>
    
      <li class="dark-nav ">
    
        <span class="glow"></span>
    
        <a class="accordion-toggle" data-toggle="collapse" href="#WLGsdJPav9">
            <i class="icon-link icon-2x"></i>
                  <span>
                    Others
                    <i class="icon-caret-down"></i>
                  </span>
        </a>
    
        <ul id="WLGsdJPav9" class="in" style="height: auto;">      
          <li class="">
            <a href="../other/wizard.html">
                <i class="icon-magic"></i> Wizard
            </a>
          </li>
    
          <li class="">
            <a href="../other/login.html">
                <i class="icon-user"></i> Login Page
            </a>
          </li>
    
          <li class="">
            <a href="../other/sign_up.html">
                <i class="icon-user"></i> Sign Up Page
            </a>
          </li>
        </ul>
      </li>
    </ul>
    
    1. I can't figure out how to lay out the ruby/rails code so that it mirrors the behavior of the markup in the fiddle?

    2. The kicker here is that the children UL/LI elements must be presented on page load, but the simple navigation GEM hides them until their parent UL/LI element is active.... frustratingly.... without fail.

Here is my custom renderer code:

class Admin < SimpleNavigation::Renderer::Base
  def render(item_container)
    config_selected_class = SimpleNavigation.config.selected_class
    SimpleNavigation.config.selected_class = 'active'
    list_content = item_container.items.inject([]) do |list, item|
      li_options = item.html_options.reject {|k, v| k == :link}
      icon = li_options.delete(:icon)
      split = (include_sub_navigation?(item) and li_options.delete(:split))
      li_content = content_tag(:span, '', class: 'glow')
      li_content << tag_for(item, item.name, icon, split)
      if include_sub_navigation?(item)
        if split
          lio = li_options.dup
          lio[:class] = [li_options[:class], 'dropdown-split-left'].flatten.compact.join(' ')
          list << content_tag(:li, li_content, lio)
          item.html_options[:link] = nil
          li_options[:id] = nil
          li_content = tag_for(item)
        end
        item.sub_navigation.dom_class = [item.sub_navigation.dom_class, 'dropdown-menu', split ? 'pull-right' : nil].flatten.compact.join(' ')
        li_content << render_sub_navigation_for(item)
        li_options[:class] = [li_options[:class], 'dropdown', split ? 'dropdown-split-right' : nil].flatten.compact.join(' ')
      end
      list << content_tag(:li, li_content, li_options)
    end.join
    SimpleNavigation.config.selected_class = config_selected_class
    if skip_if_empty? && item_container.empty?
      ''
    else  
      content_tag(:ul, list_content, {:id => item_container.dom_id, :class => item_container.dom_class}) 
    end
  end

  protected

  def tag_for(item, name = '', icon = nil, split = false)
    unless item.url or include_sub_navigation?(item)
      return item.name
    end
    url = item.url
    link = Array.new
    link << content_tag(:i, '', :class => [icon].flatten.compact.join(' ') + ' icon-2x') unless icon.nil?
    link << name
    if include_sub_navigation?(item)
      item_options = item.html_options
      item_options[:link] = Hash.new if item_options[:link].nil?
      item_options[:link][:class] = Array.new if item_options[:link][:class].nil?
      unless split
        #item_options[:link][:class] << 'dropdown-toggle'
        item_options[:link][:class] << 'in'
        #item_options[:link][:'data-toggle'] = 'dropdown'
        item_options[:link][:'data-toggle'] = 'collapse'
        item_options[:link][:'data-target'] = '#'
        #link << content_tag(:b, '', :class => 'caret')
        link << content_tag(:b, '', :class => 'icon-caret-down')
      end
      item.html_options = item_options
    end
    link_to(link.join(" ").html_safe, url, options_for(item))
  end

end

Is anyone a simple_navigation whiz?

Thanks!

Upvotes: 0

Views: 1548

Answers (1)

Andi Schacke
Andi Schacke

Reputation: 357

Regarding your two specific questions:

I can't figure out how to lay out the ruby/rails code so that it mirrors the behavior of the markup in the fiddle?

The target html structure seems pretty complicated to me. Is there any way to simplify this? In addition, it probably would be easier to help if you would fork the simple-navigation bootstrap renderer so it would be more obvious what you have changed.

The kicker here is that the children UL/LI elements must be presented on page load, but the simple navigation GEM hides them until their parent UL/LI element is active.... frustratingly.... without fail.

simple-navigation is - by default - configured that it only renders all primary items and the subnavigation of the active primary item, so this is a feature, not a bug :-). If you need to render the complete navigation independently of the active item, you need to pass the :expand_all => true option to the render_navigation call, which in turn is used to determine the return value of SimpleNavigation::Rendering::Renderer::Base#include_sub_navigation?.

Upvotes: 1

Related Questions