simple-navigation 3.12.0 → 3.12.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (30) hide show
  1. data/CHANGELOG +4 -0
  2. data/generators/navigation_config/navigation_config_generator.rb +3 -3
  3. data/generators/navigation_config/templates/config/navigation.rb +9 -10
  4. data/init.rb +1 -1
  5. data/lib/generators/navigation_config/navigation_config_generator.rb +11 -6
  6. data/lib/simple-navigation.rb +1 -1
  7. data/lib/simple_navigation.rb +93 -65
  8. data/lib/simple_navigation/adapters/base.rb +16 -16
  9. data/lib/simple_navigation/adapters/nanoc.rb +7 -6
  10. data/lib/simple_navigation/adapters/padrino.rb +5 -7
  11. data/lib/simple_navigation/adapters/rails.rb +52 -39
  12. data/lib/simple_navigation/adapters/sinatra.rb +14 -17
  13. data/lib/simple_navigation/core/configuration.rb +73 -34
  14. data/lib/simple_navigation/core/item.rb +110 -54
  15. data/lib/simple_navigation/core/item_adapter.rb +18 -13
  16. data/lib/simple_navigation/core/item_container.rb +93 -66
  17. data/lib/simple_navigation/core/items_provider.rb +12 -10
  18. data/lib/simple_navigation/rails_controller_methods.rb +98 -78
  19. data/lib/simple_navigation/rendering/helpers.rb +130 -68
  20. data/lib/simple_navigation/rendering/renderer/base.rb +30 -25
  21. data/lib/simple_navigation/rendering/renderer/breadcrumbs.rb +26 -19
  22. data/lib/simple_navigation/rendering/renderer/json.rb +11 -13
  23. data/lib/simple_navigation/rendering/renderer/links.rb +18 -13
  24. data/lib/simple_navigation/rendering/renderer/list.rb +28 -15
  25. data/lib/simple_navigation/rendering/renderer/text.rb +7 -12
  26. data/lib/simple_navigation/version.rb +1 -1
  27. data/spec/lib/simple_navigation/core/item_adapter_spec.rb +1 -1
  28. data/spec/lib/simple_navigation/core/item_container_spec.rb +118 -68
  29. data/spec/lib/simple_navigation_spec.rb +16 -5
  30. metadata +2 -2
@@ -1,81 +1,150 @@
1
1
  module SimpleNavigation
2
-
3
2
  # View helpers to render the navigation.
4
3
  #
5
4
  # Use render_navigation as following to render your navigation:
6
- # * call <tt>render_navigation</tt> without :level option to render your complete 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
- # * call <tt>render_navigation(:level => 2..3)</tt> to render navigation levels 2 and 3).
9
- # For example, you could use render_navigation(:level => 1) to render your primary navigation as tabs and render_navigation(:level => 2..3) to render the rest of the navigation as a tree in a sidebar.
5
+ # * call <tt>render_navigation</tt> without :level option to render your
6
+ # complete navigation as nested tree.
7
+ # * call <tt>render_navigation(level: x)</tt> to render a specific
8
+ # navigation level (e.g. level: 1 to render your primary navigation,
9
+ # level: 2 to render the sub navigation and so forth)
10
+ # * call <tt>render_navigation(:level => 2..3)</tt> to render navigation
11
+ # levels 2 and 3).
12
+ #
13
+ # For example, you could use render_navigation(level: 1) to render your
14
+ # primary navigation as tabs and render_navigation(level: 2..3) to render
15
+ # the rest of the navigation as a tree in a sidebar.
10
16
  #
11
17
  # ==== Examples (using Haml)
12
- # #primary_navigation= render_navigation(:level => 1)
18
+ # #primary_navigation= render_navigation(level: 1)
13
19
  #
14
- # #sub_navigation= render_navigation(:level => 2)
20
+ # #sub_navigation= render_navigation(level: 2)
15
21
  #
16
22
  # #nested_navigation= render_navigation
17
23
  #
