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,31 +1,36 @@
|
|
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 adds the 'selected' class to the <a> element that is currently active.
|
6
6
|
#
|
7
|
-
# The Links renderer cannot be used to render nested navigations. If you
|
8
|
-
#
|
9
|
-
#
|
10
|
-
# 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.
|
11
|
-
# The ItemContainer's dom_attributes are applied to the surrounding <div> element.
|
7
|
+
# The Links renderer cannot be used to render nested navigations. If you
|
8
|
+
# would like it to use with nested navigations, you have to render each
|
9
|
+
# level separately.
|
12
10
|
#
|
11
|
+
# By default, the renderer sets the item's key as dom_id for the rendered
|
12
|
+
# <a> element unless the config option <tt>autogenerate_item_ids</tt> is set
|
13
|
+
# to false.
|
14
|
+
# The id can also be explicitely specified by setting the id in the
|
15
|
+
# html-options of the 'item' method in the config/navigation.rb file.
|
16
|
+
# The ItemContainer's dom_attributes are applied to the surrounding <div>
|
17
|
+
# element.
|
13
18
|
class Links < SimpleNavigation::Renderer::Base
|
14
19
|
def render(item_container)
|
15
|
-
div_content = item_container.items
|
16
|
-
|
17
|
-
|
18
|
-
content_tag
|
20
|
+
div_content = item_container.items
|
21
|
+
.map { |item| tag_for(item) }
|
22
|
+
.join(join_with)
|
23
|
+
content_tag :div, div_content, item_container.dom_attributes
|
19
24
|
end
|
20
25
|
|
21
26
|
protected
|
22
27
|
|
23
28
|
def join_with
|
24
|
-
@join_with ||= options[:join_with] ||
|
29
|
+
@join_with ||= options[:join_with] || ''
|
25
30
|
end
|
26
31
|
|
27
32
|
def options_for(item)
|
28
|
-
{:
|
33
|
+
{ method: item.method }.merge(item.html_options)
|
29
34
|
end
|
30
35
|
end
|
31
36
|
end
|
@@ -1,28 +1,41 @@
|
|
1
1
|
module SimpleNavigation
|
2
2
|
module Renderer
|
3
|
-
|
4
|
-
#
|
5
|
-
# It adds the 'selected' class to li element AND the link inside the li
|
3
|
+
# Renders an ItemContainer as a <ul> element and its containing items as
|
4
|
+
# <li> elements.
|
5
|
+
# It adds the 'selected' class to li element AND the link inside the li
|
6
|
+
# element that is currently active.
|
6
7
|
#
|
7
|
-
# If the sub navigation should be included (based on the level and
|
8
|
+
# If the sub navigation should be included (based on the level and
|
9
|
+
# expand_all options), it renders another <ul> containing the sub navigation
|
10
|
+
# inside the active <li> element.
|
8
11
|
#
|
9
|
-
# By default, the renderer sets the item's key as dom_id for the rendered
|
10
|
-
#
|
12
|
+
# By default, the renderer sets the item's key as dom_id for the rendered
|
13
|
+
# <li> element unless the config option <tt>autogenerate_item_ids</tt> is
|
14
|
+
# set to false.
|
15
|
+
# The id can also be explicitely specified by setting the id in the
|
16
|
+
# html-options of the 'item' method in the config/navigation.rb file.
|
11
17
|
class List < SimpleNavigation::Renderer::Base
|
12
18
|
def render(item_container)
|
13
|
-
|
14
|
-
|
19
|
+
if skip_if_empty? && item_container.empty?
|
20
|
+
''
|
21
|
+
else
|
22
|
+
tag = options[:ordered] ? :ol : :ul
|
23
|
+
content = list_content(item_container)
|
24
|
+
content_tag(tag, content, item_container.dom_attributes)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def list_content(item_container)
|
31
|
+
item_container.items.map { |item|
|
32
|
+
li_options = item.html_options.except(:link)
|
15
33
|
li_content = tag_for(item)
|
16
34
|
if include_sub_navigation?(item)
|
17
35
|
li_content << render_sub_navigation_for(item)
|
18
36
|
end
|
19
|
-
|
20
|
-
|
21
|
-
if skip_if_empty? && item_container.empty?
|
22
|
-
''
|
23
|
-
else
|
24
|
-
content_tag((options[:ordered] ? :ol : :ul), list_content, item_container.dom_attributes)
|
25
|
-
end
|
37
|
+
content_tag(:li, li_content, li_options)
|
38
|
+
}.join
|
26
39
|
end
|
27
40
|
end
|
28
41
|
end
|
@@ -1,26 +1,21 @@
|
|
1
1
|
module SimpleNavigation
|
2
2
|
module Renderer
|
3
|
-
|
4
|
-
#
|
5
|
-
#
|
3
|
+
# Renders the 'chain' of selected navigation items as simple text items,
|
4
|
+
# joined with an optional separator (similar to breadcrumbs, but without
|
5
|
+
# markup).
|
6
6
|
class Text < SimpleNavigation::Renderer::Base
|
7
|
-
|
8
7
|
def render(item_container)
|
9
|
-
list(item_container).compact.join(options[:join_with] ||
|
8
|
+
list(item_container).compact.join(options[:join_with] || ' ')
|
10
9
|
end
|
11
10
|
|
12
11
|
private
|
13
12
|
|
14
13
|
def list(item_container)
|
15
|
-
item_container.items.
|
16
|
-
|
17
|
-
|
18
|
-
else
|
19
|
-
array
|
20
|
-
end
|
14
|
+
item_container.items.keep_if(&:selected?).map do |item|
|
15
|
+
[item.name(apply_generator: false)] +
|
16
|
+
(include_sub_navigation?(item) ? list(item.sub_navigation) : [])
|
21
17
|
end
|
22
18
|
end
|
23
|
-
|
24
19
|
end
|
25
20
|
end
|
26
21
|
end
|
@@ -2,19 +2,72 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
module SimpleNavigation
|
4
4
|
describe ItemContainer do
|
5
|
-
|
5
|
+
subject(:item_container) { ItemContainer.new }
|
6
6
|
|
7
|
-
|
8
|
-
it '
|
9
|
-
|
10
|
-
|
7
|
+
shared_examples 'adding the item to the list' do
|
8
|
+
it 'adds the item to the list' do
|
9
|
+
Item.stub(:new).and_return(item)
|
10
|
+
item_container.item(*args)
|
11
|
+
expect(item_container.items).to include(item)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
shared_examples 'not adding the item to the list' do
|
16
|
+
it "doesn't add the item to the list" do
|
17
|
+
Item.stub(:new).and_return(item)
|
18
|
+
item_container.item(*args)
|
19
|
+
expect(item_container.items).not_to include(item)
|
11
20
|
end
|
21
|
+
end
|
12
22
|
|
13
|
-
|
23
|
+
describe '#initialize' do
|
24
|
+
it 'sets an empty items array' do
|
14
25
|
expect(item_container.items).to be_empty
|
15
26
|
end
|
16
27
|
end
|
17
28
|
|
29
|
+
describe '#dom_attributes' do
|
30
|
+
let(:dom_attributes) {{ id: 'test_id', class: 'test_class' }}
|
31
|
+
|
32
|
+
before { item_container.dom_attributes = dom_attributes }
|
33
|
+
|
34
|
+
it "returns the container's dom_attributes" do
|
35
|
+
expect(item_container.dom_attributes).to eq dom_attributes
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'when the dom_attributes do not contain any id or class' do
|
39
|
+
let(:dom_attributes) {{ test: 'test' }}
|
40
|
+
|
41
|
+
context "and the container hasn't any dom_id" do
|
42
|
+
it "returns the contaier's dom_attributes without any id" do
|
43
|
+
expect(item_container.dom_attributes).not_to include(:id)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'and the container has a dom_id' do
|
48
|
+
before { item_container.dom_id = 'test_id' }
|
49
|
+
|
50
|
+
it "returns the contaier's dom_attributes including the #dom_id" do
|
51
|
+
expect(item_container.dom_attributes).to include(id: 'test_id')
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context "and the container hasn't any dom_class" do
|
56
|
+
it "returns the contaier's dom_attributes without any class" do
|
57
|
+
expect(item_container.dom_attributes).not_to include(:class)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'and the container has a dom_class' do
|
62
|
+
before { item_container.dom_class = 'test_class' }
|
63
|
+
|
64
|
+
it "returns the contaier's dom_attributes including the #dom_class" do
|
65
|
+
expect(item_container.dom_attributes).to include(class: 'test_class')
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
18
71
|
describe '#items=' do
|
19
72
|
let(:item) { double(:item) }
|
20
73
|
let(:items) { [item] }
|
@@ -31,23 +84,13 @@ module SimpleNavigation
|
|
31
84
|
end
|
32
85
|
|
33
86
|
context 'when item should be added' do
|
34
|
-
let(:
|
87
|
+
let(:wrapped_item) { double(:wrapped_item).as_null_object }
|
35
88
|
|
36
|
-
before
|
37
|
-
item_container.stub(should_add_item?: true)
|
38
|
-
item_adapter.stub(to_simple_navigation_item: simple_navigation_item)
|
39
|
-
end
|
89
|
+
before { ItemAdapter.stub(:new).with(item).and_return(wrapped_item) }
|
40
90
|
|
41
|
-
it 'converts
|
42
|
-
expect(item_adapter).to receive(:to_simple_navigation_item)
|
43
|
-
.with(item_container)
|
44
|
-
item_container.items = items
|
45
|
-
end
|
46
|
-
|
47
|
-
it 'adds the item to the items-collection' do
|
48
|
-
expect(item_container.items).to receive(:<<)
|
49
|
-
.with(simple_navigation_item)
|
91
|
+
it 'converts item to an Item and adds it to the items collection' do
|
50
92
|
item_container.items = items
|
93
|
+
expect(item_container.items).to include(wrapped_item)
|
51
94
|
end
|
52
95
|
end
|
53
96
|
|
@@ -177,65 +220,54 @@ module SimpleNavigation
|
|
177
220
|
end
|
178
221
|
|
179
222
|
describe '#item' do
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
before { item_container.stub(:should_add_item?).and_return(true) }
|
184
|
-
|
185
|
-
context 'when a block is given' do
|
186
|
-
let(:sub_container) { double(:sub_container) }
|
187
|
-
let(:block) { proc{} }
|
188
|
-
|
189
|
-
before { ItemContainer.stub(:new).with(2).and_return(sub_container) }
|
223
|
+
let(:options) { Hash.new }
|
224
|
+
let(:item) { double(:item) }
|
190
225
|
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
}.to yield_with_args(sub_container)
|
195
|
-
end
|
226
|
+
context 'when a block is given' do
|
227
|
+
let(:block) { proc{} }
|
228
|
+
let(:sub_container) { double(:sub_container) }
|
196
229
|
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
item_container.item('key', 'name', 'url', options, &block)
|
202
|
-
end
|
230
|
+
it 'yields a new ItemContainer' do
|
231
|
+
Item.any_instance
|
232
|
+
.stub(:sub_navigation)
|
233
|
+
.and_return(sub_container)
|
203
234
|
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
end
|
235
|
+
expect{ |blk|
|
236
|
+
item_container.item('key', 'name', 'url', options, &blk)
|
237
|
+
}.to yield_with_args(sub_container)
|
208
238
|
end
|
209
239
|
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
240
|
+
it "creates a new Item with the given params and block" do
|
241
|
+
Item.stub(:new)
|
242
|
+
.with(item_container, 'key', 'name', 'url', options, nil, &block)
|
243
|
+
.and_return(item)
|
244
|
+
item_container.item('key', 'name', 'url', options, &block)
|
245
|
+
expect(item_container.items).to include(item)
|
246
|
+
end
|
216
247
|
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
end
|
248
|
+
it 'adds the created item to the list of items' do
|
249
|
+
item_container.item('key', 'name', 'url', options) {}
|
250
|
+
expect(item_container.items).not_to include(item)
|
221
251
|
end
|
222
252
|
end
|
223
253
|
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
254
|
+
context 'when no block is given' do
|
255
|
+
it 'creates a new Item with the given params and no sub navigation' do
|
256
|
+
Item.stub(:new)
|
257
|
+
.with(item_container, 'key', 'name', 'url', options, nil)
|
258
|
+
.and_return(item)
|
259
|
+
item_container.item('key', 'name', 'url', options)
|
260
|
+
expect(item_container.items).to include(item)
|
230
261
|
end
|
231
262
|
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
end
|
263
|
+
it 'adds the created item to the list of items' do
|
264
|
+
Item.stub(:new).and_return(item)
|
265
|
+
item_container.item('key', 'name', 'url', options) {}
|
266
|
+
expect(item_container.items).to include(item)
|
237
267
|
end
|
268
|
+
end
|
238
269
|
|
270
|
+
describe 'Optional url and optional options' do
|
239
271
|
context 'when item specifed without url or options' do
|
240
272
|
it_behaves_like 'adding the item to the list' do
|
241
273
|
let(:args) { ['key', 'name'] }
|
@@ -302,7 +334,7 @@ module SimpleNavigation
|
|
302
334
|
context 'and it evals to true' do
|
303
335
|
let(:condition) { true }
|
304
336
|
|
305
|
-
it 'creates a new
|
337
|
+
it 'creates a new Item' do
|
306
338
|
expect(Item).to receive(:new)
|
307
339
|
item_container.item('key', 'name', 'url', options)
|
308
340
|
end
|
@@ -311,7 +343,7 @@ module SimpleNavigation
|
|
311
343
|
context 'and it evals to false' do
|
312
344
|
let(:condition) { false }
|
313
345
|
|
314
|
-
it "doesn't create a new
|
346
|
+
it "doesn't create a new Item" do
|
315
347
|
expect(Item).not_to receive(:new)
|
316
348
|
item_container.item('key', 'name', 'url', options)
|
317
349
|
end
|
@@ -429,6 +461,24 @@ module SimpleNavigation
|
|
429
461
|
end
|
430
462
|
end
|
431
463
|
|
464
|
+
describe '#renderer' do
|
465
|
+
context 'when no renderer is set explicitly' do
|
466
|
+
it 'returns globally-configured renderer' do
|
467
|
+
expect(item_container.renderer).to be Configuration.instance.renderer
|
468
|
+
end
|
469
|
+
end
|
470
|
+
|
471
|
+
context 'when a renderer is set explicitly' do
|
472
|
+
let(:renderer) { double(:renderer) }
|
473
|
+
|
474
|
+
before { item_container.renderer = renderer }
|
475
|
+
|
476
|
+
it 'returns the specified renderer' do
|
477
|
+
expect(item_container.renderer).to be renderer
|
478
|
+
end
|
479
|
+
end
|
480
|
+
end
|
481
|
+
|
432
482
|
describe '#level_for_item' do
|
433
483
|
before(:each) do
|
434
484
|
item_container.item(:p1, 'p1', 'p1')
|
@@ -45,7 +45,7 @@ describe SimpleNavigation do
|
|
45
45
|
before { subject.config_file_paths = ['my_config_file_path'] }
|
46
46
|
|
47
47
|
context 'and the requested config file exists' do
|
48
|
-
before { File.stub(
|
48
|
+
before { File.stub(exist?: true) }
|
49
49
|
|
50
50
|
it 'returns the path to the config_file' do
|
51
51
|
expect(subject.config_file).to eq 'my_config_file_path/navigation.rb'
|
@@ -53,7 +53,7 @@ describe SimpleNavigation do
|
|
53
53
|
end
|
54
54
|
|
55
55
|
context 'and the requested config file does not exist' do
|
56
|
-
before { File.stub(
|
56
|
+
before { File.stub(exist?: false) }
|
57
57
|
|
58
58
|
it 'returns nil' do
|
59
59
|
expect(subject.config_file).to be_nil
|
@@ -65,7 +65,7 @@ describe SimpleNavigation do
|
|
65
65
|
before { subject.config_file_paths = ['first_path', 'second_path'] }
|
66
66
|
|
67
67
|
context 'and the requested config file exists' do
|
68
|
-
before { File.stub(
|
68
|
+
before { File.stub(exist?: true) }
|
69
69
|
|
70
70
|
it 'returns the path to the first matching config_file' do
|
71
71
|
expect(subject.config_file).to eq 'first_path/navigation.rb'
|
@@ -73,7 +73,7 @@ describe SimpleNavigation do
|
|
73
73
|
end
|
74
74
|
|
75
75
|
context 'and the requested config file does not exist' do
|
76
|
-
before { File.stub(
|
76
|
+
before { File.stub(exist?: false) }
|
77
77
|
|
78
78
|
it 'returns nil' do
|
79
79
|
expect(subject.config_file).to be_nil
|
@@ -196,7 +196,7 @@ describe SimpleNavigation do
|
|
196
196
|
before do
|
197
197
|
subject.config_file_path = 'path_to_config'
|
198
198
|
IO.stub(:read).and_return('file_content')
|
199
|
-
File.stub(
|
199
|
+
File.stub(exist?: true)
|
200
200
|
end
|
201
201
|
|
202
202
|
after { subject.config_files = {} }
|
@@ -286,4 +286,15 @@ describe SimpleNavigation do
|
|
286
286
|
it_behaves_like 'loading the right adapter', :padrino, :Padrino
|
287
287
|
it_behaves_like 'loading the right adapter', :sinatra, :Sinatra
|
288
288
|
end
|
289
|
+
|
290
|
+
describe '.init_adapter_from' do
|
291
|
+
let(:adapter) { double(:adapter) }
|
292
|
+
let(:adapter_class) { double(:adapter_class, new: adapter) }
|
293
|
+
|
294
|
+
it 'sets the adapter to a new instance of adapter_class' do
|
295
|
+
subject.adapter_class = adapter_class
|
296
|
+
subject.init_adapter_from(:default)
|
297
|
+
expect(subject.adapter).to be adapter
|
298
|
+
end
|
299
|
+
end
|
289
300
|
end
|