simple-navigation 3.13.0 → 4.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +10 -3
  5. data/CHANGELOG.md +420 -0
  6. data/Guardfile +4 -2
  7. data/LICENSE +1 -1
  8. data/README.md +30 -7
  9. data/Rakefile +25 -2
  10. data/gemfiles/.bundle/config +2 -0
  11. data/gemfiles/rails-3-2-stable.gemfile +11 -0
  12. data/gemfiles/rails-4-1-stable.gemfile +7 -0
  13. data/gemfiles/rails-4-2-stable.gemfile +7 -0
  14. data/generators/navigation_config/navigation_config_generator.rb +0 -1
  15. data/generators/navigation_config/templates/config/navigation.rb +18 -15
  16. data/lib/simple_navigation.rb +25 -42
  17. data/lib/simple_navigation/adapters/padrino.rb +2 -2
  18. data/lib/simple_navigation/adapters/rails.rb +1 -24
  19. data/lib/simple_navigation/adapters/sinatra.rb +2 -11
  20. data/lib/simple_navigation/config_file.rb +36 -0
  21. data/lib/simple_navigation/config_file_finder.rb +42 -0
  22. data/lib/simple_navigation/{core/configuration.rb → configuration.rb} +7 -1
  23. data/lib/simple_navigation/{rendering/helpers.rb → helpers.rb} +0 -4
  24. data/lib/simple_navigation/{core/item.rb → item.rb} +76 -83
  25. data/lib/simple_navigation/{core/item_adapter.rb → item_adapter.rb} +3 -17
  26. data/lib/simple_navigation/{core/item_container.rb → item_container.rb} +23 -14
  27. data/lib/simple_navigation/{core/items_provider.rb → items_provider.rb} +0 -0
  28. data/lib/simple_navigation/railtie.rb +7 -0
  29. data/lib/simple_navigation/renderer.rb +12 -0
  30. data/lib/simple_navigation/{rendering/renderer → renderer}/base.rb +1 -1
  31. data/lib/simple_navigation/{rendering/renderer → renderer}/breadcrumbs.rb +0 -0
  32. data/lib/simple_navigation/{rendering/renderer → renderer}/json.rb +2 -0
  33. data/lib/simple_navigation/{rendering/renderer → renderer}/links.rb +0 -0
  34. data/lib/simple_navigation/{rendering/renderer → renderer}/list.rb +0 -0
  35. data/lib/simple_navigation/{rendering/renderer → renderer}/text.rb +0 -0
  36. data/lib/simple_navigation/version.rb +1 -1
  37. data/simple-navigation.gemspec +6 -5
  38. data/spec/fake_app/config/navigation.rb +6 -0
  39. data/spec/fake_app/rails_app.rb +35 -0
  40. data/spec/initializers/coveralls.rb +3 -0
  41. data/spec/initializers/have_css_matcher.rb +8 -3
  42. data/spec/initializers/memfs.rb +7 -0
  43. data/spec/initializers/rails.rb +4 -0
  44. data/spec/initializers/rspec.rb +7 -0
  45. data/spec/integration/rendering_navigation_spec.rb +14 -0
  46. data/spec/{lib/simple_navigation → simple_navigation}/adapters/padrino_spec.rb +0 -2
  47. data/spec/{lib/simple_navigation → simple_navigation}/adapters/rails_spec.rb +43 -94
  48. data/spec/{lib/simple_navigation → simple_navigation}/adapters/sinatra_spec.rb +4 -6
  49. data/spec/simple_navigation/config_file_finder_spec.rb +50 -0
  50. data/spec/simple_navigation/config_file_spec.rb +25 -0
  51. data/spec/{lib/simple_navigation/core → simple_navigation}/configuration_spec.rb +29 -19
  52. data/spec/{lib/simple_navigation/rendering → simple_navigation}/helpers_spec.rb +10 -13
  53. data/spec/{lib/simple_navigation/core → simple_navigation}/item_adapter_spec.rb +14 -11
  54. data/spec/{lib/simple_navigation/core → simple_navigation}/item_container_spec.rb +130 -42
  55. data/spec/simple_navigation/item_spec.rb +475 -0
  56. data/spec/{lib/simple_navigation/core → simple_navigation}/items_provider_spec.rb +1 -3
  57. data/spec/{lib/simple_navigation/rendering → simple_navigation}/renderer/base_spec.rb +34 -36
  58. data/spec/{lib/simple_navigation/rendering → simple_navigation}/renderer/breadcrumbs_spec.rb +4 -7
  59. data/spec/{lib/simple_navigation/rendering → simple_navigation}/renderer/json_spec.rb +5 -11
  60. data/spec/{lib/simple_navigation/rendering → simple_navigation}/renderer/links_spec.rb +5 -8
  61. data/spec/{lib/simple_navigation/rendering → simple_navigation}/renderer/list_spec.rb +4 -7
  62. data/spec/{lib/simple_navigation/rendering → simple_navigation}/renderer/text_spec.rb +4 -7
  63. data/spec/simple_navigation_spec.rb +190 -0
  64. data/spec/spec_helper.rb +29 -35
  65. metadata +128 -113
  66. data/CHANGELOG +0 -288
  67. data/lib/simple_navigation/core.rb +0 -5
  68. data/lib/simple_navigation/rails_controller_methods.rb +0 -164
  69. data/lib/simple_navigation/rendering.rb +0 -12
  70. data/rails/init.rb +0 -1
  71. data/spec/lib/simple_navigation/core/item_spec.rb +0 -703
  72. data/spec/lib/simple_navigation/rails_controller_methods_spec.rb +0 -270
  73. data/spec/lib/simple_navigation_spec.rb +0 -300
