simple-navigation 1.4.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
1
  .DS_Store
2
2
  rdoc
3
- pkg
3
+ pkg
4
+ coverage
data/CHANGELOG CHANGED
@@ -1,3 +1,11 @@
1
+ *2.0.0
2
+
3
+ * added auto_highlight feature. Active navigation is determined by comparing urls, no need to explicitly set it in the controllers anymore. Thanks to Jack Dempsey and Florian Hanke for the support on this.
4
+ * added ability to create multi-level navigations (not just limited to primary and secondary navigation). Thanks again to Jack Dempsey for the motivation ;-)
5
+ * simplified the process to explicitly set the navigation in the controller (where needed) - only deepest level has to be specified
6
+ * made auto_highlight feature configurable both on global and item_container's level
7
+ * config file is now evaluated in template if ever possible (not in controller anymore)
8
+
1
9
  *1.4.2
2
10
 
3
11
  * explicitly loading all source files when requiring 'simple_navigation'.
data/README CHANGED
@@ -1,7 +1,8 @@
1
1
 
2
2
  == Simple Navigation
3
3
 
4
- Simple Navigation is a plugin for creating a navigation (optionally with sub navigation) for your rails app.
4
+ Simple Navigation is a ruby library for creating navigations (with multiple levels) for your Ruby on Rails application.
5
+ If you upgrade to version 2.x.x please recheck the updated documentation on http://wiki.github.com/andi/simple-navigation.
5
6
 
6
7
  Source code:
7
8
  git://github.com/andi/simple-navigation.git
@@ -9,6 +10,9 @@ Source code:
9
10
  Documentation:
10
11
  http://wiki.github.com/andi/simple-navigation
11
12
 
13
+ RDoc:
14
+ http://andi.rubyforge.org
15
+
12
16
  Online Demo:
13
17
  http://simple-navigation-demo.andischacke.com
14
18
 
data/Rakefile CHANGED
@@ -11,6 +11,16 @@ Spec::Rake::SpecTask.new(:spec) do |t|
11
11
  t.spec_files = FileList['spec/**/*_spec.rb']
12
12
  end
13
13
 
14
+ namespace :spec do
15
+ desc "Run all specs with RCov"
16
+ Spec::Rake::SpecTask.new(:rcov) do |t|
17
+ t.spec_opts = ['--colour --format progress --loadby mtime --reverse']
18
+ t.spec_files = FileList['spec/**/*_spec.rb']
19
+ t.rcov = true
20
+ t.rcov_opts = ['--exclude', 'spec,/Users/']
21
+ end
22
+ end
23
+
14
24
  desc 'Generate documentation for the simple_navigation plugin.'
15
25
  Rake::RDocTask.new(:rdoc) do |rdoc|
16
26
  rdoc.rdoc_dir = 'rdoc'
@@ -24,10 +34,10 @@ begin
24
34
  require 'jeweler'
25
35
  Jeweler::Tasks.new do |gemspec|
26
36
  gemspec.name = "simple-navigation"
27
- gemspec.summary = "Simple Navigation is a ruby library for creating a navigation (optionally with sub navigation) for your rails app."
37
+ gemspec.summary = "Simple Navigation is a ruby library for creating navigations (with multiple levels) for your Ruby on Rails application."
28
38
  gemspec.email = "andreas.schacke@gmail.com"
29
39
  gemspec.homepage = "http://github.com/andi/simple-navigation"
30
- gemspec.description = "Simple Navigation is a ruby library for creating a navigation (optionally with sub navigation) for your rails app."
40
+ gemspec.description = "With the simple-navigation gem installed you can easily create multilevel navigations for your Ruby on Rails applications. The navigation is defined in a single configuration file. It supports automatic as well as explicit highlighting of the currently active navigation."
31
41
  gemspec.authors = ["Andi Schacke"]
32
42
  gemspec.rdoc_options = ["--inline-source", "--charset=UTF-8"]
33
43
  gemspec.files += ["CHANGELOG"]
@@ -36,6 +46,6 @@ begin
36
46
  Jeweler::RubyforgeTasks.new do |rubyforge|
37
47
  rubyforge.doc_task = "rdoc"
38
48
  end
