navigation_builder 1.0.0.beta1 → 1.0.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,7 +1,115 @@
1
1
  Navigation Builder
2
2
  ==================
3
3
 
4
+ While at [RailsConf](http://www.railsconf.com) in the Spring/Summer of 2011, [Bruce Williams](http://github.com/bruce) mentioned a gem he wrote called ["Goose"](http://github.com/bruce/goose) that made generating navigation really easy. After looking through the code, I immediately thought of some tweaks that I wanted to make.
4
5
 
6
+ Rather than dealing with forks and pull requests, I just decided to spin off my own implementation from scratch, modeling the API after ActionView's FormBuilder.
7
+
8
+ #### That's great, let me see some code. ####
9
+
10
+ <% navigation_for :main do |nav| %>
11
+ <%= nav.link_to 'Home', '#' %>
12
+ <% end %>
13
+
14
+ Generates:
15
+
16
+ <ul>
17
+ <li>
18
+ <a href="#">Home</a>
19
+ </li>
20
+ </ul>
21
+
22
+ #### How do you mark a link as selected? ####
23
+
24
+ <% navigation_select 'Home' %>
25
+
26
+ Make sure that is called *before* the navigation is rendered in the view.
27
+
28
+ That will generate:
29
+
30
+ <ul>
31
+ <li class="selected">
32
+ <a href="#">Home</a>
33
+ </li>
34
+ </ul>
35
+
36
+ #### I don't want to use the class "selected". I'd rather use "current-page" ####
37
+
38
+ <% navigation_for :main, :selected_class => "current-page" do |nav| %>
39
+ <%= nav.link_to 'Home', '#' %>
40
+ <% end %>
41
+
42
+ #### But my links need additional HTML! ####
43
+
44
+ NavigationBuilder supports the same options that the `link_to` helper does:
45
+
46
+ <% navigation_for :sub_nav do |nav| %>
47
+ <% nav.link_to '#' do %>
48
+ <em>Home</em>
49
+ <span>Go to your home! Are you too good for your home?!</span>
50
+ <% end %>
51
+ <% end %>
52
+
53
+ #### Doesn't that mean that I need to repeat the entire `link_to` block when marking a link as selected? ####
54
+
55
+ Not at all, just use a regular expression:
56
+
57
+ <% navigation_select /Home/ %>
58
+
59
+ #### But what if I have multiple blocks of navigation on the page? ####
60
+
61
+ <% navigation_select 'Home', :in => :sub_nav %>
62
+
63
+ And in your layout:
64
+
65
+ <% navigation_for :sub_nav do |nav| %>
66
+ <%= nav.link_to 'Home', '#' %>
67
+ <% end %>
68
+
69
+ #### Well... what if I need an Ordered List! ####
70
+
71
+ <% navigation_for :main, :wrapper_tag => :ol do |nav| %>
72
+ <%= nav.link_to 'Home', '#' %>
73
+ <% end %>
74
+
75
+ Generates:
76
+
77
+ <ol>
78
+ <li class="selected">
79
+ <a href="#">Home</a>
80
+ </li>
81
+ </ol>
82
+
83
+ #### Nevermind, I hate lists. I just want DIVs. ####
84
+
85
+ <% navigation_for :main, :nav_item_tag => :div do |nav| %>
86
+ <%= nav.link_to 'Home', '#' %>
87
+ <% end %>
88
+
89
+ Generates:
90
+
91
+ <div class="selected">
92
+ <a href="#">Home</a>
93
+ </div>
94
+
95
+ #### My designer just said that's DIV-soup. ####
96
+
97
+ <% navigation_for :main, :nav_item_tag => false do |nav| %>
98
+ <%= nav.link_to 'Home', '#' %>
99
+ <% end %>
100
+
101
+ Generates:
102
+
103
+ <a href="#" class="selected">Home</a>
104
+
105
+ #### Why didn't you name this Gem "Wolfman" ####
106
+
107
+ Originally I was going to. But if you came across a method named "wolfman" in your view code, it would not be entirely clear as to what it was going to do.
108
+ So I just went with something boring and generic.
109
+
110
+ #### Well, you've thought of everything, haven't you! ####
111
+
112
+ Probably not, let me know if you have any feature requests!
5
113
 
6
114
  TODOs
7
115
  =====
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.0.beta1
1
+ 1.0.0.beta2
@@ -3,15 +3,19 @@ module ActionView
3
3
 
4
4
  module NavigationBuilderHelper
5
5
 
6
+ # Holds references to the currently selected links for each navigation block on the page.
6
7
  def navigation_builder
7
8
  @navigation_builder ||= { :main => nil }
8
9
  end
9
10
 
10
- # <% navigation_for :popup do |n| %>
11
- # <%= nav_to 'Design', :action => :design %>
12
- # <% end %>
13
- #
14
- # <%= navigation_select 'Design', :in => :popup %>
11
+ # Generates a block of navigation to be rendered to the page.
12
+ #
13
+ # Example:
14
+ # <% navigation_for :popup do |n| %>
15
+ # <%= nav_to 'Members', members_path %>
16
+ # <% end %>
17
+ #
18
+ # Generally speaking, this should go in your layout.
15
19
  def navigation_for( nav_name, options = {}, &block )
16
20
  raise ArgumentError, "Missing block" unless block_given?
17
21
 
@@ -27,11 +31,24 @@ module ActionView
27
31
  concat( tag(options[:wrapper_tag], options[:html], true) ) if navigation_has_wrapper?( options )
28
32
  yield builder.new(self, nav_name, options, block)
29
33
  concat("</#{options[:wrapper_tag]}>".html_safe) if navigation_has_wrapper?( options )
34
+
35
+ # Mark the navigation block has having been rendered
36
+ navigation_builder[nav_name] = true
30
37
  end
31
38
 
39
+ # Make sure this is called *before* your navigation is rendered.
40
+ # Ideally, this should go in your views and navigation_for() should
41
+ # be in your layout.
42
+ #
43
+ # Example:
44
+ # <%= navigation_select 'Members', :in => :popup %>
32
45
  def navigation_select( link_name, options = {} )
33
- options.reverse_merge!( :in => :main )
34
- navigation_builder[options[:in]] = link_name
46
+ if navigation_builder[options[:in]] == true
47
+ raise RuntimeError, "The #{options[:in]} navigation block has already been rendered. You cannot call navigation_select if navigation_for has already been called."
48
+ else
49
+ options.reverse_merge!( :in => :main )
50
+ navigation_builder[options[:in]] = link_name
51
+ end
35
52
  end
36
53
 
37
54
  private
@@ -44,21 +61,28 @@ module ActionView
44
61
 
45
62
  class NavigationBuilder
46
63
 
64
+ # Initializes the NavigationBuilder.
65
+ # You'll mostly likely never call this method directly.
47
66
  def initialize( template, nav_name, options, proc )
48
67
  @template, @nav_name, @options, @proc = template, nav_name, options, proc
49
68
  end
50
69
 
70
+ # Builds a link_to tag within the context of the current navigation block.
71
+ # This accepts all of the same parameters that ActiveView's link_to method
72
+ #
73
+ # Example:
74
+ # <%= nav.link_to 'Home', '#' %>
51
75
  def link_to( *args, &link_block )
52
76
  if block_given?
53
77
  name = @template.capture(&link_block)
54
78
  options = args.first || {}
55
- html_options = args.second
79
+ html_options = args.second || {}
56
80
 
57
81
  link_to_in_block( name, options, html_options, &link_block )
58
82
  else
59
83
  name = args[0]
60
84
  options = args[1] || {}
61
- html_options = args[2]
85
+ html_options = args[2] || {}
62
86
 
63
87
  link_to_in_html( name, options, html_options )
64
88
  end
@@ -69,7 +93,7 @@ module ActionView
69
93
  def link_to_in_block( name, options, html_options, &link_block )
70
94
  item_html_options = extract_item_options!( html_options )
71
95
 
72
- set_selected_link( name, item_html_options ) if is_selected?( name )
96
+ set_selected_link( name, html_options, item_html_options ) if is_selected?( name )
73
97
 
74
98
  @template.concat( @template.tag( @options[:nav_item_tag], item_html_options, true) ) if @options[:nav_item_tag]
75
99
  @template.link_to(options, html_options, &link_block)
@@ -79,7 +103,7 @@ module ActionView
79
103
  def link_to_in_html( name, options, html_options )
80
104
  item_html_options = extract_item_options!( html_options )
81
105
 
82
- set_selected_link( name, item_html_options ) if is_selected?( name )
106
+ set_selected_link( name, html_options, item_html_options ) if is_selected?( name )
83
107
 
84
108
  link_html = @template.link_to(name, options, html_options)
85
109
 
@@ -94,8 +118,16 @@ module ActionView
94
118
  options.try(:delete, :item_html) || {}
95
119
  end
96
120
 
97
- def set_selected_link( name, item_html_options )
98
- ((item_html_options[:class] ||= '') << " #{@options[:selected_class]}").strip!
121
+ def set_selected_link( name, html_options, item_html_options )
122
+ (selected_tag_options( html_options, item_html_options ) << " #{@options[:selected_class]}").strip!
123
+ end
124
+
125
+ def selected_tag_options( html_options, item_html_options )
126
+ if @options[:nav_item_tag]
127
+ item_html_options[:class] ||= ''
128
+ else
129
+ html_options[:class] ||= ''
130
+ end
99
131
  end
100
132
 
101
133
  def is_selected?( name )
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{navigation_builder}
8
- s.version = "1.0.0.beta1"
8
+ s.version = "1.0.0.beta2"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Derek Lindahl"]
@@ -187,8 +187,19 @@ class TestNavigationBuilder < ActionView::TestCase
187
187
  assert_dom_equal expected, output_buffer
188
188
  end
189
189
 
190
+ should "generate HTML that highlights the currently selected navigation link even where there is no item tag" do
191
+ navigation_select 'Foo', :in => :main
192
+
193
+ navigation_for :main, :nav_item_tag => false do |nav|
194
+ concat nav.link_to( 'Foo', '#' )
195
+ end
190
196
 
191
- # TODO: Add test for "selected" class when there is no item tag
197
+ expected = [
198
+ "<a href=\"#\" class=\"selected\">Foo</a>"
199
+ ].join('')
200
+
201
+ assert_dom_equal expected, output_buffer
202
+ end
192
203
 
193
204
  should "generate HTML that highlights the currently selected navigation link by using a Regular Expression" do
194
205
  navigation_select /Foo/, :in => :main
@@ -211,4 +222,13 @@ class TestNavigationBuilder < ActionView::TestCase
211
222
  assert_dom_equal expected, output_buffer
212
223
  end
213
224
 
225
+ should "raise an exception if a link is selected AFTER the navigation has been rendered" do
226
+ assert_raises RuntimeError do
227
+ navigation_for :main do |nav|
228
+ concat nav.link_to( 'Foo', '#' )
229
+ end
230
+ navigation_select 'Foo', :in => :main
231
+ end
232
+ end
233
+
214
234
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: navigation_builder
3
3
  version: !ruby/object:Gem::Version
4
- hash: 62196353
4
+ hash: 62196359
5
5
  prerelease: 6
6
6
  segments:
7
7
  - 1
8
8
  - 0
9
9
  - 0
10
10
  - beta
11
- - 1
12
- version: 1.0.0.beta1
11
+ - 2
12
+ version: 1.0.0.beta2
13
13
  platform: ruby
14
14
  authors:
15
15
  - Derek Lindahl