@@ -7,7 +7,10 @@ module SimpleNavigation
7
7
 
8
8
  attr_accessor :autogenerate_item_ids,
9
9
  :auto_highlight,
10
- :consider_item_names_as_safe
10
+ :consider_item_names_as_safe,
11
+ :highlight_on_subpath,
12
+ :ignore_query_params_on_auto_highlight,
13
+ :ignore_anchors_on_auto_highlight
11
14
 
12
15
  attr_reader :primary_navigation
13
16
 
@@ -33,6 +36,9 @@ module SimpleNavigation
33
36
  @autogenerate_item_ids = true
34
37
  @auto_highlight = true
35
38
  @consider_item_names_as_safe = false
39
+ @highlight_on_subpath = false
40
+ @ignore_anchors_on_auto_highlight = true
41
+ @ignore_query_params_on_auto_highlight = true
36
42
  end
37
43
 
38
44
  def active_leaf_class
@@ -34,10 +34,6 @@ module SimpleNavigation
34
34
  SimpleNavigation.config.items(options[:items], &block)
35
35
  end
36
36
 
37
- if SimpleNavigation.respond_to?(:handle_explicit_navigation)
38
- SimpleNavigation.handle_explicit_navigation
39
- end
40
-
41
37
  unless SimpleNavigation.primary_navigation
42
38
  fail 'no primary navigation defined, either use a navigation config ' \
43
39
  'file or pass items directly to render_navigation'
@@ -2,27 +2,23 @@ module SimpleNavigation
2
2
  # Represents an item in your navigation.
3
3
  # Gets generated by the item method in the config-file.
4
4
  class Item
5
- attr_reader :highlights_on,
6
- :key,
7
- :method,
5
+ attr_reader :key,
6
+ :name,
8
7
  :sub_navigation,
9
8
  :url
10
9
 
11
- attr_writer :html_options
12
-
13
10
  # see ItemContainer#item
14
11
  #
15
12
  # The subnavigation (if any) is either provided by a block or
16
13
  # passed in directly as <tt>items</tt>
17
- def initialize(container, key, name, url_or_options = {}, options_or_nil = {}, items = nil, &sub_nav_block)
18
- options = setup_url_and_options(url_or_options, options_or_nil)
19
-
20
- @key = key
21
- @method = options.delete(:method)
22
- @name = name
23
- @container = setup_container(container, options)
14
+ def initialize(container, key, name, url = nil, opts = {}, &sub_nav_block)
15
+ self.container = container
16
+ self.key = key
17
+ self.name = name.respond_to?(:call) ? name.call : name
18
+ self.url = url.respond_to?(:call) ? url.call : url
19
+ self.options = opts
24
20
 
25
- setup_sub_navigation(items, &sub_nav_block)
21
+ setup_sub_navigation(options[:items], &sub_nav_block)
26
22
  end
27
23
 
28
24
  # Returns the item's name.
@@ -32,8 +28,8 @@ module SimpleNavigation
32
28
  #
33
29
  def name(options = {})
34
30
  options = { apply_generator: true }.merge(options)
35
- if (options[:apply_generator])
36
- SimpleNavigation.config.name_generator.call(@name, self)
31
+ if options[:apply_generator]
32
+ config.name_generator.call(@name, self)
37
33
  else
38
34
  @name
39
35
  end
@@ -42,35 +38,32 @@ module SimpleNavigation
42
38
  # Returns true if this navigation item should be rendered as 'selected'.