39
- rescue LoadError
40
- puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
49
+ rescue LoadError => e
50
+ puts "Jeweler not available (#{e}). Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
41
51
  end
data/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
- :patch: 2
3
- :major: 1
4
- :minor: 4
2
+ :patch: 0
3
+ :major: 2
4
+ :minor: 0
@@ -12,10 +12,14 @@ SimpleNavigation::Configuration.run do |navigation|
12
12
  # driven hovering menus like the jquery superfish plugin
13
13
  # navigation.render_all_levels = true
14
14
 
15
- # Item keys are normally added to list items.
16
- # this setting turns that off
15
+ # Item keys are normally added to list items as id.
16
+ # This setting turns that off
17
17
  # navigation.autogenerate_item_ids = false
18
18
 
19
+ # The auto highlight feature is turned on by default.
20
+ # This turns it off globally (for the whole plugin)
21
+ # navigation.auto_highlight = false
22
+
19
23
  # Define the primary navigation
20
24
  navigation.items do |primary|
21
25
  # Add an item to the primary navigation. The following params apply:
@@ -42,6 +46,9 @@ SimpleNavigation::Configuration.run do |navigation|
42
46
  # works for all levels of the menu
43
47
  # primary.dom_id = 'menu-id'
44
48
  # primary.dom_class = 'menu-class'
49
+
50
+ # You can turn off auto highlighting for a specific level
51
+ # primary.auto_highlight = false
45
52
 
46
53
  end
47
54
 
@@ -6,25 +6,30 @@ module SimpleNavigation
6
6
  class Configuration
7
7
  include Singleton
8
8
 
9
- attr_accessor :renderer
10
- attr_accessor :selected_class
11
- attr_accessor :render_all_levels
12
- attr_accessor :autogenerate_item_ids
9
+ attr_accessor :renderer, :selected_class, :render_all_levels, :autogenerate_item_ids, :auto_highlight
13
10
  attr_reader :primary_navigation
14
11
 
15
12
  class << self
16
13
 
17
14
  # Evals the config_file for the given navigation_context inside the specified context (usually a controller or view)
18
15
  def eval_config(context, navigation_context = :default)
19
- context.instance_eval(SimpleNavigation.config_files[navigation_context])
20
16
  SimpleNavigation.controller = extract_controller_from context
17
+ SimpleNavigation.template = SimpleNavigation.controller.instance_variable_get(:@template)
18
+ context_for_eval.instance_eval(SimpleNavigation.config_files[navigation_context])
21
19
  end
22
-
20
+
23
21
  # Starts processing the configuration
24
22
  def run(&block)
25
23
  block.call Configuration.instance
26
24
  end
27
25
 
26
+ # Returns the context in which the config file should be evaluated.
27
+ # This is preferably the template, otherwise te controller
28
+ def context_for_eval
29
+ raise 'no context set for evaluation the config file' unless SimpleNavigation.template || SimpleNavigation.controller
30
+ SimpleNavigation.template || SimpleNavigation.controller
31
+ end
32
+
28
33
  # Extracts a controller from the context.
29
34
  def extract_controller_from(context)
30
35
  if context.respond_to? :controller
@@ -33,8 +38,8 @@ module SimpleNavigation
33
38
  context
34
39
  end
35
40
  end
36
-
37
- end
41
+
42
+ end #class << self
38
43
 
39
44
  # Sets the config's default-settings
40
45
  def initialize
@@ -42,6 +47,7 @@ module SimpleNavigation
42
47
  @selected_class = 'selected'
43
48
  @render_all_levels = false
44
49
  @autogenerate_item_ids = true
50
+ @auto_highlight = true
45
51
  end
46
52
 
47
53
  # Yields an SimpleNavigation::ItemContainer for adding navigation items
@@ -1,9 +1,12 @@
1
1
  #TODO: add :except and :only options to navigation method
2
2
  module SimpleNavigation
3
3
 
4
- # Adds methods for handling the current 'active' navigation to the controllers.
4
+ # Adds methods for explicitely setting the current 'active' navigation to the controllers.
5
+ # Since version 2.0.0 the simple_navigation plugin determines the active navigation based on the current url by default (auto highlighting),
6
+ # so explicitely defining the active navigation in the controllers is only needed for edge cases where automatic highlighting does not work.
5
7
  #