18
- # #top_navigation= render_navigation(:level => 1..2)
19
- # #sidebar_navigation= render_navigation(:level => 3)
24
+ # #top_navigation= render_navigation(level: 1..2)
25
+ # #sidebar_navigation= render_navigation(level: 3)
20
26
  module Helpers
27
+ def self.load_config(options, includer, &block)
28
+ context = options.delete(:context)
29
+ SimpleNavigation.init_adapter_from includer
30
+ SimpleNavigation.load_config context
31
+ SimpleNavigation::Configuration.eval_config context
32
+
33
+ if block_given? || options[:items]
34
+ SimpleNavigation.config.items(options[:items], &block)
35
+ end
36
+
37
+ if SimpleNavigation.respond_to?(:handle_explicit_navigation)
38
+ SimpleNavigation.handle_explicit_navigation
39
+ end
40
+
41
+ unless SimpleNavigation.primary_navigation
42
+ fail 'no primary navigation defined, either use a navigation config ' \
43
+ 'file or pass items directly to render_navigation'
44
+ end
45
+ end
46
+
47
+ def self.apply_defaults(options)
48
+ options[:level] = options.delete(:levels) if options[:levels]
49
+ { context: :default, level: :all }.merge(options)
50
+ end
21
51
 
22
52
  # Renders the navigation according to the specified options-hash.
23
53
  #
24
54
  # The following options are supported:
25
- # * <tt>:level</tt> - defaults to :all which renders the the sub_navigation for an active primary_navigation inside that active primary_navigation item.
26
- # Specify a specific level to only render that level of navigation (e.g. :level => 1 for primary_navigation etc...).
27
- # Specifiy a Range of levels to render only those specific levels (e.g. :level => 1..2 to render both your first and second levels, maybe you want to render your third level somewhere else on the page)
28
- # * <tt>:expand_all</tt> - defaults to false. If set to true the all specified levels will be rendered as a fully expanded tree (always open). This is useful for javascript menus like Superfish.
29
- # * <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).
30
- # 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
31
- # will be loaded and used for rendering the navigation.
32
- # * <tt>:items</tt> - you can specify the items directly (e.g. if items are dynamically generated from database). See SimpleNavigation::ItemsProvider for documentation on what to provide as items.
33
- # * <tt>:renderer</tt> - specify the renderer to be used for rendering the navigation. Either provide the Class or a symbol matching a registered renderer. Defaults to :list (html list renderer).
55
+ # * <tt>:level</tt> - defaults to :all which renders the the sub_navigation
56
+ # for an active primary_navigation inside that active
57
+ # primary_navigation item.
58
+ # Specify a specific level to only render that level of navigation
59
+ # (e.g. level: 1 for primary_navigation, etc).
60
+ # Specifiy a Range of levels to render only those specific levels
61
+ # (e.g. level: 1..2 to render both your first and second levels, maybe
62
+ # you want to render your third level somewhere else on the page)
63
+ # * <tt>:expand_all</tt> - defaults to false. If set to true the all
64
+ # specified levels will be rendered as a fully expanded
65
+ # tree (always open). This is useful for javascript menus like Superfish.
66
+ # * <tt>:context</tt> - specifies the context for which you would render
67
+ # the navigation. Defaults to :default which loads the default
68
+ # navigation.rb (i.e. config/navigation.rb).
69
+ # If you specify a context then the plugin tries to load the configuration
70
+ # file for that context, e.g. if you call
71
+ # <tt>render_navigation(context: :admin)</tt> the file
72
+ # config/admin_navigation.rb will be loaded and used for rendering
73
+ # the navigation.
74
+ # * <tt>:items</tt> - you can specify the items directly (e.g. if items are
75
+ # dynamically generated from database).
76
+ # See SimpleNavigation::ItemsProvider for documentation on what to
77
+ # provide as items.
78
+ # * <tt>:renderer</tt> - specify the renderer to be used for rendering the
79
+ # navigation. Either provide the Class or a symbol matching a registered
80
+ # renderer. Defaults to :list (html list renderer).
34
81
  #
35
- # Instead of using the <tt>:items</tt> option, a block can be passed to specify the items dynamically
82
+ # Instead of using the <tt>:items</tt> option, a block can be passed to
83
+ # specify the items dynamically
36
84
  #
