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.
- data/CHANGELOG +4 -0
- data/generators/navigation_config/navigation_config_generator.rb +3 -3
- data/generators/navigation_config/templates/config/navigation.rb +9 -10
- data/init.rb +1 -1
- data/lib/generators/navigation_config/navigation_config_generator.rb +11 -6
- data/lib/simple-navigation.rb +1 -1
- data/lib/simple_navigation.rb +93 -65
- data/lib/simple_navigation/adapters/base.rb +16 -16
- data/lib/simple_navigation/adapters/nanoc.rb +7 -6
- data/lib/simple_navigation/adapters/padrino.rb +5 -7
- data/lib/simple_navigation/adapters/rails.rb +52 -39
- data/lib/simple_navigation/adapters/sinatra.rb +14 -17
- data/lib/simple_navigation/core/configuration.rb +73 -34
- data/lib/simple_navigation/core/item.rb +110 -54
- data/lib/simple_navigation/core/item_adapter.rb +18 -13
- data/lib/simple_navigation/core/item_container.rb +93 -66
- data/lib/simple_navigation/core/items_provider.rb +12 -10
- data/lib/simple_navigation/rails_controller_methods.rb +98 -78
- data/lib/simple_navigation/rendering/helpers.rb +130 -68
- data/lib/simple_navigation/rendering/renderer/base.rb +30 -25
- data/lib/simple_navigation/rendering/renderer/breadcrumbs.rb +26 -19
- data/lib/simple_navigation/rendering/renderer/json.rb +11 -13
- data/lib/simple_navigation/rendering/renderer/links.rb +18 -13
- data/lib/simple_navigation/rendering/renderer/list.rb +28 -15
- data/lib/simple_navigation/rendering/renderer/text.rb +7 -12
- data/lib/simple_navigation/version.rb +1 -1
- data/spec/lib/simple_navigation/core/item_adapter_spec.rb +1 -1
- data/spec/lib/simple_navigation/core/item_container_spec.rb +118 -68
- data/spec/lib/simple_navigation_spec.rb +16 -5
- 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
|
7
|
-
#
|
8
|
-
# * call <tt>render_navigation(:
|
9
|
-
#
|
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(:
|
18
|
+
# #primary_navigation= render_navigation(level: 1)
|
13
19
|
#
|
14
|
-
# #sub_navigation= render_navigation(:
|
20
|
+
# #sub_navigation= render_navigation(level: 2)
|
15
21
|
#
|
16
22
|
# #nested_navigation= render_navigation
|
17
23
|
#
|
18
|
-
# #top_navigation= render_navigation(:
|
19
|
-
# #sidebar_navigation= render_navigation(:
|
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
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
# * <tt>:
|
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
|
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={}
|
42
|
-
container = active_navigation_item_container(options
|
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
|
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
|
51
|
-
|
52
|
-
|
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
|
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
|
60
|
-
|
61
|
-
|
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
|
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
|
68
|
-
#
|
69
|
-
#
|
70
|
-
#
|
71
|
-
#
|
72
|
-
# * <tt>:
|
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
|
-
|
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
|
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
|
91
|
-
#
|
92
|
-
#
|
93
|
-
#
|
94
|
-
#
|
95
|
-
# * <tt>:
|
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={}
|
99
|
-
options = SimpleNavigation::Helpers
|
100
|
-
SimpleNavigation::Helpers
|
101
|
-
|
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
|
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 :
|
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(
|
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
|
44
|
-
# whether an item's sub_navigation
|
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
|
-
|
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
|
53
|
+
return false unless item.sub_navigation
|
54
|
+
|
54
55
|
case level
|
55
|
-
when :all
|
56
|
-
|
57
|
-
|
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 = {
|
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
|
-
|
102
|
-
|
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
|
-
#
|
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
|
8
|
-
#
|
9
|
-
#
|
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
|
-
|
17
|
-
|
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.
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
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?
|
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]
|
57
|
+
opts[:id] &&= "breadcrumb_#{opts[:id]}"
|
52
58
|
opts
|
53
59
|
else
|
54
|
-
|
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
|
-
#
|
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
|
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
|
14
|
+
return nil unless item_container
|
15
|
+
|
17
16
|
item_container.items.map do |item|
|
18
|
-
|
19
|
-
:
|
20
|
-
:
|
21
|
-
:
|
22
|
-
:
|
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
|