6
- # On the controller class level, use the navigation method to set the active navigation for all actions in the controller.
8
+ # On the controller class level, use the <tt>navigation</tt> method to set the active navigation for all actions in the controller.
9
+ # Let's assume that we have a primary navigation item :account which in turn has a sub navigation item :settings.
7
10
  #
8
11
  # ==== Examples
9
12
  # class AccountController << ActionController
@@ -12,15 +15,16 @@ module SimpleNavigation
12
15
  # end
13
16
  #
14
17
  # class AccountSettingsController << ActionController
15
- # navigation :account, :settings
18
+ # navigation :settings
16
19
  # ...
17
20
  # end
18
21
  #
19
- # The first example sets the current_primary_navigation to :account for all actions. No active sub_navigation.
20
- # The second example sets the current_primary_navigation to :account and the current_sub_navigation to :settings.
22
+ # The first example sets the current primary navigation to :account for all actions. No active sub_navigation.
23
+ # The second example sets the current sub navigation to :settings and since it is a child of :account the current primary navigation is set to :account.
21
24
  #
22
- # On the controller instance level, use the current_navigation method to define the active navigation for a specific action.
23
- # The navigation item that is set in current_navigation overrides the one defined on the controller class level (see navigation method).
25
+ # On the controller instance level, use the <tt>current_navigation</tt> method to define the active navigation for a specific action.
26
+ # The navigation item that is set in <tt>current_navigation</tt> overrides the one defined on the controller class level (see <tt>navigation</tt> method).
27
+ # Thus if you have an :account primary item with a :special sub navigation item:
24
28
  #
25
29
  # ==== Example
26
30
  # class AccountController << ActionController
@@ -28,13 +32,15 @@ module SimpleNavigation
28
32
  #
29
33
  # def your_special_action
30
34
  # ...
31
- # current_navigation :account, :special
35
+ # current_navigation :special
32
36
  # end
33
37
  # end
34
38
  #
35
- # The code above still sets the active primary navigation to :account but also sets the sub_navigation to :special for 'your_special_action'.
39
+ # The code above still sets the active primary navigation to :account for all actions, but sets the sub_navigation to :account -> :special for 'your_special_action'.
36
40
  #
37
- # Note: The specified symbols must match the keys for your navigation items in your config/navigation.rb file.
41
+ # Note 1: As you can see above you just have to set the navigation item of your 'deepest' navigation level as active and all its parents are marked as active, too.
42
+ #
43
+ # Note 2: The specified symbols must match the keys for your navigation items in your config/navigation.rb file.
38
44
  module ControllerMethods
39
45
  def self.included(base) #:nodoc:
40
46
  base.class_eval do
@@ -48,26 +54,24 @@ module SimpleNavigation
48
54
  module ClassMethods
49
55
  # Sets the active navigation for all actions in this controller.
50
56
  #
51
- # The specified symbols must match the keys for your navigation items in your config/navigation.rb file.
52
- def navigation(primary_navigation, sub_navigation=nil)
57
+ # The specified symbol must match the keys for your navigation items in your config/navigation.rb file.
58
+ def navigation(*args)
53
59
  self.class_eval do
54
- define_method :set_navigation do
55
- current_navigation(primary_navigation, sub_navigation)
60
+ define_method :sn_set_navigation do
61
+ current_navigation(*args)
56
62
  end
57
- before_filter :set_navigation
63
+ before_filter :sn_set_navigation
58
64
  end
59
65
  end
60
66
  end
61
67
 
62
68
  module InstanceMethods
63
-
64
69
  # Sets the active navigation. Call this method in any action to override the controller-wide active navigation
65
70
  # specified by navigation.
66
71
  #
67
- # The specified symbols must match the keys for your navigation items in your config/navigation.rb file.
68
- def current_navigation(primary_navigation, sub_navigation=nil)
69
- @current_primary_navigation = primary_navigation
70
- @current_secondary_navigation = sub_navigation
72
+ # The specified symbol must match the keys for your navigation items in your config/navigation.rb file.
73
+ def current_navigation(*args)
74
+ @sn_current_navigation_args = args
71
75
  end
72
76
  end
73
77
 
@@ -2,63 +2,78 @@ module SimpleNavigation
2
2
 
3
3
  # View helpers to render the navigation.
