h1. Navigasmic Semantic navigation; a semantic way to build beautifully simple navigation structures in Rails. h2. The Story Most of the navigation styles I've done over the years pretty much boil down to this idea: Use simple markup, and do the rest with css (and javascript if you need it). So, yeah, the default markup is beautifully simple (UL and LI tags). Ok, so navigation is easy right? Until you start managing active/highlighted, disabled states, and more if you may need them. This can quickly become a mess, and all too often it just stays in the views with whatever logic tossed on top of it as people go. I've seen it too many times, and I wanted to do something about it. I went in with these requirements: * Should be simple * Should be easily customizable * Should handle active/highlighted states * Should handle disabled states * Should be pleasant to use * Should use less code to create than it generates And then I wrote a DSL that met those requirements:
<% semantic_navigation :main do |n| %> <%= n.group 'Media' do %> <%= n.item 'Image Gallery', :link => '/media/images', :highlights_on => '/media/videos' %> <%= n.item 'Videos', :link => '/media/videos', :disabled_if => proc { true } %> <%= n.item 'Contact Us' # auto links to the contact_us_path if it exists %> <% end %> <% end %>Since I clearly needed something that allowed for customization I ended up emulating the way Rails uses form builders. With some ideas taken from formtastic, I setup navigasmic to use builders. There are two builders that are provided (HTML for ERB, HAML, etc. and XML for ERB, Builder, etc), and these builders can be extended or replaced if you need more custom markup. Currently the HTML builder generates UL and LI tags, which helps with SEO, and the XML builder generates tags that can be used for XML site maps. h2. Installation The gem is hosted on gemcutter, so *if you haven't already*, add it as a gem source:
sudo gem sources -a http://gemcutter.org/Then install the navigasmic gem:
sudo gem install navigasmich2. Usage h3. HAML *Simple Usage*
- semantic_navigation :main do |n| = n.group 'Media', :html => {:class => 'media'} do = n.item 'Image Gallery', :link => {:controller => 'media/images'} = n.item 'Videos', :link => {:controller => 'media/videos'} = n.group 'Info' do = n.item 'About Us', :link => '/about_us', :html => {:title => 'we are the coolest'} = n.item 'Nothing Here'...produces...
*Nesting of items and additional markup*
- semantic_navigation :main, :html => { :class => 'primary' } do |n| = n.group 'Media' do = n.item 'Image Gallery', :link => {:controller => 'media/images', :action => 'index'} = n.item 'Videos', :link => {:controller => 'media/videos'} .secondary = n.group 'Info' do = n.item 'About Us', :link => '/about_us' do %ul = n.item 'Nothing Here'...produces...
*Highlighting* -- highlights on the media controller (or any that inherit from it), on the /images path, and on mondays
- semantic_navigation :main do = n.item 'Image Gallery', :link => 'media/images' :highlights_on => [{:controller => 'media'}, '/images', proc { Time.now.wday == 1 }]...produces
*Disabling* -- disabled on tuesdays, and when not logged in
- semantic_navigation :main do = n.item 'Image Gallery', :link => 'media/images' :disabled_if => proc { Time.now.wday == 2 || !logged_in? }...produces
h3. ERB *Nesting of items and additional markup*
<% semantic_navigation :main, :html => { :class => 'primary' } do |n| %> <%= n.group 'Media' do %> <%= n.item 'Image Gallery', :link => {:controller => 'media/images', :action => 'index'} %> <%= n.item 'Videos', :link => {:controller => 'media/videos'} %> <% end %>...produces...<%= n.group 'Info' do %> <%= n.item 'About Us', :link => '/about_us' do %><% end %><%= n.item 'Nothing Here' %>
<% end %> <% end %>
h3. XML The XML Builder isn't hashed out completely, but it more or less generates google sitemap style xml. I don't know if the format is entirely correct in terms of nesting (it would make sense if it is), and I'd invite anyone who would like to hash it out more to do so. *Simple Usage Using Builder*
xml.instruct! :xml, :version => '1.0', :encoding => 'UTF-8' semantic_navigation :primary, :builder => Navigasmic::XmlNavigationBuilder do |n| n.group 'Media' do n.item 'Image Gallery', :link => {:controller => 'media/images', :action => 'index'} n.item 'Videos', :link => {:controller => 'media/videos'}, :changefreq => 'monthly' end end...produces...
*Simple Usage Using HAML*http://host:port/media/images yearly http://host:port/media/videos monthly
- semantic_navigation :primary, :builder => Navigasmic::XmlNavigationBuilder, :changefreq => 'daily' do |n| = n.item 'Image Gallery', :link => {:controller => 'media/images', :action => 'index'} = n.item 'Videos', :link => {:controller => 'media/videos'}, :changefreq => 'monthly'...produces...
Tip: You can check the template_format and use the XML Builder when it's :xml, and the HTML Builder if not. @:builder => template_format == :xml ? Navigasmic::XmlNavigationBuilder : nil@ h3. Other You can always create your own builder by extending one of the existing ones, or creating one from scratch. Then just specify your builder, or do it as a configuration. @semantic_navigation :main, :builder => MyCustomBuilder do@ @Navigasmic::SemanticNavigationHelper.builder = MyCustomBuilder@ h2. Documentation RDoc documentation _should_ be automatically generated after each commit and made available on the "rdoc.info website":http://rdoc.info/projects/jejacks0n/navigasmic. h2. Compatibility I'm only testing with the latest Rails 2.3.x stable release, and it should work under Rails 2.3.x as well. Feel free to add backwards compatibility if you need it. h2. Project Info Navigasmic is hosted on Github: "http://github.com/jejacks0n/navigasmic":http://github.com/jejacks0n/navigasmic, and the gem is available on Gemcutter: "http://gemcutter.org/gems/navigasmic":http://gemcutter.org/gems/navigasmic Copyright (c) Jeremy Jackson, released under the MIT license.http://host:port/media/images daily http://host:port/media/videos monthly