85
+ # ==== Examples
37
86
  # render_navigation do |menu|
38
87
  # menu.item :posts, "Posts", posts_path
39
88
  # end
40
89
  #
41
- def render_navigation(options={},&block)
42
- container = active_navigation_item_container(options,&block)
90
+ def render_navigation(options = {}, &block)
91
+ container = active_navigation_item_container(options, &block)
43
92
  container && container.render(options)
44
93
  end
45
94
 
46
- # Returns the name of the currently active navigation item belonging to the specified level.
95
+ # Returns the name of the currently active navigation item belonging to the
96
+ # specified level.
47
97
  #
48
98
  # See Helpers#active_navigation_item for supported options.
49
99
  #
50
- # Returns an empty string if no active item can be found for the specified options
51
- def active_navigation_item_name(options={})
52
- active_navigation_item(options,'') { |item| item.name(:apply_generator => false) }
100
+ # Returns an empty string if no active item can be found for the specified
101
+ # options
102
+ def active_navigation_item_name(options = {})
103
+ active_navigation_item(options, '') do |item|
104
+ item.name(apply_generator: false)
105
+ end
53
106
  end
54
107
 
55
- # Returns the key of the currently active navigation item belonging to the specified level.
108
+ # Returns the key of the currently active navigation item belonging to the
109
+ # specified level.
56
110
  #
57
111
  # See Helpers#active_navigation_item for supported options.
58
112
  #
59
- # Returns <tt>nil</tt> if no active item can be found for the specified options
60
- def active_navigation_item_key(options={})
61
- active_navigation_item(options) { |item| item.key }
113
+ # Returns <tt>nil</tt> if no active item can be found for the specified
114
+ # options
115
+ def active_navigation_item_key(options = {})
116
+ active_navigation_item(options, &:key)
62
117
  end
63
118
 
64
- # Returns the currently active navigation item belonging to the specified level.
119
+ # Returns the currently active navigation item belonging to the specified
120
+ # level.
65
121
  #
66
122
  # The following options are supported:
67
- # * <tt>:level</tt> - defaults to :all which returns the most specific/deepest selected item (the leaf).
68
- # Specify a specific level to only look for the selected item in the specified level of navigation (e.g. :level => 1 for primary_navigation etc...).
69
- # * <tt>:context</tt> - specifies the context for which you would like to find the active navigation item. Defaults to :default which loads the default navigation.rb (i.e. config/navigation.rb).
70
- # If you specify a context then the plugin tries to load the configuration file for that context, e.g. if you call <tt>active_navigation_item_name(:context => :admin)</tt> the file config/admin_navigation.rb
71
- # will be loaded and used for searching the active item.
72
- # * <tt>:items</tt> - you can specify the items directly (e.g. if items are dynamically generated from database). See SimpleNavigation::ItemsProvider for documentation on what to provide as items.
123
+ # * <tt>:level</tt> - defaults to :all which returns the
124
+ # most specific/deepest selected item (the leaf).
125
+ # Specify a specific level to only look for the selected item in the
126
+ # specified level of navigation
127
+ # (e.g. level: 1 for primary_navigation, etc).
128
+ # * <tt>:context</tt> - specifies the context for which you would like to
129
+ # find the active navigation item. Defaults to :default which loads the
130
+ # default navigation.rb (i.e. config/navigation.rb).
131
+ # If you specify a context then the plugin tries to load the configuration
132
+ # file for that context, e.g. if you call
133
+ # <tt>active_navigation_item_name(context: :admin)</tt> the file
134
+ # config/admin_navigation.rb will be loaded and used for searching the
135
+ # active item.
136
+ # * <tt>:items</tt> - you can specify the items directly (e.g. if items are
137
+ # dynamically generated from database).
138
+ # See SimpleNavigation::ItemsProvider for documentation on what to provide
139
+ # as items.
73
140
  #
74
141
  # Returns the supplied <tt>value_for_nil</tt> object (<tt>nil</tt>