4
4
  #
5
- # Use render_primary_navigation to render your primary navigation with the configured renderer.
6
- # Use render_sub_navigation to render the sub navigation belonging to the active primary navigation.
7
- # Use render_navigation to render the primary navigation with the corresponding sub navigation rendered inside primary navigation item which is active.
5
+ # Use render_navigation as following to render your navigation:
6
+ # * call <tt>render_navigation</tt> without :level option to render your navigation as nested tree.
7
+ # * call <tt>render_navigation(:level => x)</tt> to render a specific navigation level (e.g. :level => 1 to render your primary navigation, :level => 2 to render the sub navigation and so forth)
8
8
  #
9
9
  # ==== Examples (using Haml)
10
- # #primary_navigation= render_primary_navigation
10
+ # #primary_navigation= render_navigation(:level => 1)
11
11
  #
12
- # #sub_navigation= render_sub_navigation
12
+ # #sub_navigation= render_navigation(:level => 2)
13
13
  #
14
- # #main_navigation= render_navigation
14
+ # #nested_navigation= render_navigation
15
15
  #
16
+ # Please note that <tt>render_primary_navigation</tt> and <tt>render_sub_navigation</tt> still work, but have been deprecated and may be removed in a future release.
16
17
  module Helpers
17
18
 
18
19
  # Renders the navigation according to the specified options-hash.
19
20
  #
20
21
  # The following options are supported:
21
- # * <tt>level</tt> - defaults to :nested which renders the the sub_navigation for an active primary_navigation inside that active primary_navigation item.
22
- # Other possible levels are :primary which only renders the primary_navigation (also see render_primary_navigation) and :secondary which only renders the sub_navigation (see render_sub_navigation).
23
- # * <tt>context</tt> - specifies the context for which you would render the navigation. Defaults to :default which loads the default navigation.rb (i.e. config/navigation.rb)
24
- # if you specify a context then the plugin tries to load the configuration file for that context, e.g. if you call <tt>render_navigation(:context => :admin)</tt> the file config/admin_navigation.rb
22
+ # * <tt>:level</tt> - defaults to :nested which renders the the sub_navigation for an active primary_navigation inside that active primary_navigation item.
23
+ # Specify a specific level to only render that level of navigation (e.g. :level => 1 for primary_navigation etc...).
24
+ # * <tt>:context</tt> - specifies the context for which you would render the navigation. Defaults to :default which loads the default navigation.rb (i.e. config/navigation.rb).
25
+ # If you specify a context then the plugin tries to load the configuration file for that context, e.g. if you call <tt>render_navigation(:context => :admin)</tt> the file config/admin_navigation.rb
25
26
  # will be loaded and used for rendering the navigation.
26
27
  #
27
28
  def render_navigation(*args)
28
29
  args = [Hash.new] if args.empty?
29
- default_options = {:context => :default, :level => :nested}
30
- level, navigation_context = case args.first
31
- when Hash
32
- options = default_options.merge(args.first)
33
- [options[:level], options[:context]]
34
- when Symbol
35
- [args[0], default_options.merge(args[1] || {})[:context]]
36
- else
37
- raise ArgumentError, "Invalid arguments"
38
- end
39
- SimpleNavigation.load_config(navigation_context)
40
- SimpleNavigation::Configuration.eval_config(self, navigation_context)
41
- case level
42
- when :primary
43
- SimpleNavigation.primary_navigation.render(@current_primary_navigation)
44
- when :secondary
45
- primary = SimpleNavigation.primary_navigation[@current_primary_navigation]
46
- primary.sub_navigation.render(@current_secondary_navigation) if primary && primary.sub_navigation
30
+ options = extract_backwards_compatible_options(*args)
31
+ options = {:context => :default, :level => :nested}.merge(options)
32
+ SimpleNavigation.load_config(options[:context])
33
+ SimpleNavigation::Configuration.eval_config(self, options[:context])
34
+ SimpleNavigation.handle_explicit_navigation
35
+ case options[:level]
36
+ when Integer
37
+ active_item_container = SimpleNavigation.active_item_container_for(options[:level])
38
+ active_item_container.render if active_item_container
47
39
  when :nested
