simple-navigation 3.14.0 → 4.0.0

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 (70) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +10 -2
  5. data/CHANGELOG.md +400 -0
  6. data/Guardfile +4 -2
  7. data/README.md +1 -1
  8. data/gemfiles/.bundle/config +2 -0
  9. data/gemfiles/rails-3-2-stable.gemfile +10 -0
  10. data/gemfiles/rails-4-1-stable.gemfile +6 -0
  11. data/gemfiles/rails-4-2-stable.gemfile +7 -0
  12. data/generators/navigation_config/navigation_config_generator.rb +0 -1
  13. data/generators/navigation_config/templates/config/navigation.rb +18 -15
  14. data/lib/simple_navigation.rb +25 -42
  15. data/lib/simple_navigation/adapters/rails.rb +1 -24
  16. data/lib/simple_navigation/adapters/sinatra.rb +2 -11
  17. data/lib/simple_navigation/config_file.rb +36 -0
  18. data/lib/simple_navigation/config_file_finder.rb +42 -0
  19. data/lib/simple_navigation/{core/configuration.rb → configuration.rb} +7 -1
  20. data/lib/simple_navigation/{rendering/helpers.rb → helpers.rb} +0 -4
  21. data/lib/simple_navigation/{core/item.rb → item.rb} +76 -85
  22. data/lib/simple_navigation/{core/item_adapter.rb → item_adapter.rb} +3 -17
  23. data/lib/simple_navigation/{core/item_container.rb → item_container.rb} +23 -14
  24. data/lib/simple_navigation/{core/items_provider.rb → items_provider.rb} +0 -0
  25. data/lib/simple_navigation/railtie.rb +7 -0
  26. data/lib/simple_navigation/renderer.rb +12 -0
  27. data/lib/simple_navigation/{rendering/renderer → renderer}/base.rb +1 -1
  28. data/lib/simple_navigation/{rendering/renderer → renderer}/breadcrumbs.rb +0 -0
  29. data/lib/simple_navigation/{rendering/renderer → renderer}/json.rb +2 -0
  30. data/lib/simple_navigation/{rendering/renderer → renderer}/links.rb +0 -0
  31. data/lib/simple_navigation/{rendering/renderer → renderer}/list.rb +0 -0
  32. data/lib/simple_navigation/{rendering/renderer → renderer}/text.rb +0 -0
  33. data/lib/simple_navigation/version.rb +1 -1
  34. data/simple-navigation.gemspec +5 -4
  35. data/spec/fake_app/config/navigation.rb +6 -0
  36. data/spec/fake_app/rails_app.rb +35 -0
  37. data/spec/initializers/coveralls.rb +3 -0
  38. data/spec/initializers/have_css_matcher.rb +8 -3
  39. data/spec/initializers/memfs.rb +7 -0
  40. data/spec/initializers/rails.rb +4 -0
  41. data/spec/initializers/rspec.rb +7 -0
  42. data/spec/integration/rendering_navigation_spec.rb +12 -0
  43. data/spec/{lib/simple_navigation → simple_navigation}/adapters/padrino_spec.rb +0 -2
  44. data/spec/{lib/simple_navigation → simple_navigation}/adapters/rails_spec.rb +36 -93
  45. data/spec/{lib/simple_navigation → simple_navigation}/adapters/sinatra_spec.rb +4 -6
  46. data/spec/simple_navigation/config_file_finder_spec.rb +50 -0
  47. data/spec/simple_navigation/config_file_spec.rb +25 -0
  48. data/spec/{lib/simple_navigation/core → simple_navigation}/configuration_spec.rb +29 -19
  49. data/spec/{lib/simple_navigation/rendering → simple_navigation}/helpers_spec.rb +10 -13
  50. data/spec/{lib/simple_navigation/core → simple_navigation}/item_adapter_spec.rb +14 -11
  51. data/spec/{lib/simple_navigation/core → simple_navigation}/item_container_spec.rb +130 -42
  52. data/spec/simple_navigation/item_spec.rb +467 -0
  53. data/spec/{lib/simple_navigation/core → simple_navigation}/items_provider_spec.rb +1 -3
  54. data/spec/{lib/simple_navigation/rendering → simple_navigation}/renderer/base_spec.rb +34 -36
  55. data/spec/{lib/simple_navigation/rendering → simple_navigation}/renderer/breadcrumbs_spec.rb +4 -7
  56. data/spec/{lib/simple_navigation/rendering → simple_navigation}/renderer/json_spec.rb +5 -11
  57. data/spec/{lib/simple_navigation/rendering → simple_navigation}/renderer/links_spec.rb +5 -8
  58. data/spec/{lib/simple_navigation/rendering → simple_navigation}/renderer/list_spec.rb +4 -7
  59. data/spec/{lib/simple_navigation/rendering → simple_navigation}/renderer/text_spec.rb +4 -7
  60. data/spec/simple_navigation_spec.rb +190 -0
  61. data/spec/spec_helper.rb +29 -35
  62. metadata +103 -68
  63. data/CHANGELOG +0 -292
  64. data/lib/simple_navigation/core.rb +0 -5
  65. data/lib/simple_navigation/rails_controller_methods.rb +0 -164
  66. data/lib/simple_navigation/rendering.rb +0 -12
  67. data/rails/init.rb +0 -1
  68. data/spec/lib/simple_navigation/core/item_spec.rb +0 -703
  69. data/spec/lib/simple_navigation/rails_controller_methods_spec.rb +0 -270
  70. data/spec/lib/simple_navigation_spec.rb +0 -300