75
142
  # by default) if no active item can be found for the specified
76
143
  # options
77
- def active_navigation_item(options={},value_for_nil = nil)
78
- options[:level] = :leaves if options[:level].nil? || options[:level] == :all
144
+ def active_navigation_item(options = {}, value_for_nil = nil)
145
+ if options[:level].nil? || options[:level] == :all
146
+ options[:level] = :leaves
147
+ end
79
148
  container = active_navigation_item_container(options)
80
149
  if container && (item = container.selected_item)
81
150
  block_given? ? yield(item) : item
@@ -84,40 +153,33 @@ module SimpleNavigation
84
153
  end
85
154
  end
86
155
 
87
- # Returns the currently active item container belonging to the specified level.
156
+ # Returns the currently active item container belonging to the specified
157
+ # level.
88
158
  #
89
159
  # The following options are supported:
90
- # * <tt>:level</tt> - defaults to :all which returns the least specific/shallowest selected item.
91
- # Specify a specific level to only look for the selected item in the specified level of navigation (e.g. :level => 1 for primary_navigation etc...).
92
- # * <tt>:context</tt> - specifies the context for which you would like to find the active navigation item. Defaults to :default which loads the default navigation.rb (i.e. config/navigation.rb).
93
- # If you specify a context then the plugin tries to load the configuration file for that context, e.g. if you call <tt>active_navigation_item_name(:context => :admin)</tt> the file config/admin_navigation.rb
94
- # will be loaded and used for searching the active item.
95
- # * <tt>:items</tt> - you can specify the items directly (e.g. if items are dynamically generated from database). See SimpleNavigation::ItemsProvider for documentation on what to provide as items.
160
+ # * <tt>:level</tt> - defaults to :all which returns the
161
+ # least specific/shallowest selected item.
162
+ # Specify a specific level to only look for the selected item in the
163
+ # specified level of navigation
164
+ # (e.g. level: 1 for primary_navigation, etc).
165
+ # * <tt>:context</tt> - specifies the context for which you would like to
166
+ # find the active navigation item. Defaults to :default which loads the
167
+ # default navigation.rb (i.e. config/navigation.rb).
168
+ # If you specify a context then the plugin tries to load the configuration
169
+ # file for that context, e.g. if you call
170
+ # <tt>active_navigation_item_name(context: :admin)</tt> the file
171
+ # config/admin_navigation.rb will be loaded and used for searching the
172
+ # active item.
173
+ # * <tt>:items</tt> - you can specify the items directly (e.g. if items are
174
+ # dynamically generated from database).
175
+ # See SimpleNavigation::ItemsProvider for documentation on what to provide
176
+ # as items.
96
177
  #
97
178
  # Returns <tt>nil</tt> if no active item container can be found
98
- def active_navigation_item_container(options={},&block)
99
- options = SimpleNavigation::Helpers::apply_defaults(options)
100
- SimpleNavigation::Helpers::load_config(options,self,&block)
101
- container = SimpleNavigation.active_item_container_for(options[:level])
102
- end
103
-
104
- class << self
105
- def load_config(options,includer,&block)
106
- ctx = options.delete(:context)
107
- SimpleNavigation.init_adapter_from includer
108
- SimpleNavigation.load_config(ctx)
109
- SimpleNavigation::Configuration.eval_config(ctx)
110
- if block_given? || options[:items]
111
- SimpleNavigation.config.items(options[:items],&block)
112
- end
113
- SimpleNavigation.handle_explicit_navigation if SimpleNavigation.respond_to?(:handle_explicit_navigation)
114
- raise "no primary navigation defined, either use a navigation config file or pass items directly to render_navigation" unless SimpleNavigation.primary_navigation
115
- end
116
-
117
- def apply_defaults(options)
118
- options[:level] = options.delete(:levels) if options[:levels]
119
- {:context => :default, :level => :all}.merge(options)
120
- end
179
+ def active_navigation_item_container(options = {}, &block)
180
+ options = SimpleNavigation::Helpers.apply_defaults(options)
181
+ SimpleNavigation::Helpers.load_config(options, self, &block)
182
+ SimpleNavigation.active_item_container_for(options[:level])
121
183
  end