48
- SimpleNavigation.primary_navigation.render(@current_primary_navigation, true, @current_secondary_navigation)
40
+ SimpleNavigation.primary_navigation.render(true)
49
41
  else
50
- raise ArgumentError, "Invalid navigation level: #{level}"
42
+ raise ArgumentError, "Invalid navigation level: #{options[:level]}"
51
43
  end
52
44
  end
53
45
 
54
- # Renders the primary_navigation with the configured renderer. Calling render_navigation(:level => :primary) has the same effect.
46
+ # Deprecated. Renders the primary_navigation with the configured renderer. Calling render_navigation(:level => 0) has the same effect.
55
47
  def render_primary_navigation(options = {})
56
- render_navigation(options.merge(:level => :primary))
48
+ ActiveSupport::Deprecation.warn("SimpleNavigation::Helpers.render_primary_navigation has been deprected. Please use render_navigation(:level => 1) instead")
49
+ render_navigation(options.merge(:level => 1))
57
50
  end
58
51
 
59
- # Renders the sub_navigation with the configured renderer. Calling render_navigation(:level => :secondary) has the same effect.
52
+ # Deprecated. Renders the sub_navigation with the configured renderer. Calling render_navigation(:level => 1) has the same effect.
60
53
  def render_sub_navigation(options = {})
61
- render_navigation(options.merge(:level => :secondary))
54
+ ActiveSupport::Deprecation.warn("SimpleNavigation::Helpers.render_primary_navigation has been deprected. Please use render_navigation(:level => 2) instead")
55
+ render_navigation(options.merge(:level => 2))
56
+ end
57
+
58
+ private
59
+
60
+ def extract_backwards_compatible_options(*args)
61
+ case args.first
62
+ when Hash
63
+ options = args.first
64
+ options[:level] = 1 if options[:level] == :primary
65
+ options[:level] = 2 if options[:level] == :secondary
66
+ when Symbol
67
+ raise ArgumentError, "Invalid arguments" unless [:primary, :secondary, :nested].include? args.first
68
+ options = Hash.new
69
+ options[:level] = args.first
70
+ options[:level] = 1 if options[:level] == :primary
71
+ options[:level] = 2 if options[:level] == :secondary
72
+ options.merge!(args[1] || {})
73
+ else
74
+ raise ArgumentError, "Invalid arguments"
75
+ end
76
+ options
62
77
  end
63
78
 
64
79
  end
@@ -6,43 +6,84 @@ module SimpleNavigation
6
6
  attr_writer :html_options
7
7
 
8
8
  # see ItemContainer#item
9
- def initialize(key, name, url, options, sub_nav_block)
9
+ def initialize(container, key, name, url, options, sub_nav_block) #:nodoc:
10
+ @container = container
10
11
  @key = key
11
12
  @method = options.delete(:method)
12
13
  @name = name
13
14
  @url = url
14
15
  @html_options = options
15
16
  if sub_nav_block
16
- @sub_navigation = ItemContainer.new
17
+ @sub_navigation = ItemContainer.new(@container.level + 1)
17
18
  sub_nav_block.call @sub_navigation
18
19
  end
19
20
  end
20
21
 
21
- # Returns true if this navigation item should be rendered as 'selected' for the specified current_navigation.
22
- def selected?(current_navigation)
23
- key == current_navigation
22
+ # Returns true if this navigation item should be rendered as 'selected'.
23
+ # An item is selected if
24
+ #
25
+ # * it has been explicitly selected in a controller or
26
+ # * it has a subnavigation and one of its subnavigation items is selected or
27
+ # * its url matches the url of the current request (auto highlighting)
28
+ #
29
+ def selected?
30
+ @selected = @selected || selected_by_config? || selected_by_subnav? || selected_by_url?
24
31
  end
25
32
 
26
33
  # Returns the html-options hash for the item, i.e. the options specified for this item in the config-file.
27
34
  # It also adds the 'selected' class to the list of classes if necessary.
28
- def html_options(current_navigation)
35
+ def html_options
29
36
  default_options = self.autogenerate_item_ids? ? {:id => key.to_s} : {}
30
37
  options = default_options.merge(@html_options)