@@ -1,5 +0,0 @@
1
- require 'simple_navigation/core/configuration'
2
- require 'simple_navigation/core/item_adapter'
3
- require 'simple_navigation/core/item'
4
- require 'simple_navigation/core/item_container'
5
- require 'simple_navigation/core/items_provider'
@@ -1,164 +0,0 @@
1
- module SimpleNavigation
2
- def self.explicit_navigation_args
3
- adapter.controller.instance_variable_get(:'@sn_current_navigation_args')
4
- end
5
-
6
- # Reads the current navigation for the specified level from the controller.
7
- # Returns nil if there is no current navigation set for level.
8
- def self.current_navigation_for(level)
9
- adapter.controller.instance_variable_get(:"@sn_current_navigation_#{level}")
10
- end
11
-
12
- # If any navigation has been explicitely set in the controller this method
13
- # evaluates the specified args set in the controller and sets the correct
14
- # instance variable in the controller.
15
- def self.handle_explicit_navigation
16
- return unless explicit_navigation_args
17
- level, navigation = parse_explicit_navigation_args
18
- navigation_level = :"@sn_current_navigation_#{level}"
19
- adapter.controller.instance_variable_set(navigation_level, navigation)
20
- end
21
-
22
- def self.parse_explicit_navigation_args
23
- args = if explicit_navigation_args.empty?
24
- [{}]
25
- else
26
- explicit_navigation_args
27
- end
28
- indexed_args = args_indexed_by_level(args)
29
- deepest = deepest_level_and_item(indexed_args)
30
-
31
- if deepest.first.zero?
32
- fail ArgumentError, 'Invalid level specified or item key not found'
33
- end
34
-
35
- deepest
36
- end
37
-
38
- private
39
-
40
- def self.deepest_level_and_item(navigation_args)
41
- navigation_args.map { |k, v| [k.to_s[/level_(\d)/, 1].to_i, v] }
42
- .max
43
- end
44
-
45
- def self.args_indexed_by_level(navigation_args)
46
- if navigation_args.first.is_a?(Hash)
47
- navigation_args.first
48
- elsif navigation_args.size == 1
49
- level = primary_navigation.level_for_item(navigation_args.first)
50
- level ? { :"level_#{level}" => navigation_args.first } : {}
51
- else
52
- navigation_args.each_with_index
53
- .with_object({}) do |(arg, i), h|
54
- h[:"level_#{i + 1}"] = arg
55
- end
56
- end
57
- end
58
-
59
- # Adds methods for explicitely setting the current 'active' navigation to
60
- # the controllers.
61
- # Since version 2.0.0 the simple_navigation plugin determines the active
62
- # navigation based on the current url by default (auto highlighting),
63
- # so explicitely defining the active navigation in the controllers is only
64
- # needed for edge cases where automatic highlighting does not work.
65
- #
66
- # On the controller class level, use the <tt>navigation</tt> method to set the
67
- # active navigation for all actions in the controller.
68
- # Let's assume that we have a primary navigation item :account which in turn
69
- # has a sub navigation item :settings.
70
- #
71
- # ==== Examples
72
- # class AccountController << ActionController
73
- # navigation :account
74
- # ...
75
- # end
76
- #
77
- # class AccountSettingsController << ActionController
78
- # navigation :settings
79
- # ...
80
- # end
81
- #
82
- # The first example sets the current primary navigation to :account for all
83
- # actions. No active sub_navigation.
84
- # The second example sets the current sub navigation to :settings and since
85
- # it is a child of :account the current primary navigation is set to :account.
86
- #
87
- # On the controller instance level, use the <tt>current_navigation</tt> method
88
- # to define the active navigation for a specific action.
89
- # The navigation item that is set in <tt>current_navigation</tt> overrides the
90
- # one defined on the controller class level (see <tt>navigation</tt> method).
91
- # Thus if you have an :account primary item with a :special
92
- # sub navigation item:
93
- #
94
- # ==== Example
95
- # class AccountController << ActionController
96
- # navigation :account
97
- #
98
- # def your_special_action
99
- # ...
100
- # current_navigation :special
101
- # end
102
- # end
103
- #
104
- # The code above still sets the active primary navigation to :account for all
105
- # actions, but sets the sub_navigation to :account -> :special for
106
- # 'your_special_action'.
107
- #
108
- # Note 1: As you can see above you just have to set the navigation item of
109
- # your 'deepest' navigation level as active and all its parents are
110
- # marked as active, too.
111
- #
112
- # Note 2: The specified symbols must match the keys for your navigation
113
- # items in your config/navigation.rb file.
114
- module ControllerMethods
115
- def self.included(base) #:nodoc:
116
- base.class_eval do
117
- extend ClassMethods
118
- include InstanceMethods
119
- end
120
- end
121
-
122
- module ClassMethods
123
- # Sets the active navigation for all actions in this controller.
124
- #
125
- # The specified symbol must match the keys for your navigation items
126
- # in your config/navigation.rb file.
127
- def navigation(*args)
128
- class_eval do
129
- define_method :sn_set_navigation do
130
- current_navigation(*args)
131
- end
132
- protected :sn_set_navigation
133
- before_filter :sn_set_navigation
134
- end
135
- end
136
- end
137
-
138
- module InstanceMethods
139
- # Sets the active navigation. Call this method in any action to override
140
- # the controller-wide active navigation specified by navigation.
141
- #
142
- # The specified symbol must match the keys for your navigation items in
143
- # your config/navigation.rb file.
144
- def current_navigation(*args)
145
- @sn_current_navigation_args = args
146
- end
147
- end
148
- end
149
-
150
- class Item
151
- def selected_by_config?
152
- key == SimpleNavigation.current_navigation_for(container.level)
153
- end
154
- end
155
-
156
- class ItemContainer
157
- def selected_item
158
- self[SimpleNavigation.current_navigation_for(level)] ||
159
- items.find(&:selected?)
160
- end
161
- end
162
- end
163
-
164
- ActionController::Base.send(:include, SimpleNavigation::ControllerMethods)
@@ -1,12 +0,0 @@
1
- require 'simple_navigation/rendering/helpers'
2
- require 'simple_navigation/rendering/renderer/base'
3
-
4
- module SimpleNavigation
5
- module Renderer
6
- autoload :List, 'simple_navigation/rendering/renderer/list'
7
- autoload :Links, 'simple_navigation/rendering/renderer/links'
8
- autoload :Breadcrumbs, 'simple_navigation/rendering/renderer/breadcrumbs'
9
- autoload :Text, 'simple_navigation/rendering/renderer/text'
10
- autoload :Json, 'simple_navigation/rendering/renderer/json'
11
- end
12
- end
data/rails/init.rb DELETED
@@ -1 +0,0 @@
1
- SimpleNavigation.register
@@ -1,703 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module SimpleNavigation
4
- describe Item do
5
- let!(:item_container) { ItemContainer.new }
6
-
7
- let(:adapter) { double(:adapter) }
8
- let(:item_args) { [item_container, :my_key, 'name', url, options, items] }
9
- let(:item) { Item.new(*item_args) }
10
- let(:items) { nil }
11
- let(:options) { Hash.new }
12
- let(:url) { 'url' }
13
-
14
- before { SimpleNavigation.stub(adapter: adapter) }
15
-
16
- describe '#initialize' do
17
- context 'when there is a sub_navigation' do
18
- let(:subnav_container) { double(:subnav_container).as_null_object }
19
-
20
- before { ItemContainer.stub(new: subnav_container) }
21
-
22
- context 'when a block is given' do
23
- it 'creates a new ItemContainer with a level+1' do
24
- expect(ItemContainer).to receive(:new).with(2)
25
- Item.new(*item_args) {}
26
- end
27
-
28
- it 'calls the block' do
29
- expect{ |blk|
30
- Item.new(*item_args, &blk)
31
- }.to yield_with_args(subnav_container)
32
- end
33
- end
34
-
35
- context 'when no block is given' do
36
- context 'and items are given' do
37
- let(:items) { double(:items) }
38
-
39
- it 'creates a new ItemContainer with a level+1' do
40
- expect(ItemContainer).to receive(:new).with(2)
41
- Item.new(*item_args)
42
- end
43
-
44
- it "sets the items on the subnav_container" do
45
- expect(subnav_container).to receive(:items=).with(items)
46
- Item.new(*item_args)
47
- end
48
- end
49
-
50
- context 'and no items are given' do
51
- it "doesn't create a new ItemContainer" do
52
- expect(ItemContainer).not_to receive(:new)
53
- Item.new(*item_args)
54
- end
55
- end
56
- end
57
- end
58
-
59
- context 'when a :method option is given' do
60
- let(:options) {{ method: :delete }}
61
-
62
- it "sets the item's method" do
63
- expect(item.method).to eq :delete
64
- end
65
-
66
- it 'sets the html options without the method' do
67
- meth = item.instance_variable_get(:@html_options).key?(:method)
68
- expect(meth).to be_false
69
- end
70
- end
71
-
72
- context 'when no :method option is given' do
73
- it "sets the item's method to nil" do
74
- expect(item.method).to be_nil
75
- end
76
- end
77
-
78
- context 'setting class and id on the container' do
79
- let!(:create) { item }
80
-
81
- let(:options) {{
82
- container_class: 'container_class',
83
- container_id: 'container_id',
84
- container_attributes: { 'ng-show' => 'false' }
85
- }}
86
-
87
- it "fills in the container's dom_attributes" do
88
- expect(item_container.dom_attributes).to eq({
89
- id: 'container_id',
90
- class: 'container_class',
91
- 'ng-show' => 'false'
92
- })
93
- end
94
- end
95
-
96
- context 'when a :highlights_on option is given' do
97
- it "sets the item's highlights_on to nil" do
98
- expect(item.highlights_on).to be_nil
99
- end
100
- end
101
-
102
- context 'when no :highlights_on option is given' do
103
- let(:highlights_on) { double(:highlights_on) }
104
- let(:options) {{ highlights_on: highlights_on }}
105
-
106
- it "sets the item's highlights_on" do
107
- expect(item.highlights_on).to eq highlights_on
108
- end
109
-
110
- it 'sets the html options without the method' do
111
- html_options = item.instance_variable_get(:@html_options)
112
- expect(html_options).not_to have_key(:highlights_on)
113
- end
114
- end
115
-
116
- context 'when a url is given' do
117
- context 'and it is a string' do
118
- it "sets the item's url accordingly" do
119
- expect(item.url).to eq 'url'
120
- end
121
- end
122
-
123
- context 'and it is a proc' do
124
- let(:url) { proc{ "my_" + "url" } }
125
-
126
- it "sets the item's url accordingly" do
127
- expect(item.url).to eq 'my_url'
128
- end
129
- end
130
-
131
- context 'and it is nil' do
132
- let(:url) { nil }
133
-
134
- it "sets the item's url accordingly" do
135
- expect(item.url).to be_nil
136
- end
137
- end
138
- end
139
-
140
- describe 'Optional url and optional options' do
141
- context 'when no parameter is specified' do
142
- let(:item_args) { [item_container, :my_key, 'name'] }
143
-
144
- it "sets the item's url to nil" do
145
- expect(item.url).to be_nil
146
- end
147
-
148
- it "sets the item's html_options to an empty hash" do
149
- expect(item.instance_variable_get(:@html_options)).to eq({})
150
- end
151
- end
152
-
153
- context 'when only a url is given' do
154
- let(:item_args) { [item_container, :my_key, 'name', 'url'] }
155
-
156
- it "set the item's url accordingly" do
157
- expect(item.url).to eq 'url'
158
- end
159
-
160
- it "sets the item's html_options to an empty hash" do
161
- expect(item.instance_variable_get(:@html_options)).to eq({})
162
- end
163
- end
164
-
165
- context 'when only options are given' do
166
- let(:item_args) { [item_container, :my_key, 'name', { option: true }] }
167
-
168
- it "sets the item's url to nil" do
169
- expect(item.url).to be_nil
170
- end
171
-
172
- it "sets the item's html_options accordingly" do
173
- html_options = item.instance_variable_get(:@html_options)
174
- expect(html_options).to eq({ option: true })
175
- end
176
- end
177
-
178
- context 'when url and options are given' do
179
- let(:options) {{ option: true }}
180
-
181
- it "set the item's url accordingly" do
182
- expect(item.url).to eq 'url'
183
- end
184
-
185
- it "sets the item's html_options accordingly" do
186
- html_options = item.instance_variable_get(:@html_options)
187
- expect(html_options).to eq({ option: true })
188
- end
189
- end
190
- end
191
- end
192
-
193
- describe '#name' do
194
- before do
195
- SimpleNavigation.config.stub(
196
- name_generator: proc{ |name| "<span>#{name}</span>" })
197
- end
198
-
199
- context 'when no option is given' do
200
- context 'and the name_generator uses only the name' do
201
- it 'uses the default name_generator' do
202
- expect(item.name).to eq '<span>name</span>'
203
- end
204
- end
205
-
206
- context 'and the name_generator uses only the item itself' do
207
- before do
208
- SimpleNavigation.config.stub(
209
- name_generator: proc{ |name, item| "<span>#{item.key}</span>" })
210
- end
211
-
212
- it 'uses the default name_generator' do
213
- expect(item.name).to eq '<span>my_key</span>'
214
- end
215
- end
216
- end
217
-
218
- context 'when the :apply_generator is false' do
219
- it "returns the item's name" do
220
- expect(item.name(apply_generator: false)).to eq 'name'
221
- end
222
- end
223
- end
224
-
225
- describe '#selected?' do
226
- context 'when the item is explicitly selected' do
227
- before { item.stub(selected_by_config?: true) }
228
-
229
- it 'is selected' do
230
- expect(item).to be_selected
231
- end
232
-
233
- # FIXME: testing the implementation not the behavior here
234
- it "doesn't check for selection by sub navigation" do
235
- expect(item).not_to receive(:selected_by_subnav?)
236
- item.selected?
237
- end
238
-
239
- # FIXME: testing the implementation not the behavior here
240
- it "doesn't check for selection by highlighting condition" do
241
- expect(item).not_to receive(:selected_by_condition?)
242
- item.selected?
243
- end
244
- end
245
-
246
- context "when the item isn't explicitly selected" do
247
- before { item.stub(selected_by_config?: false) }
248
-
249
- context 'and it is selected by sub navigation' do
250
- before { item.stub(selected_by_subnav?: true) }
251
-
252
- it 'is selected' do
253
- expect(item).to be_selected
254
- end
255
- end
256
-
257
- context "and it isn't selected by sub navigation" do
258
- before { item.stub(selected_by_subnav?: false) }
259
-
260
- context 'and it is selected by a highlighting condition' do
261
- before { item.stub(selected_by_condition?: true) }
262
-
263
- it 'is selected' do
264
- expect(item).to be_selected
265
- end
266
- end
267
-
268
- context "and it isn't selected by any highlighting condition" do
269
- before { item.stub(selected_by_condition?: false) }
270
-
271
- it "isn't selected" do
272
- expect(item).not_to be_selected
273
- end
274
- end
275
- end
276
- end
277
- end
278
-
279
- describe '#selected_class' do
280
- context 'when the item is selected' do
281
- before { item.stub(selected?: true) }
282
-
283
- it 'returns the default selected_class' do
284
- expect(item.selected_class).to eq 'selected'
285
- end
286
-
287
- context 'and selected_class is defined in the context' do
288
- before { item_container.stub(selected_class: 'defined') }
289
-
290
- it "returns the context's selected_class" do
291
- expect(item.selected_class).to eq 'defined'
292
- end
293
- end
294
- end
295
-
296
- context 'when the item is not selected' do
297
- before { item.stub(selected?: false) }
298
-
299
- it 'returns nil' do
300
- expect(item.selected_class).to be_nil
301
- end
302
- end
303
- end
304
-
305
- describe ':html_options argument' do
306
- let(:selected_classes) { 'selected simple-navigation-active-leaf' }
307
-
308
- context 'when the :class option is given' do
309
- let(:options) {{ class: 'my_class' }}
310
-
311
- context 'and the item is selected' do
312
- before { item.stub(selected?: true, selected_by_condition?: true) }
313
-
314
- it "adds the specified class to the item's html classes" do
315
- expect(item.html_options[:class]).to include('my_class')
316
- end
317
-
318
- it "doesn't replace the default html classes of a selected item" do
319
- expect(item.html_options[:class]).to include(selected_classes)
320
- end
321
- end
322
-
323
- context "and the item isn't selected" do
324
- before { item.stub(selected?: false, selected_by_condition?: false) }
325
-
326
- it "sets the specified class as the item's html classes" do
327
- expect(item.html_options[:class]).to include('my_class')
328
- end
329
- end
330
- end
331
-
332
- context "when the :class option isn't given" do
333
- context 'and the item is selected' do
334
- before { item.stub(selected?: true, selected_by_condition?: true) }
335
-
336
- it "sets the default html classes of a selected item" do
337
- expect(item.html_options[:class]).to include(selected_classes)
338
- end
339
- end
340
-
341
- context "and the item isn't selected" do
342
- before { item.stub(selected?: false, selected_by_condition?: false) }
343
-
344
- it "doesn't set any html class on the item" do
345
- expect(item.html_options[:class]).to be_blank
346
- end
347
- end
348
- end
349
-
350
- shared_examples 'generating id' do |id|
351
- it "sets the item's html id to the specified id" do
352
- expect(item.html_options[:id]).to eq id
353
- end
354
- end
355
-
356
- describe 'when the :id option is given' do
357
- let(:options) {{ id: 'my_id' }}
358
-
359
- before do
360
- item.stub(selected?: false,
361
- selected_by_condition?: false,
362
- autogenerate_item_ids?: generate_ids)
363
- end
364
-
365
- context 'and :autogenerate_item_ids is true' do
366
- let(:generate_ids) { true }
367
-
368
- it_behaves_like 'generating id', 'my_id'
369
- end
370
-
371
- context 'and :autogenerate_item_ids is false' do
372
- let(:generate_ids) { false }
373
-
374
- it_behaves_like 'generating id', 'my_id'
375
- end
376
- end
377
-
378
- context "when the :id option isn't given" do
379
- before do
380
- item.stub(selected?: false,
381
- selected_by_condition?: false,
382
- autogenerate_item_ids?: generate_ids)
383
- end
384
-
385
- context 'and :autogenerate_item_ids is true' do
386
- let(:generate_ids) { true }
387
-
388
- it_behaves_like 'generating id', 'my_key'
389
- end
390
-
391
- context 'and :autogenerate_item_ids is false' do
392
- let(:generate_ids) { false }
393
-
394
- it "doesn't set any html id on the item" do
395
- expect(item.html_options[:id]).to be_blank
396
- end
397
- end
398
- end
399
- end
400
-
401
- describe '#selected_by_subnav?' do
402
- before { item.stub(sub_navigation: sub_navigation) }
403
-
404
- context 'the item has a sub_navigation' do
405
- let(:sub_navigation) { double(:sub_navigation) }
406
-
407
- context 'and an item of the sub_navigation is selected' do
408
- before do
409
- sub_navigation.stub(selected?: true, selected_by_condition?: true)
410
- end
411
-
412
- it 'returns true' do
413
- expect(item).to be_selected_by_subnav
414
- end
415
- end
416
-
417
- context 'and no item of the sub_navigation is selected' do
418
- before do
419
- sub_navigation.stub(selected?: false, selected_by_condition?: true)
420
- end
421
-
422
- it 'returns false' do
423
- expect(item).not_to be_selected_by_subnav
424
- end
425
- end
426
- end
427
-
428
- context "when the item doesn't have any sub_navigation" do
429
- let(:sub_navigation) { nil }
430
-
431
- it 'returns false' do
432
- expect(item).not_to be_selected_by_subnav
433
- end
434
- end
435
- end
436
-
437
- describe '#selected_by_condition?' do
438
- let(:current_url) { '' }
439
-
440
- before { adapter.stub(request_uri: current_url) }
441
-
442
- context 'when the :highlights_on option is set' do
443
- before { item.stub(highlights_on: /^\/matching/) }
444
-
445
- context 'and :highlights_on is a regexp' do
446
- context 'and it matches the current url' do
447
- let(:current_url) { '/matching_url' }
448
-
449
- it 'returns true' do
450
- expect(item).to be_selected_by_condition
451
- end
452
- end
453
-
454
- context "and it doesn't match current url" do
455
- let(:current_url) { '/other_url' }
456
-
457
- it 'returns false' do
458
- expect(item).not_to be_selected_by_condition
459
- end
460
- end
461
- end
462
-
463
- context 'and :highlights_on is a lambda' do
464
- context 'and it is truthy' do
465
- before { item.stub(highlights_on: ->{ true }) }
466
-
467
- it 'returns true' do
468
- expect(item).to be_selected_by_condition
469
- end
470
- end
471
-
472
- context 'falsey lambda results in no selection' do
473
- before { item.stub(highlights_on: ->{ false }) }
474
-
475
- it 'returns false' do
476
- expect(item).not_to be_selected_by_condition
477
- end
478
- end
479
- end
480
-
481
- context 'and :highlights_on is :subpath' do
482
- before { item.stub(url: '/path', highlights_on: :subpath) }
483
-
484
- context "and the current url is a sub path of the item's url" do
485
- let(:current_url) { '/path/sub-path' }
486
-
487
- it 'returns true' do
488
- expect(item).to be_selected_by_condition
489
- end
490
- end
491
-
492
- context "and the current url starts with item's url" do
493
- let(:current_url) { '/path_group/id' }
494
-
495
- it 'returns false' do
496
- expect(item).not_to be_selected_by_condition
497
- end
498
- end
499
-
500
- context "and the current url is totally different from the item's url" do
501
- let(:current_url) { '/other_path/id' }
502
-
503
- it 'returns false' do
504
- expect(item).not_to be_selected_by_condition
505
- end
506
- end
507
- end
508
-
509
- context 'when :highlights_on something else' do
510
- before { item.stub(highlights_on: 'nothing') }
511
-
512
- it 'raises an exception' do
513
- expect{ item.send(:selected_by_condition?) }.to raise_error
514
- end
515
- end
516
- end
517
-
518
- context 'when :auto_highlight is true' do
519
- before { item.stub(auto_highlight?: true) }
520
-
521
- context 'and root path matches' do
522
- before { item.stub(root_path_match?: true) }
523
-
524
- it 'returns true' do
525
- expect(item).to be_selected_by_condition
526
- end
527
- end
528
-
529
- context "and root path doesn't match" do
530
- before { item.stub(root_path_match?: false) }
531
-
532
- context "and the current url matches the item's url" do
533
- let(:url) { 'url#anchor' }
534
-
535
- before { adapter.stub(current_page?: true) }
536
-
537
- it 'returns true' do
538
- expect(item).to be_selected_by_condition
539
- end
540
-
541
- # FIXME: testing the implementation not the behavior here
542
- it "removes anchors before testing the item's url" do
543
- expect(adapter).to receive(:current_page?).with('url')
544
- item.send(:selected_by_condition?)
545
- end
546
-
547
- context 'when url is nil' do
548
- let(:url) { nil }
549
-
550
- it "doesn't check the url" do
551
- expect(adapter).not_to receive(:current_page?)
552
- item.send(:selected_by_condition?)
553
- end
554
- end
555
- end
556
-
557
- context "and the current url doesn't match the item's url" do
558
- before { adapter.stub(current_page?: false) }
559
-
560
- it 'returns false' do
561
- expect(item).not_to be_selected_by_condition
562
- end
563
- end
564
- end
565
- end
566
-
567
- context 'when :auto_highlight is false' do
568
- before { item.stub(auto_highlight?: false) }
569
-
570
- it 'returns false' do
571
- expect(item).not_to be_selected_by_condition
572
- end
573
- end
574
- end
575
-
576
- describe '#root_path_match?' do
577
- context "when current url is /" do
578
- before { adapter.stub(request_path: '/') }
579
-
580
- context "and the item's url is /" do
581
- let(:url) { '/' }
582
-
583
- it 'returns true' do
584
- expect(item.send(:root_path_match?)).to be_true
585
- end
586
- end
587
-
588
- context "and the item's url isn't /" do
589
- let(:url) { '/other' }
590
-
591
- it 'returns false' do
592
- expect(item.send(:root_path_match?)).to be_false
593
- end
594
- end
595
- end
596
-
597
- context "when current url isn't /" do
598
- before { adapter.stub(request_path: '/other') }
599
-
600
- context "and the item's url is /" do
601
- let(:url) { '/' }
602
-
603
- it 'returns false' do
604
- expect(item.send(:root_path_match?)).to be_false
605
- end
606
- end
607
-
608
- context "and the item's url is nil" do
609
- let(:url) { nil }
610
-
611
- it 'returns false' do
612
- expect(item.send(:root_path_match?)).to be_false
613
- end
614
- end
615
- end
616
-
617
- context "when current url doesn't match the item's url" do
618
- let(:url) { '/path' }
619
-
620
- before { adapter.stub(request_path: '/other') }
621
-
622
- it 'returns false' do
623
- expect(item.send(:root_path_match?)).to be_false
624
- end
625
- end
626
-
627
- context "when current url doesn't match the item's url" do
628
- let(:url) { nil }
629
-
630
- before { adapter.stub(request_path: '/other') }
631
-
632
- it 'returns false' do
633
- expect(item.send(:root_path_match?)).to be_false
634
- end
635
- end
636
- end
637
-
638
- describe '#auto_highlight?' do
639
- let(:global) { double(:config) }
640
-
641
- before { SimpleNavigation.stub(config: global) }
642
-
643
- context 'when :auto_highlight is globally true' do
644
- before { global.stub(auto_highlight: true) }
645
-
646
- context "and container's :auto_highlight is true" do
647
- before { item_container.stub(auto_highlight: true) }
648
-
649
- it 'returns true' do
650
- expect(item.send(:auto_highlight?)).to be_true
651
- end
652
- end
653
-
654
- context "and container's :auto_highlight is false" do
655
- before { item_container.stub(auto_highlight: false) }
656
-
657
- it 'returns false' do
658
- expect(item.send(:auto_highlight?)).to be_false
659
- end
660
- end
661
- end
662
-
663
- context 'when :auto_highlight is globally false' do
664
- before { global.stub(auto_highlight: false) }
665
-
666
- context 'when :auto_highlight is globally true' do
667
- before { item_container.stub(auto_highlight: true) }
668
-
669
- it 'returns false' do
670
- expect(item.send(:auto_highlight?)).to be_false
671
- end
672
- end
673
-
674
- context "and container's :auto_highlight is false" do
675
- before { item_container.stub(auto_highlight: false) }
676
-
677
- it 'returns false' do
678
- expect(item.send(:auto_highlight?)).to be_false
679
- end
680
- end
681
- end
682
- end
683
-
684
- describe '#autogenerated_item_id' do
685
- context 'when no generator is configured' do
686
- let(:id_generator) { double(:id_generator) }
687
-
688
- before { SimpleNavigation.config.stub(id_generator: id_generator) }
689
-
690
- it 'calls the globally configured id generator' do
691
- expect(id_generator).to receive(:call).with(:my_key)
692
- item.send(:autogenerated_item_id)
693
- end
694
- end
695
-
696
- context 'when no generator is configured' do
697
- it 'uses the default generator' do
698
- expect(item.send(:autogenerated_item_id)).to eq 'my_key'
699
- end
700
- end
701
- end
702
- end
703
- end