43
39
  # An item is selected if
44
40
  #
45
- # * it has been explicitly selected in a controller or
46
41
  # * it has a subnavigation and one of its subnavigation items is selected or
47
42
  # * its url matches the url of the current request (auto highlighting)
48
43
  #
49
44
  def selected?
50
- @selected ||= selected_by_config? ||
51
- selected_by_subnav? ||
52
- selected_by_condition?
45
+ @selected ||= selected_by_subnav? || selected_by_condition?
53
46
  end
54
47
 
55
48
  # Returns the html-options hash for the item, i.e. the options specified
56
49
  # for this item in the config-file.
57
50
  # It also adds the 'selected' class to the list of classes if necessary.
58
51
  def html_options
59
- options = @html_options
60
- options[:id] ||= autogenerated_item_id if autogenerate_item_ids?
52
+ html_opts = options.fetch(:html) { Hash.new }
53
+ html_opts[:id] ||= autogenerated_item_id
61
54
 
62
- classes = [@html_options[:class], selected_class, active_leaf_class]
55
+ classes = [html_opts[:class], selected_class, active_leaf_class]
63
56
  classes = classes.flatten.compact.join(' ')
64
- options[:class] = classes unless classes.nil? || classes.empty?
57
+ html_opts[:class] = classes if classes && !classes.empty?
65
58
 
66
- options
59
+ html_opts
67
60
  end
68
61
 
69
62
  # Returns the configured active_leaf_class if the item is the selected leaf,
70
63
  # nil otherwise
71
64
  def active_leaf_class
72
65
  if !selected_by_subnav? && selected_by_condition?
73
- SimpleNavigation.config.active_leaf_class
66
+ config.active_leaf_class
74
67
  end
75
68
  end
76
69
 
@@ -78,10 +71,26 @@ module SimpleNavigation
78
71
  # nil otherwise
79
72
  def selected_class
80
73
  if selected?
81
- container.selected_class || SimpleNavigation.config.selected_class
74
+ container.selected_class || config.selected_class
82
75
  end
83
76
  end
84
77
 
78
+ # Returns the :highlights_on option as set at initialization
79
+ def highlights_on
80
+ @highlights_on ||= options[:highlights_on]
81
+ end
82
+
83
+ # Returns the :method option as set at initialization
84
+ def method
85
+ @method ||= options[:method]
86
+ end
87
+
88
+ # Returns the html attributes for the link as set with the :link_html option
89
+ # at initialization
90
+ def link_html_options
91
+ @link_html_options ||= options[:link_html]
92
+ end
93
+
85
94
  protected
86
95
 
87
96
  # Returns true if item has a subnavigation and
@@ -90,10 +99,6 @@ module SimpleNavigation
90
99
  sub_navigation && sub_navigation.selected?
91
100
  end
92
101
 
93
- def selected_by_config?
94
- false
95
- end
96
-
97
102
  # Returns true if the item's url matches the request's current url.
98
103
  def selected_by_condition?
99
104
  highlights_on ? selected_by_highlights_on? : selected_by_autohighlight?
@@ -104,86 +109,74 @@ module SimpleNavigation
104
109
  url == '/' && SimpleNavigation.request_path == '/'
105
110
  end
106
111
 
107
- # Returns true if the item's id should be added to the rendered output.
108
- def autogenerate_item_ids?
109
- SimpleNavigation.config.autogenerate_item_ids
110
- end
111
-
112
112
  # Returns the item's id which is added to the rendered output.
113
113
  def autogenerated_item_id
114
- SimpleNavigation.config.id_generator.call(key)
114
+ config.id_generator.call(key) if config.autogenerate_item_ids
115
115
  end
116
116
 
117
117
  # Return true if auto_highlight is on for this item.
118
118
  def auto_highlight?
119
- SimpleNavigation.config.auto_highlight && container.auto_highlight
120
- end
121
-
122
- def url_without_anchor
123
- url && url.split('#').first
119
+ config.auto_highlight && container.auto_highlight
124
120
  end
125
121
 
126
122
  private
127
123
 
128
- attr_reader :container
124
+ attr_accessor :container,
125
+ :options
129
126
 
130
- attr_writer :highlights_on,
127
+ attr_writer :key,
128
+ :name,
131
129
  :sub_navigation,
132
130
  :url
133
131
 
134
- def selected_by_autohighlight?
135
- auto_highlight? &&
136
- (root_path_match? ||
137
- (url_without_anchor &&
138
- SimpleNavigation.current_page?(url_without_anchor)))
132
+ def config
133
+ SimpleNavigation.config
139
134
  end