31
- options[:class] = [@html_options[:class], self.selected_class(current_navigation)].flatten.compact.join(' ')
32
- options.delete(:class) if options[:class].blank?
38
+ options[:class] = [@html_options[:class], self.selected_class].flatten.compact.join(' ')
39
+ options.delete(:class) if options[:class].blank?
33
40
  options
34
41
  end
35
-
36
- def selected_class(current_navigation) #:nodoc:
37
- selected?(current_navigation) ? SimpleNavigation.config.selected_class : nil
42
+
43
+ # Returns the configured selected_class if the item is selected, nil otherwise
44
+ #
45
+ def selected_class
46
+ selected? ? SimpleNavigation.config.selected_class : nil
38
47
  end
39
-
40
-
48
+
41
49
  protected
42
-
50
+
51
+ # Returns true if item has a subnavigation and the sub_navigation is selected
52
+ def selected_by_subnav?
53
+ sub_navigation && sub_navigation.selected?
54
+ end
55
+
56
+ # Return true if item has explicitly selected in controllers
57
+ def selected_by_config?
58
+ key == @container.current_explicit_navigation
59
+ end
60
+
61
+ # Returns true if the item's url matches the request's current url.
62
+ def selected_by_url?
63
+ if auto_highlight?
64
+ !!(root_path_match? || (SimpleNavigation.template && SimpleNavigation.template.current_page?(url)))
65
+ else
66
+ false
67
+ end
68
+ end
69
+
70
+ # Returns true if both the item's url and the request's url are root_path
71
+ def root_path_match?
72
+ url == '/' && SimpleNavigation.controller.request.path == '/'
73
+ end
74
+
75
+ # Converts url to url_hash. Accesses routing system, quite slow... Not used at the moment
76
+ # def hash_for_url(url) #:nodoc:
77
+ # ActionController::Routing::Routes.recognize_path(url, {:method => (method || :get)})
78
+ # end
79
+
43
80
  def autogenerate_item_ids?
44
81
  SimpleNavigation.config.autogenerate_item_ids
45
82
  end
46
-
83
+
84
+ def auto_highlight?
85
+ SimpleNavigation.config.auto_highlight && @container.auto_highlight
86
+ end
87
+
47
88
  end
48
89
  end
@@ -1,14 +1,16 @@
1
1
  module SimpleNavigation
2
2
 
3
- # Holds the Items for a navigation 'level' (either the primary_navigation or a sub_navigation).
3
+ # Holds the Items for a navigation 'level'.
4
4
  class ItemContainer
5
5
 
6
- attr_reader :items
7
- attr_accessor :renderer, :dom_id, :dom_class
6
+ attr_reader :items, :level
7
+ attr_accessor :renderer, :dom_id, :dom_class, :auto_highlight
8
8
 
9
- def initialize #:nodoc:
9
+ def initialize(level=1) #:nodoc:
10
+ @level = level
10
11
  @items = []
11
- @renderer = Configuration.instance.renderer
12
+ @renderer = SimpleNavigation.config.renderer
13
+ @auto_highlight = true
12
14
  end
13
15
 
14
16
  # Creates a new navigation item.
@@ -30,23 +32,72 @@ module SimpleNavigation
30
32
  #
31
33
  # The <tt>block</tt> - if specified - will hold the item's sub_navigation.
32
34
  def item(key, name, url, options={}, &block)
33
- (@items << Item.new(key, name, url, options, block)) if should_add_item?(options)
35
+ (@items << SimpleNavigation::Item.new(self, key, name, url, options, block)) if should_add_item?(options)
34
36
  end
35
37
 
36
38
  # Returns the Item with the specified key, nil otherwise.
39
+ #
37
40
  def [](navi_key)
38
41
  items.find {|i| i.key == navi_key}
39
42
  end
43
+
44
+ # Returns the level of the item specified by navi_key.
45
+ # Recursively works its way down the item's sub_navigations if the desired item is not found directly in this container's items.
46
+ # Returns nil item cannot be found.
47
+ #
48
+ def level_for_item(navi_key)
49
+ my_item = self[navi_key]
50
+ return self.level if my_item
51
+ items.each do |i|
52
+ if i.sub_navigation
53
+ level = i.sub_navigation.level_for_item(navi_key)
54
+ return level unless level.nil?
55
+ end
56
+ end
57
+ return nil
58
+ end
40
59
 
