krasivotokak-simple-navigation 1.4.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.
- data/.gitignore +3 -0
- data/CHANGELOG +38 -0
- data/README +19 -0
- data/Rakefile +74 -0
- data/VERSION.yml +4 -0
- data/generators/navigation_config/USAGE +1 -0
- data/generators/navigation_config/navigation_config_generator.rb +8 -0
- data/generators/navigation_config/templates/config/navigation.rb +48 -0
- data/init.rb +1 -0
- data/install.rb +5 -0
- data/lib/simple_navigation.rb +40 -0
- data/lib/simple_navigation/configuration.rb +60 -0
- data/lib/simple_navigation/controller_methods.rb +75 -0
- data/lib/simple_navigation/helpers.rb +65 -0
- data/lib/simple_navigation/item.rb +48 -0
- data/lib/simple_navigation/item_container.rb +69 -0
- data/lib/simple_navigation/renderer/base.rb +44 -0
- data/lib/simple_navigation/renderer/list.rb +30 -0
- data/rails/init.rb +3 -0
- data/simple-navigation.gemspec +78 -0
- data/spec/lib/simple_navigation/configuration_spec.rb +101 -0
- data/spec/lib/simple_navigation/controller_methods_spec.rb +77 -0
- data/spec/lib/simple_navigation/helpers_spec.rb +125 -0
- data/spec/lib/simple_navigation/item_container_spec.rb +174 -0
- data/spec/lib/simple_navigation/item_spec.rb +148 -0
- data/spec/lib/simple_navigation/renderer/base_spec.rb +56 -0
- data/spec/lib/simple_navigation/renderer/list_spec.rb +118 -0
- data/spec/lib/simple_navigation_spec.rb +140 -0
- data/spec/spec_helper.rb +25 -0
- data/uninstall.rb +1 -0
- metadata +93 -0
@@ -0,0 +1,48 @@
|
|
1
|
+
module SimpleNavigation
|
2
|
+
|
3
|
+
# Represents an item in your navigation. Gets generated by the item method in the config-file.
|
4
|
+
class Item
|
5
|
+
attr_reader :key, :name, :url, :sub_navigation, :method
|
6
|
+
attr_writer :html_options
|
7
|
+
|
8
|
+
# see ItemContainer#item
|
9
|
+
def initialize(key, name, url, options, sub_nav_block)
|
10
|
+
@key = key
|
11
|
+
@method = options.delete(:method)
|
12
|
+
@name = name
|
13
|
+
@url = url
|
14
|
+
@html_options = options
|
15
|
+
if sub_nav_block
|
16
|
+
@sub_navigation = ItemContainer.new
|
17
|
+
sub_nav_block.call @sub_navigation
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns true if this navigation item should be rendered as 'selected' for the specified current_navigation.
|
22
|
+
def selected?(current_navigation)
|
23
|
+
key == current_navigation
|
24
|
+
end
|
25
|
+
|
26
|
+
# Returns the html-options hash for the item, i.e. the options specified for this item in the config-file.
|
27
|
+
# It also adds the 'selected' class to the list of classes if necessary.
|
28
|
+
def html_options(current_navigation)
|
29
|
+
default_class = self.autogenerate_item_ids? ? key.to_s : nil
|
30
|
+
@html_options
|
31
|
+
@html_options[:class] = [default_class, @html_options[:class], self.selected_class(current_navigation)].flatten.compact.uniq.join(' ')
|
32
|
+
@html_options.delete(:class) if @html_options[:class].blank?
|
33
|
+
@html_options
|
34
|
+
end
|
35
|
+
|
36
|
+
def selected_class(current_navigation) #:nodoc:
|
37
|
+
selected?(current_navigation) ? SimpleNavigation.config.selected_class : nil
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
protected
|
42
|
+
|
43
|
+
def autogenerate_item_ids?
|
44
|
+
SimpleNavigation.config.autogenerate_item_ids
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module SimpleNavigation
|
2
|
+
|
3
|
+
# Holds the Items for a navigation 'level' (either the primary_navigation or a sub_navigation).
|
4
|
+
class ItemContainer
|
5
|
+
|
6
|
+
attr_reader :items
|
7
|
+
attr_accessor :renderer, :dom_id, :dom_class
|
8
|
+
|
9
|
+
def initialize #:nodoc:
|
10
|
+
@items = []
|
11
|
+
@renderer = Configuration.instance.renderer
|
12
|
+
end
|
13
|
+
|
14
|
+
# Creates a new navigation item.
|
15
|
+
#
|
16
|
+
# The <tt>key</tt> is a symbol which uniquely defines your navigation item in the scope of the primary_navigation or the sub_navigation.
|
17
|
+
#
|
18
|
+
# The <tt>name</tt> will be displayed in the rendered navigation. This can also be a call to your I18n-framework.
|
19
|
+
#
|
20
|
+
# The <tt>url</tt> is the address that the generated item points to. You can also use url_helpers (named routes, restful routes helper, url_for etc.)
|
21
|
+
#
|
22
|
+
# The <tt>options</tt> can be used to specify the following things:
|
23
|
+
# * <tt>html_attributes</tt> - will be included in the rendered navigation item (e.g. id, class etc.)
|
24
|
+
# * <tt>:if</tt> - Specifies a proc to call to determine if the item should
|
25
|
+
# be rendered (e.g. <tt>:if => Proc.new { current_user.admin? }</tt>). The
|
26
|
+
# proc should evaluate to a true or false value and is evaluated in the context of the view.
|
27
|
+
# * <tt>:unless</tt> - Specifies a proc to call to determine if the item should not
|
28
|
+
# be rendered (e.g. <tt>:unless => Proc.new { current_user.admin? }</tt>). The
|
29
|
+
# proc should evaluate to a true or false value and is evaluated in the context of the view.
|
30
|
+
#
|
31
|
+
# The <tt>block</tt> - if specified - will hold the item's sub_navigation.
|
32
|
+
def item(key, name, url, options={}, &block)
|
33
|
+
(@items << Item.new(key, name, url, options, block)) if should_add_item?(options)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Returns the Item with the specified key, nil otherwise.
|
37
|
+
def [](navi_key)
|
38
|
+
items.find {|i| i.key == navi_key}
|
39
|
+
end
|
40
|
+
|
41
|
+
# Renders the items in this ItemContainer using the configured renderer.
|
42
|
+
#
|
43
|
+
# Set <tt>include_sub_navigation</tt> to true if you want to nest the sub_navigation into the active primary_navigation
|
44
|
+
def render(current_navigation, include_sub_navigation=false, current_sub_navigation=nil)
|
45
|
+
self.renderer.new(current_navigation, current_sub_navigation).render(self, include_sub_navigation)
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
# partially borrowed from ActionSupport::Callbacks
|
51
|
+
def should_add_item?(options) #:nodoc:
|
52
|
+
[options.delete(:if)].flatten.compact.all? { |m| evaluate_method(m) } &&
|
53
|
+
![options.delete(:unless)].flatten.compact.any? { |m| evaluate_method(m) }
|
54
|
+
end
|
55
|
+
|
56
|
+
# partially borrowed from ActionSupport::Callbacks
|
57
|
+
def evaluate_method(method) #:nodoc:
|
58
|
+
case method
|
59
|
+
when Proc, Method
|
60
|
+
method.call
|
61
|
+
else
|
62
|
+
raise ArgumentError, ":if or :unless must be procs or lambdas"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module SimpleNavigation
|
2
|
+
module Renderer
|
3
|
+
|
4
|
+
# This is the base class for all renderers.
|
5
|
+
#
|
6
|
+
# A renderer is responsible for rendering an ItemContainer (primary or a sub_navigation) and its containing items to HTML.
|
7
|
+
# It must be initialized with the current_navigation for the rendered ItemContainer and
|
8
|
+
# optionally with the current_sub_navigation (if the sub_navigation will be nested).
|
9
|
+
class Base
|
10
|
+
include ActionView::Helpers::UrlHelper
|
11
|
+
include ActionView::Helpers::TagHelper
|
12
|
+
|
13
|
+
attr_reader :current_navigation, :current_sub_navigation, :controller
|
14
|
+
|
15
|
+
class << self
|
16
|
+
|
17
|
+
# Delegates method calls to the controller.
|
18
|
+
def controller_method(*methods)
|
19
|
+
methods.each do |method|
|
20
|
+
delegate method, :to => :controller
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
controller_method :form_authenticity_token, :protect_against_forgery?, :request_forgery_protection_token
|
27
|
+
|
28
|
+
def initialize(current_navigation, current_sub_navigation=nil) #:nodoc:
|
29
|
+
@current_navigation = current_navigation
|
30
|
+
@current_sub_navigation = current_sub_navigation
|
31
|
+
@controller = SimpleNavigation.controller
|
32
|
+
end
|
33
|
+
|
34
|
+
# Renders the specified ItemContainer to HTML.
|
35
|
+
#
|
36
|
+
# If <tt>include_sub_navigation</tt> is set to true, the renderer should nest the sub_navigation for the active navigation
|
37
|
+
# inside that navigation item.
|
38
|
+
def render(item_container, include_sub_navigation=false)
|
39
|
+
raise 'subclass responsibility'
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module SimpleNavigation
|
2
|
+
module Renderer
|
3
|
+
|
4
|
+
# Renders an ItemContainer as a <ul> element and its containing items as <li> elements.
|
5
|
+
# It adds the 'selected' class to li element AND the link inside the li element that is currently active.
|
6
|
+
# If the sub navigation should be included, it renders another <ul> containing the sub navigation inside the active <li> element.
|
7
|
+
#
|
8
|
+
# By default, the renderer sets the item's key as dom_id for the rendered <li> element. The id can be explicitely specified by setting
|
9
|
+
# the id in the html-options of the 'item' method in the config/navigation.rb file.
|
10
|
+
class List < Renderer::Base
|
11
|
+
|
12
|
+
def render(item_container, include_sub_navigation=false)
|
13
|
+
list_content = item_container.items.inject([]) do |list, item|
|
14
|
+
html_options = item.html_options(current_navigation)
|
15
|
+
li_content = link_to(item.name, item.url, :class => item.selected_class(current_navigation), :method => item.method)
|
16
|
+
if item.sub_navigation
|
17
|
+
if SimpleNavigation.config.render_all_levels
|
18
|
+
li_content << (item.sub_navigation.render(current_sub_navigation))
|
19
|
+
else
|
20
|
+
li_content << (item.sub_navigation.render(current_sub_navigation)) if include_sub_navigation && item.selected?(current_navigation)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
list << content_tag(:li, li_content, html_options)
|
24
|
+
end
|
25
|
+
content_tag(:ul, list_content.join, {:class => %(#{item_container.dom_class} #{item_container.dom_id})})
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/rails/init.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{simple-navigation}
|
8
|
+
s.version = "1.4.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Andi Schacke", "Alexander Semyonov"]
|
12
|
+
s.date = %q{2009-08-31}
|
13
|
+
s.description = %q{Simple Navigation is a ruby library for creating a navigation (optionally with sub navigation) for your rails app.}
|
14
|
+
s.email = %q{andreas.schacke@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"README"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
".gitignore",
|
20
|
+
"CHANGELOG",
|
21
|
+
"CHANGELOG",
|
22
|
+
"README",
|
23
|
+
"Rakefile",
|
24
|
+
"VERSION.yml",
|
25
|
+
"generators/navigation_config/USAGE",
|
26
|
+
"generators/navigation_config/navigation_config_generator.rb",
|
27
|
+
"generators/navigation_config/templates/config/navigation.rb",
|
28
|
+
"init.rb",
|
29
|
+
"install.rb",
|
30
|
+
"lib/simple_navigation.rb",
|
31
|
+
"lib/simple_navigation/configuration.rb",
|
32
|
+
"lib/simple_navigation/controller_methods.rb",
|
33
|
+
"lib/simple_navigation/helpers.rb",
|
34
|
+
"lib/simple_navigation/item.rb",
|
35
|
+
"lib/simple_navigation/item_container.rb",
|
36
|
+
"lib/simple_navigation/renderer/base.rb",
|
37
|
+
"lib/simple_navigation/renderer/list.rb",
|
38
|
+
"rails/init.rb",
|
39
|
+
"simple-navigation.gemspec",
|
40
|
+
"spec/lib/simple_navigation/configuration_spec.rb",
|
41
|
+
"spec/lib/simple_navigation/controller_methods_spec.rb",
|
42
|
+
"spec/lib/simple_navigation/helpers_spec.rb",
|
43
|
+
"spec/lib/simple_navigation/item_container_spec.rb",
|
44
|
+
"spec/lib/simple_navigation/item_spec.rb",
|
45
|
+
"spec/lib/simple_navigation/renderer/base_spec.rb",
|
46
|
+
"spec/lib/simple_navigation/renderer/list_spec.rb",
|
47
|
+
"spec/lib/simple_navigation_spec.rb",
|
48
|
+
"spec/spec_helper.rb",
|
49
|
+
"uninstall.rb"
|
50
|
+
]
|
51
|
+
s.homepage = %q{http://github.com/andi/simple-navigation}
|
52
|
+
s.rdoc_options = ["--inline-source", "--charset=UTF-8"]
|
53
|
+
s.require_paths = ["lib"]
|
54
|
+
s.rubyforge_project = %q{andi}
|
55
|
+
s.rubygems_version = %q{1.3.5}
|
56
|
+
s.summary = %q{Simple Navigation is a ruby library for creating a navigation (optionally with sub navigation) for your rails app.}
|
57
|
+
s.test_files = [
|
58
|
+
"spec/lib/simple_navigation/item_spec.rb",
|
59
|
+
"spec/lib/simple_navigation/controller_methods_spec.rb",
|
60
|
+
"spec/lib/simple_navigation/item_container_spec.rb",
|
61
|
+
"spec/lib/simple_navigation/helpers_spec.rb",
|
62
|
+
"spec/lib/simple_navigation/configuration_spec.rb",
|
63
|
+
"spec/lib/simple_navigation/renderer/list_spec.rb",
|
64
|
+
"spec/lib/simple_navigation/renderer/base_spec.rb",
|
65
|
+
"spec/lib/simple_navigation_spec.rb",
|
66
|
+
"spec/spec_helper.rb"
|
67
|
+
]
|
68
|
+
|
69
|
+
if s.respond_to? :specification_version then
|
70
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
71
|
+
s.specification_version = 3
|
72
|
+
|
73
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
74
|
+
else
|
75
|
+
end
|
76
|
+
else
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
describe SimpleNavigation::Configuration do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@config = SimpleNavigation::Configuration.instance
|
7
|
+
end
|
8
|
+
|
9
|
+
describe 'self.run' do
|
10
|
+
it "should yield the singleton Configuration object" do
|
11
|
+
SimpleNavigation::Configuration.run do |c|
|
12
|
+
c.should == @config
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe 'self.eval_config' do
|
18
|
+
before(:each) do
|
19
|
+
@context = mock(:context)
|
20
|
+
@context.stub!(:instance_eval)
|
21
|
+
@config_files = {:default => 'default', :my_context => 'my_context'}
|
22
|
+
SimpleNavigation.stub!(:config_files).and_return(@config_files)
|
23
|
+
end
|
24
|
+
context "with default navigation context" do
|
25
|
+
it "should instance_eval the default config_file-string inside the context" do
|
26
|
+
@context.should_receive(:instance_eval).with('default')
|
27
|
+
SimpleNavigation::Configuration.eval_config(@context)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
context 'with non default navigation context' do
|
31
|
+
it "should instance_eval the specified config_file-string inside the context" do
|
32
|
+
@context.should_receive(:instance_eval).with('my_context')
|
33
|
+
SimpleNavigation::Configuration.eval_config(@context, :my_context)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
it "should set the controller" do
|
37
|
+
@controller = stub(:controller)
|
38
|
+
SimpleNavigation::Configuration.should_receive(:extract_controller_from).with(@context).and_return(@controller)
|
39
|
+
SimpleNavigation.should_receive(:controller=).with(@controller)
|
40
|
+
SimpleNavigation::Configuration.eval_config(@context)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe 'self.extract_controller_from' do
|
45
|
+
before(:each) do
|
46
|
+
@nav_context = stub(:nav_context)
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'object responds to controller' do
|
50
|
+
before(:each) do
|
51
|
+
@controller = stub(:controller)
|
52
|
+
@nav_context.stub!(:controller).and_return(@controller)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should return the controller" do
|
56
|
+
SimpleNavigation::Configuration.extract_controller_from(@nav_context).should == @controller
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'object does not respond to controller' do
|
62
|
+
it "should return the nav_context" do
|
63
|
+
SimpleNavigation::Configuration.extract_controller_from(@nav_context).should == @nav_context
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe 'initialize' do
|
69
|
+
it "should set the List-Renderer as default upon initialize" do
|
70
|
+
@config.renderer.should == SimpleNavigation::Renderer::List
|
71
|
+
end
|
72
|
+
it "should set the selected_class to 'selected' as default" do
|
73
|
+
@config.selected_class.should == 'selected'
|
74
|
+
end
|
75
|
+
it "should set render_all_levels to false as default" do
|
76
|
+
@config.render_all_levels.should be_false
|
77
|
+
end
|
78
|
+
it "should set autogenerate_item_ids to true as default" do
|
79
|
+
@config.autogenerate_item_ids.should be_true
|
80
|
+
end
|
81
|
+
end
|
82
|
+
describe 'items' do
|
83
|
+
before(:each) do
|
84
|
+
@container = stub(:items_container)
|
85
|
+
SimpleNavigation::ItemContainer.stub!(:new).and_return(@container)
|
86
|
+
end
|
87
|
+
it "should should yield an new ItemContainer" do
|
88
|
+
@config.items do |container|
|
89
|
+
container.should == @container
|
90
|
+
end
|
91
|
+
end
|
92
|
+
it "should assign the ItemContainer to an instance-var" do
|
93
|
+
@config.items {}
|
94
|
+
@config.primary_navigation.should == @container
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
ActionController::Base.send(:include, SimpleNavigation::ControllerMethods)
|
4
|
+
|
5
|
+
describe SimpleNavigation::ControllerMethods do
|
6
|
+
|
7
|
+
def stub_loading_config
|
8
|
+
SimpleNavigation::Configuration.stub!(:load)
|
9
|
+
end
|
10
|
+
|
11
|
+
before(:each) do
|
12
|
+
stub_loading_config
|
13
|
+
class ApplicationController < ActionController::Base
|
14
|
+
end
|
15
|
+
@controller = ApplicationController.new
|
16
|
+
end
|
17
|
+
|
18
|
+
describe 'when being included' do
|
19
|
+
it "should extend the ClassMethods" do
|
20
|
+
@controller.class.should respond_to(:navigation)
|
21
|
+
end
|
22
|
+
it "should include the InstanceMethods" do
|
23
|
+
@controller.should respond_to(:current_navigation)
|
24
|
+
end
|
25
|
+
it "should install the Helpers Module" do
|
26
|
+
[:render_navigation, :render_primary_navigation, :render_sub_navigation].each do |m|
|
27
|
+
@controller.master_helper_module.instance_methods.map(&:to_s).should include(m.to_s)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'class_methods' do
|
33
|
+
|
34
|
+
describe 'navigation' do
|
35
|
+
|
36
|
+
def call_navigation(key1, key2=nil)
|
37
|
+
@controller.class_eval do
|
38
|
+
navigation key1, key2
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should not have an instance-method 'set_navigation if navigation-method has not been called" do
|
43
|
+
@controller.respond_to?(:set_navigation).should be_false
|
44
|
+
end
|
45
|
+
it 'should create an instance-method "set_navigation" when being called' do
|
46
|
+
call_navigation(:key)
|
47
|
+
@controller.respond_to?(:set_navigation).should be_true
|
48
|
+
end
|
49
|
+
it 'the created method should call current_navigation with the specified keys' do
|
50
|
+
call_navigation(:primary, :secondary)
|
51
|
+
@controller.should_receive(:current_navigation).with(:primary, :secondary)
|
52
|
+
@controller.set_navigation
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
describe 'instance_methods' do
|
59
|
+
|
60
|
+
describe 'current_navigation' do
|
61
|
+
it "should set the current_primary_navigation as specified" do
|
62
|
+
@controller.current_navigation(:first)
|
63
|
+
@controller.instance_variable_get(:@current_primary_navigation).should == :first
|
64
|
+
end
|
65
|
+
it "should set the current_secondary_navigation as specified" do
|
66
|
+
@controller.current_navigation(:first, :second)
|
67
|
+
@controller.instance_variable_get(:@current_secondary_navigation).should == :second
|
68
|
+
end
|
69
|
+
it "should set the current_secondary_navigation to nil if no secondary is specified" do
|
70
|
+
@controller.current_navigation(:first)
|
71
|
+
@controller.instance_variable_get(:@current_secondary_navigation).should be_nil
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|