140
135
 
141
- def selected_by_highlights_on?
142
- return false unless highlights_on
136
+ def request_uri
137
+ SimpleNavigation.request_uri
138
+ end
143
139
 
144
- case highlights_on
145
- when Regexp then SimpleNavigation.request_uri =~ highlights_on
146
- when Proc then highlights_on.call
147
- when :subpath
148
- escaped_url = Regexp.escape(url_without_anchor)
149
- !!(SimpleNavigation.request_uri =~ /^#{escaped_url}(\/|$|\?)/i)
150
- else
151
- fail ArgumentError, ':highlights_on must be a Regexp, Proc or :subpath'
152
- end
140
+ def remove_anchors(url_with_anchors)
141
+ url_with_anchors && url_with_anchors.split('#').first
153
142
  end
154
143
 
155
- def setup_container(container, options = {})
156
- if options[:container_class]
157
- container.dom_class = options.delete(:container_class)
158
- end
144
+ def remove_query_params(url_with_params)
145
+ url_with_params && url_with_params.split('?').first
146
+ end
159
147
 
160
- if options[:container_id]
161
- container.dom_id = options.delete(:container_id)
162
- end
148
+ def url_for_autohighlight
149
+ relevant_url = remove_anchors(self.url) if config.ignore_anchors_on_auto_highlight
150
+ relevant_url = remove_query_params(relevant_url) if config.ignore_query_params_on_auto_highlight
151
+ relevant_url
152
+ end
163
153
 
164
- container.dom_attributes = if options[:container_attributes]
165
- options.delete(:container_attributes)
166
- else
167
- {}
168
- end
154
+ def selected_by_autohighlight?
155
+ return false unless auto_highlight?
156
+ return false unless self.url
169
157
 
170
- if options[:selected_class]
171
- container.selected_class = options.delete(:selected_class)
172
- end
158
+ root_path_match? ||
159
+ (url_for_autohighlight && SimpleNavigation.current_page?(url_for_autohighlight)) ||
160
+ autohighlight_by_subpath?
161
+ end
173
162
 
174
- container
163
+ def autohighlight_by_subpath?
164
+ config.highlight_on_subpath && selected_by_subpath?
175
165
  end
176
166
 
177
- def setup_url_and_options(url_or_options, options_or_nil)
178
- case url_or_options
179
- when Hash then options = url_or_options # there is no url
180
- when Proc then self.url = url_or_options.call
181
- else self.url = url_or_options
167
+ def selected_by_highlights_on?
168
+ case highlights_on
169
+ when Regexp then !!(request_uri =~ highlights_on)
170
+ when Proc then highlights_on.call
171
+ when :subpath then selected_by_subpath?
172
+ else
173
+ fail ArgumentError, ':highlights_on must be a Regexp, Proc or :subpath'
182
174
  end
175
+ end
183
176
 
184
- options ||= options_or_nil
185
- self.highlights_on = options.delete(:highlights_on)
186
- self.html_options = options
177
+ def selected_by_subpath?
178
+ escaped_url = Regexp.escape(url_for_autohighlight)
179
+ !!(request_uri =~ /^#{escaped_url}(\/|$||\?)/i)
187
180
  end
188
181
 
189
182
  def setup_sub_navigation(items = nil, &sub_nav_block)
@@ -1,4 +1,5 @@
1
1
  require 'forwardable'
2
+ require 'ostruct'
2
3
 
3
4
  module SimpleNavigation
4
5
  # This class acts as an adapter to items that are not defined using the DSL
@@ -30,7 +31,7 @@ module SimpleNavigation
30
31
  attr_reader :item
31
32
 
32
33
  def initialize(item)
33
- @item = item.is_a?(Hash) ? to_object(item) : item
34
+ @item = item.is_a?(Hash) ? OpenStruct.new(item) : item
34
35
  end
35
36
 
36
37
  # Returns the options for this item. If the wrapped item does not implement
@@ -47,22 +48,7 @@ module SimpleNavigation
47
48
 
48
49
  # Converts this Item into a SimpleNavigation::Item
49
50
  def to_simple_navigation_item(item_container)
50
- SimpleNavigation::Item.new(item_container, key, name, url, options, items)
51
- end
52
-
53
- protected
54
-
55
- # Converts the specified hash into an object. Each key will be added
56
- # as method.
57
- def to_object(hash)
58
- mod = Module.new do
59
- hash.each_pair do |key, value|
60
- define_method key do
61
- value
62
- end
63
- end
64
- end
65
- Object.new.extend(mod)
51
+ SimpleNavigation::Item.new(item_container, key, name, url, options)
66
52
  end
67
53
  end
68
54
  end
@@ -59,22 +59,18 @@ module SimpleNavigation
59
59
  # set a regexp which is matched againstthe current URI.
60
60
  #
61
61
  # The <tt>block</tt> - if specified - will hold the item's sub_navigation.
62
- def item(key, name, url_or_options = {}, options_or_nil = {}, &block)
63
- options = url_or_options.is_a?(Hash) ? url_or_options : options_or_nil
62
+ def item(key, name, url = nil, options = {}, &block)
64
63
  return unless should_add_item?(options)
65
- items << SimpleNavigation::Item.new(self,
66
- key,
67
- name,
68
- url_or_options,
69
- options_or_nil,
70
- nil,
71
- &block)
64
+ item = Item.new(self, key, name, url, options, &block)
65
+ add_item item, options
72
66
  end
73
67
 
74
68
  def items=(new_items)
75
- @items += new_items.map { |item| ItemAdapter.new(item) }
76
- .keep_if { |item| should_add_item?(item.options) }
77
- .map { |item| item.to_simple_navigation_item(self) }
69
+ new_items.each do |item|
70
+ item_adapter = ItemAdapter.new(item)
71
+ next unless should_add_item?(item_adapter.options)
72
+ add_item item_adapter.to_simple_navigation_item(self), item_adapter.options
73
+ end
78
74
  end
79
75
 
80
76
  # Returns the Item with the specified key, nil otherwise.
@@ -148,6 +144,19 @@ module SimpleNavigation
148
144
 
149
145
  private
150
146
 
147
+ def add_item(item, options)
148
+ items << item
149
+ modify_dom_attributes(options)
150
+ end
151
+
152
+ def modify_dom_attributes(options)
153
+ return unless container_options = options[:container]
154
+ self.dom_attributes = container_options.fetch(:attributes) { dom_attributes }
155
+ self.dom_class = container_options.fetch(:class) { dom_class }
156
+ self.dom_id = container_options.fetch(:id) { dom_id }
157
+ self.selected_class = container_options.fetch(:selected_class) { selected_class }
158
+ end
159
+
151
160
  # FIXME: raise an exception if :rederer is a symbol and it is not registred
152
161
  # in SimpleNavigation.registered_renderers
153
162
  def renderer_instance(options)
@@ -166,8 +175,8 @@ module SimpleNavigation
166
175
  end
167
176
 
168
177
  def should_add_item?(options)
169
- [options.delete(:if)].flatten.compact.all? { |m| evaluate_method(m) } &&
170
- [options.delete(:unless)].flatten.compact.none? { |m| evaluate_method(m) }
178
+ [options[:if]].flatten.compact.all? { |m| evaluate_method(m) } &&
179
+ [options[:unless]].flatten.compact.none? { |m| evaluate_method(m) }
171
180
  end
172
181
 
173
182
  def evaluate_method(method)
@@ -0,0 +1,7 @@
1
+ module SimpleNavigation
2
+ class Railtie < ::Rails::Railtie
3
+ initializer 'simple_navigation.register' do |app|
4
+ SimpleNavigation.register
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,12 @@
1
+ require 'simple_navigation/helpers'
2
+ require 'simple_navigation/renderer/base'
3
+
4
+ module SimpleNavigation
5
+ module Renderer
6
+ autoload :List, 'simple_navigation/renderer/list'
7
+ autoload :Links, 'simple_navigation/renderer/links'
8
+ autoload :Breadcrumbs, 'simple_navigation/renderer/breadcrumbs'
9
+ autoload :Text, 'simple_navigation/renderer/text'
10
+ autoload :Json, 'simple_navigation/renderer/json'
11
+ end
12
+ end
@@ -95,7 +95,7 @@ module SimpleNavigation
95
95
  class: item.selected_class
96
96
  }.reject { |_, v| v.nil? }
97
97
 
98
- link_options = item.html_options[:link]
98
+ link_options = item.link_html_options
99
99
 
100
100
  return special_options unless link_options
101
101
 
@@ -1,3 +1,5 @@
1
+ require 'json'
2
+
1
3
  module SimpleNavigation
2
4
  module Renderer
3
5
  # Renders the navigation items as a object tree serialized as a json string,
@@ -1,3 +1,3 @@
1
1
  module SimpleNavigation
2
- VERSION = '3.13.0'
2
+ VERSION = '4.0.5'
3
3
  end