122
184
  end
123
185
  end
@@ -2,17 +2,17 @@ require 'forwardable'
2
2
 
3
3
  module SimpleNavigation
4
4
  module Renderer
5
-
6
5
  # This is the base class for all renderers.
7
6
  #
8
- # A renderer is responsible for rendering an ItemContainer and its containing items to HTML.
7
+ # A renderer is responsible for rendering an ItemContainer and its
8
+ # containing items to HTML.
9
9
  class Base
10
10
  extend Forwardable
11
-
12
- attr_reader :options, :adapter
13
-
11
+
12
+ attr_reader :adapter, :options
13
+
14
14
  def_delegators :adapter, :link_to, :content_tag
15
-
15
+
16
16
  def initialize(options) #:nodoc:
17
17
  @options = options
18
18
  @adapter = SimpleNavigation.adapter
@@ -35,31 +35,28 @@ module SimpleNavigation
35
35
  end
36
36
 
37
37
  def render_sub_navigation_for(item)
38
- item.sub_navigation.render(self.options)
38
+ item.sub_navigation.render(options)
39
39
  end
40
-
40
+
41
41
  # Renders the specified ItemContainer to HTML.
42
42
  #
43
- # When implementing a renderer, please consider to call include_sub_navigation? to determin
44
- # whether an item's sub_navigation should be rendered or not.
45
- #
43
+ # When implementing a renderer, please consider to call
44
+ # include_sub_navigation? to determine whether an item's sub_navigation
45
+ # should be rendered or not.
46
46
  def render(item_container)
47
- raise 'subclass responsibility'
47
+ fail NotImplementedError, 'subclass responsibility'
48
48
  end
49
49
 
50
50
  protected
51
51
 
52
52
  def consider_sub_navigation?(item)
53
- return false if item.sub_navigation.nil?
53
+ return false unless item.sub_navigation
54
+
54
55
  case level
55
- when :all
56
- return true
57
- when Integer
58
- return false
59
- when Range
60
- return item.sub_navigation.level <= level.max
56
+ when :all then true
57
+ when Range then item.sub_navigation.level <= level.max
58
+ else false
61
59
  end
62
- false
63
60
  end
64
61
 
65
62
  def expand_sub_navigation?(item)
@@ -92,16 +89,24 @@ module SimpleNavigation
92
89
  end
93
90
 
94
91
  # Extracts the options relevant for the generated link
95
- #
96
92
  def link_options_for(item)
97
- special_options = {:method => item.method, :class => item.selected_class}.reject {|k, v| v.nil? }
93
+ special_options = {
94
+ method: item.method,
95
+ class: item.selected_class
96
+ }.reject { |_, v| v.nil? }
97
+
98
98
  link_options = item.html_options[:link]
99
+
99
100
  return special_options unless link_options
101
+
100
102
  opts = special_options.merge(link_options)
101
- opts[:class] = [link_options[:class], item.selected_class].flatten.compact.join(' ')
102
- opts.delete(:class) if opts[:class].nil? || opts[:class] == ''
103
+
104
+ classes = [link_options[:class], item.selected_class]
105
+ classes = classes.flatten.compact.join(' ')
106
+ opts[:class] = classes unless classes.empty?
107
+
103
108
  opts
104
- end
109
+ end
105
110
  end
106
111
  end
107
112
  end
@@ -1,38 +1,40 @@
1
1
  module SimpleNavigation
2
2
  module Renderer
3
-
4
- # Renders an ItemContainer as a <div> element and its containing items as <a> elements.
3
+ # Renders an ItemContainer as a <div> element and its containing items as
4
+ # <a> elements.
5
5
  # It only renders 'selected' elements.
6
6
  #
