simple-navigation 3.12.0 → 3.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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