41
60
  # Renders the items in this ItemContainer using the configured renderer.
42
61
  #
43
- # Set <tt>include_sub_navigation</tt> to true if you want to nest the sub_navigation into the active primary_navigation
44
- def render(current_navigation, include_sub_navigation=false, current_sub_navigation=nil)
45
- self.renderer.new(current_navigation, current_sub_navigation).render(self, include_sub_navigation)
62
+ # Set <tt>include_sub_navigation</tt> to true if you want to nest the sub_navigation into the active parent_navigation
63
+ def render(include_sub_navigation=false)
64
+ self.renderer.new.render(self, include_sub_navigation)
65
+ end
66
+
67
+ # Returns true if any of this container's items is selected.
68
+ #
69
+ def selected?
70
+ items.any? {|i| i.selected?}
71
+ end
72
+
73
+ # Returns the currently selected item, nil if no item is selected.
74
+ #
75
+ def selected_item
76
+ self[current_explicit_navigation] || items.find {|i| i.selected?}
77
+ end
78
+
79
+ # Returns the current navigation that has been explicitely defined in the controller for this container's level.
80
+ # Returns nil if no explicit current navigation has been set.
81
+ #
82
+ def current_explicit_navigation
83
+ SimpleNavigation.current_navigation_for(level)
84
+ end
85
+
86
+ # Returns the active item_container for the specified level
87
+ # (recursively looks up items in selected sub_navigation if level is deeper than this container's level).
88
+ #
89
+ def active_item_container_for(desired_level)
90
+ return self if self.level == desired_level
91
+ return nil unless selected_sub_navigation?
92
+ return selected_item.sub_navigation.active_item_container_for(desired_level)
46
93
  end
47
94
 
48
95
  private
49
96
 
97
+ def selected_sub_navigation?
98
+ !!(selected_item && selected_item.sub_navigation)
99
+ end
100
+
50
101
  # partially borrowed from ActionSupport::Callbacks
51
102
  def should_add_item?(options) #:nodoc:
52
103
  [options.delete(:if)].flatten.compact.all? { |m| evaluate_method(m) } &&
@@ -62,7 +113,6 @@ module SimpleNavigation
62
113
  raise ArgumentError, ":if or :unless must be procs or lambdas"
63
114
  end
64
115
  end
65
-
66
116
 
67
117
  end
68
118
 
@@ -3,14 +3,12 @@ module SimpleNavigation
3
3
 
4
4
  # This is the base class for all renderers.
5
5
  #
6
- # A renderer is responsible for rendering an ItemContainer (primary or a sub_navigation) and its containing items to HTML.
7
- # It must be initialized with the current_navigation for the rendered ItemContainer and
8
- # optionally with the current_sub_navigation (if the sub_navigation will be nested).
6
+ # A renderer is responsible for rendering an ItemContainer and its containing items to HTML.
9
7
  class Base
10
8
  include ActionView::Helpers::UrlHelper
11
9
  include ActionView::Helpers::TagHelper
12
10
 
13
- attr_reader :current_navigation, :current_sub_navigation, :controller
11
+ attr_reader :controller
14
12
 
15
13
  class << self
16
14
 
@@ -25,16 +23,18 @@ module SimpleNavigation
25
23
 
26
24
  controller_method :form_authenticity_token, :protect_against_forgery?, :request_forgery_protection_token
27
25
 
28
- def initialize(current_navigation, current_sub_navigation=nil) #:nodoc:
29
- @current_navigation = current_navigation
30
- @current_sub_navigation = current_sub_navigation
26
+ def initialize #:nodoc:
31
27
  @controller = SimpleNavigation.controller
32
28
  end
33
29
 
34
30
  # Renders the specified ItemContainer to HTML.
35
31
  #
36
32
  # If <tt>include_sub_navigation</tt> is set to true, the renderer should nest the sub_navigation for the active navigation
37
- # inside that navigation item.
33
+ # inside that navigation item.
34
+ #
35
+ # A renderer should also take the option SimpleNavigation.config.render_all_levels into account. If it is set to true then it should render all navigation levels
36
+ # independent of the <tt>include_sub_navigation</tt> option.
37
+ #
38
38
  def render(item_container, include_sub_navigation=false)
39
39
  raise 'subclass responsibility'
40
40
  end