7
- # By default, the renderer sets the item's key as dom_id for the rendered <a> element unless the config option <tt>autogenerate_item_ids</tt> is set to false.
8
- # The id can also be explicitely specified by setting the id in the html-options of the 'item' method in the config/navigation.rb file.
9
- # The ItemContainer's dom_attributes are applied to the surrounding <div> element.
7
+ # By default, the renderer sets the item's key as dom_id for the rendered
8
+ # <a> element unless the config option <tt>autogenerate_item_ids</tt> is
9
+ # set to false.
10
10
  #
11
+ # The id can also be explicitely specified by setting the id in the
12
+ # html-options of the 'item' method in the config/navigation.rb file.
13
+ # The ItemContainer's dom_attributes are applied to the surrounding <div>
14
+ # element.
11
15
  class Breadcrumbs < SimpleNavigation::Renderer::Base
12
-
13
16
  def render(item_container)
14
17
  content = a_tags(item_container).join(join_with)
15
18
  content_tag(:div,
16
- prefix_for(content) + content,
17
- item_container.dom_attributes)
19
+ prefix_for(content) + content,
20
+ item_container.dom_attributes)
18
21
  end
19
22
 
20
23
  protected
21
24
 
22
25
  def a_tags(item_container)
23
- item_container.items.inject([]) do |list, item|
24
- if item.selected?
25
- list << tag_for(item)
26
- if include_sub_navigation?(item)
27
- list.concat a_tags(item.sub_navigation)
28
- end
26
+ item_container.items.each_with_object([]) do |item, list|
27
+ next unless item.selected?
28
+ list << tag_for(item)
29
+
30
+ if include_sub_navigation?(item)
31
+ list.concat a_tags(item.sub_navigation)
29
32
  end
30
- list
31
33
  end
32
34
  end
33
35
 
34
36
  def join_with
35
- @join_with ||= options[:join_with] || " "
37
+ @join_with ||= options[:join_with] || ' '
36
38
  end
37
39
 
38
40
  def suppress_link?(item)
@@ -40,7 +42,11 @@ module SimpleNavigation
40
42
  end
41
43
 
42
44
  def prefix_for(content)
43
- content.empty? ? '' : options[:prefix] || ''
45
+ if !content.empty? && options[:prefix]
46
+ options[:prefix]
47
+ else
48
+ ''
49
+ end
44
50
  end
45
51
 
46
52
  # Extracts the options relevant for the generated link
@@ -48,10 +54,11 @@ module SimpleNavigation
48
54
  def link_options_for(item)
49
55
  if options[:allow_classes_and_ids]
50
56
  opts = super
51
- opts[:id] = "breadcrumb_#{opts[:id]}" if opts[:id]
57
+ opts[:id] &&= "breadcrumb_#{opts[:id]}"
52
58
  opts
53
59
  else
54
- {:method => item.method}.merge(item.html_options.except(:class,:id))
60
+ html_options = item.html_options.except(:class, :id)
61
+ { method: item.method }.merge(html_options)
55
62
  end
56
63
  end
57
64
  end
@@ -1,29 +1,27 @@
1
1
  module SimpleNavigation
2
2
  module Renderer
3
-
4
- # Renders the navigation items as a object tree serialized as a json string, can also output raw ruby Hashes
3
+ # Renders the navigation items as a object tree serialized as a json string,
4
+ # can also output raw ruby Hashes
5
5
  class Json < SimpleNavigation::Renderer::Base
6
-
7
6
  def render(item_container)
8
7
  results = hash_render(item_container)
9
- results = results.to_json unless options[:as_hash]
10
- results
8
+ options[:as_hash] ? results : results.to_json
11
9
  end
12
10
 
13
11
  private
14
12
 
15
13
  def hash_render(item_container)
16
- return nil if item_container.nil?
14
+ return nil unless item_container
15
+
17
16
  item_container.items.map do |item|
18
- item_hash = {
19
- :name => item.name,
20
- :url => item.url,
21
- :selected => item.selected?,
22
- :items => hash_render(item.sub_navigation)
17
+ {
18
+ items: hash_render(item.sub_navigation),
19
+ name: item.name,
20
+ selected: item.selected?,
21
+ url: item.url
23
22
  }
24
- end
23
+ end
25
24
  end
26
-
27
25
  end
28
26
  end
29
27
  end