foraker/navigatrix

View on GitHub
README.md

Summary

Maintainability
Test Coverage
# Navigatrix
[![Build Status](https://api.travis-ci.org/foraker/navigatrix.png?branch=master)](http://travis-ci.org/foraker/navigatrix)
[![Code Climate](https://codeclimate.com/github/foraker/navigatrix.png)](https://codeclimate.com/github/foraker/navigatrix)

Navigation generation for Rails and Sinatra.

## Installation
Add `gem "navigatrix"` to your Gemfile and run `bundle install`.

### The Simplest Possible Navigation
```ERB
<%= render_navigation({
  "Home"     => "/",
  "About Us" => "/about-us",
  "Blog"     => "/blog",
  "Contact"  => "/contact"
}) %>
```
Assuming we're on the "/about-us" path, the resulting HTML will look like this:
```HTML
<ul>
  <li><a href="/">Home</a></li>
  <li class="active">About Us</li>
  <li><a href="/blog">Blog</a></li>
  <li><a href="/contact">Contact</a></li>
</ul>
```

### A More Sophisticated Configuration
```ERB
<%= render_navigation({
  "Home" => "/",
  "Users" => {
    :path   => "/users",
    :active_states => [
      {:path => "/my_account"},
      {:path  => /\/users\/\d*/},
    ]
  },
  "Sign In" => {
    :path   => "/sign_in",
    :render? => !user_signed_in?
  },
  "Sign Out" => {
    :path   => "/sign_out",
    :render? => user_signed_in?
  }
}, {
  :item => {
    :active_class => "active-nav-item"
  },
  :list => {
    :html_attributes => {
      :class => "nav"
    }
  }
}) %>
```

Assuming we're on the "/users/1" path, and a User is signed in, the resulting HTML will look like this:
```HTML
<ul class="nav">
  <li><a href="/">Home</a></li>
  <li class="active-nav-item"><a href="/users">Users</a></li>
  <li><a href="/sign_out">Sign Out</a></li>
</ul>
```
The "Users" item is active and not linked because the path "/users/1" matches the pattern `/\/users\/\d*/`.  The "Home" item is linked because we are not on the path "/".

## List Configuration Options
List configuration options are supplied via the `:list` option when rendering a navigation.  For example,

```Ruby
render_navigation(config, {
  list: {
    html_attributes: {
      class: "nav"
    }
  }
})
```

A list accepts the following configuration options:

##### `:html_attributes`
HTML attributes added to an the list.

## List Item Configuration Options

List item configuration options can be supplied to all list items or a single list item.  Supply options to a single list item via the navigation configuration.

```Ruby
render_navigation({
  "Home" => {
    path: "/",
    active_class: "home-active"
  }
})
```

The following options are supported.

##### `:path`
Specifies where the navigation item should link to.

##### `:active_states`
An array of state specification hashes used to control when a list item is considered "active".  By default, when an item is active, it receives an HTML class of "active". For example:
```Ruby
active_states: [
  {controller: "users", actions: ["index"]},
  {path: "/my-account"}
]
```
The first state specification dictates that the item will be active when the current controller is the `UsersController` and the current controller action is `index`.  If we wanted the item to be active for any `UsersController` action, the specification should be `{controller: "users"}`.

The second state specification dictates that the item will be active with the current path is "/my-account".  `:path` can be a string or regular expression.

##### `:unlinked_states`
Also an array of state specification hashes (like `:active_states`).  The state specifications determine if the item should be linked.  By default, the item is unlinked if the current path is the same as the item path.  The `:unlinked_states` option can be used to override this behavior.

##### `:html_attributes`
HTML attributes added to an item.
```Ruby
  "Item 3" => {
    :path => "/item_path"
    :html_attributes => {:id => "nav-3"}
  }
```
Results in the following HTML.
```HTML
<li id="nav-3"><a href="item_path">Item 3</a></li>
```

##### `:children`
Used for creating nested navigations.  The `:children` should contain a navigation configuration.
```Ruby
"Parent" => {
  :path => "/parent_path",
  :children => {
    "Child 1" => "/child_1_path",
    "Child 2" => {
      :path => "/child_2_path",
      :children => {
        "Grandchild" => "/grandchild_path"
      }
    }
  }
}
```
Results in the following HTML.
```HTML
<ul>
  <li>
    <a href="/parent_path">Parent</a>
    <ul>
      <li><a href="/child_1_path">Child 1</a></li>
      <li>
        <a href="/child_2_path">Child 2</a>
        <ul>
          <li href="/grandchild_path">Grandchild</li>
        </ul>
      </li>
    </ul>
  </li>
</ul>
```

##### `:render?`
Determines if the navigation item is rendered.

### Supplying options to all list items
List configuration options are supplied via the `:item` option when rendering a navigation.  For example,
```Ruby
render_navigation(config, {
  item: {
    active_class: "active-item"
  }
})
```

Supported options are:

##### `:active_class`
Determines which HTML class is applied to list items when the item is active.

##### `:inactive_class`
Determines which HTML class is applied to list items when the item is *not* active.

`active_class`, `inactive_class`, `html_attributes`.

## Building Custom List Renderers

To change the default list rendering from \<ul> tags to \<section> tags with an id of "nav", create a custom list renderer:

```Ruby
Navigatrix.register_list_renderer(:my_custom_list) do |renderer|
  renderer.wrapper do |items, html_attributes|
    content_tag(:section, items, html_attributes.merge_attribute(:id, "nav"))
  end
end
```

```ERB
<%= render_navigation({
  "Home"     => "/",
  "About Us" => "/about-us",
}, {
  list: {renderer: :my_custom_list}
}) %>
```

## Building Custom Item Renderers

If the basic list and and item configuration, custom renders can be registered.

For example, to add change the default item rendering from \<li> tags to \<p> tags, create a custom item renderer:

```Ruby
Navigatrix.register_item_renderer(:my_custom_item) do |renderer|
  renderer.wrapper do |content, children, html_attributes|
    content(:p, content + children, html_attributes)
  end
end
```

```ERB
<%= render_navigation({
  "Home"     => "/",
  "About Us" => "/about-us",
}, {
  item: {renderer: :my_custom_item}
}) %>
```

#### All item rendering options

`wrapper` - wraps item content - accepts `content, children, html_attributes`

`linked` - content when the item is linked - accepts `name, path`

`unlinked` - content when the item is not linked - accepts `name, path`

`html_attributes` - HTML attributes for the item

`children_options` - attributes passed to the child list

## About Foraker Labs

![Foraker Logo](http://assets.foraker.com/attribution_logo.png)

Foraker Labs builds exciting web and mobile apps in Boulder, CO. Our work powers a wide variety of businesses with many different needs. We love open source software, and we're proud to contribute where we can. Interested to learn more? [Contact us today](https://www.foraker.com/contact-us).

This project is maintained by Foraker Labs. The names and logos of Foraker Labs are fully owned and copyright Foraker Design, LLC.