simple-navigation 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ *1.1.1
2
+
3
+ * Change plugin into a GemPlugin
data/README ADDED
@@ -0,0 +1,19 @@
1
+
2
+ == Simple Navigation
3
+
4
+ Simple Navigation is a plugin for creating a navigation (optionally with sub navigation) for your rails app.
5
+
6
+ Source code:
7
+ git://github.com/andi/simple-navigation.git
8
+
9
+ Documentation:
10
+ http://wiki.github.com/andi/simple-navigation
11
+
12
+ Online Demo:
13
+ http://simple-navigation-demo.andischacke.com
14
+
15
+ Discussion Group for Feedback and Questions
16
+ http://groups.google.com/group/simple-navigation
17
+
18
+ Copyright (c) 2009 Andi Schacke, released under the MIT license
19
+
@@ -0,0 +1,65 @@
1
+ require 'rake'
2
+ require 'spec/rake/spectask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run specs.'
6
+ task :default => :spec
7
+
8
+ desc 'Run the specs'
9
+ Spec::Rake::SpecTask.new(:spec) do |t|
10
+ t.spec_opts = ['--colour --format progress --loadby mtime --reverse']
11
+ t.spec_files = FileList['spec/**/*_spec.rb']
12
+ end
13
+
14
+ desc 'Generate documentation for the simple_navigation plugin.'
15
+ Rake::RDocTask.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'SimpleNavigation'
18
+ rdoc.options << '--line-numbers' << '--inline-source'
19
+ rdoc.rdoc_files.include('README')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+ begin
24
+ require 'jeweler'
25
+ Jeweler::Tasks.new do |gemspec|
26
+ gemspec.name = "simple-navigation"
27
+ gemspec.summary = "Simple Navigation is a ruby library for creating a navigation (optionally with sub navigation) for your rails app."
28
+ gemspec.email = "andreas.schacke@gmail.com"
29
+ gemspec.homepage = "http://github.com/andi/simple-navigation"
30
+ gemspec.description = "Simple Navigation is a ruby library for creating a navigation (optionally with sub navigation) for your rails app."
31
+ gemspec.authors = ["Andi Schacke"]
32
+ gemspec.rdoc_options = ["--inline-source", "--charset=UTF-8"]
33
+ gemspec.files += ["CHANGELOG"]
34
+ gemspec.rubyforge_project = 'andi'
35
+ end
36
+ rescue LoadError
37
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
38
+ end
39
+
40
+ begin
41
+ require 'rake/contrib/sshpublisher'
42
+ namespace :rubyforge do
43
+
44
+ desc "Release gem and RDoc documentation to RubyForge"
45
+ task :release => ["rubyforge:release:gem", "rubyforge:release:docs"]
46
+
47
+ namespace :release do
48
+ desc "Publish RDoc to RubyForge."
49
+ task :docs => [:rdoc] do
50
+ config = YAML.load(
51
+ File.read(File.expand_path('~/.rubyforge/user-config.yml'))
52
+ )
53
+
54
+ host = "#{config['username']}@rubyforge.org"
55
+ remote_dir = "/var/www/gforge-projects/simple-navigation/"
56
+ local_dir = 'rdoc'
57
+
58
+ Rake::SshDirPublisher.new(host, remote_dir, local_dir).upload
59
+ end
60
+ end
61
+ end
62
+ rescue LoadError
63
+ puts "Rake SshDirPublisher is unavailable or your rubyforge environment is not configured."
64
+ end
65
+
@@ -0,0 +1,4 @@
1
+ ---
2
+ :minor: 1
3
+ :patch: 1
4
+ :major: 1
@@ -0,0 +1 @@
1
+ Creates a template config file for the simple-navigation plugin. You will find the generated file in config/navigation.rb.
@@ -0,0 +1,8 @@
1
+ class NavigationConfigGenerator < Rails::Generator::Base
2
+ def manifest
3
+ record do |m|
4
+ m.file "config/navigation.rb", "config/navigation.rb"
5
+ m.readme "../../../README"
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,28 @@
1
+ # Configures your navigation
2
+ SimpleNavigation::Configuration.run do |navigation|
3
+ # Specify a custom renderer if needed.
4
+ # The default renderer is SimpleNavigation::Renderer::List which renders HTML lists.
5
+ # navigation.renderer = Your::Custom::Renderer
6
+
7
+ # Specify the class that will be applied to active navigation items. Defaults to 'selected'
8
+ # navigation.selected_class = 'your_selected_class'
9
+
10
+ # Define the primary navigation
11
+ navigation.items do |primary|
12
+ # Add an item to the primary navigation. The following params apply:
13
+ # key - a symbol which uniquely defines your navigation item in the scope of the primary_navigation
14
+ # name - will be displayed in the rendered navigation. This can also be a call to your I18n-framework.
15
+ # url - the address that the generated item links to. You can also use url_helpers (named routes, restful routes helper, url_for etc.)
16
+ # html_options - can be used to specify attributes that will be included in the rendered navigation item (e.g. id, class etc.)
17
+ #
18
+ primary.item :key_1, 'name', url, html_options
19
+
20
+ # Add an item which has a sub navigation (same params, but with block)
21
+ primary.item :key_2, 'name', url, html_options do |sub_nav|
22
+ # Add an item to the sub navigation (same params again)
23
+ sub_nav.item :key_2_1, 'name', url, html_options
24
+ end
25
+
26
+ end
27
+
28
+ end
@@ -0,0 +1,21 @@
1
+ # A plugin for generating a simple navigation. See README for resources on usage instructions.
2
+ module SimpleNavigation
3
+
4
+ mattr_accessor :config_file
5
+
6
+ # Reads the specified config_file and stores it for later evaluation.
7
+ def self.load_config(config_file)
8
+ self.config_file = IO.read(config_file)
9
+ end
10
+
11
+ # Returns the singleton instance of the SimpleNavigation::Configuration
12
+ def self.config
13
+ Configuration.instance
14
+ end
15
+
16
+ # Returns the ItemContainer that contains the items for the primary navigation
17
+ def self.primary_navigation
18
+ config.primary_navigation
19
+ end
20
+
21
+ end
@@ -0,0 +1,41 @@
1
+ require 'singleton'
2
+
3
+ module SimpleNavigation
4
+
5
+ # Responsible for evaluating and handling the config/navigation.rb file.
6
+ class Configuration
7
+ include Singleton
8
+
9
+ attr_accessor :renderer
10
+ attr_accessor :selected_class
11
+ attr_reader :primary_navigation
12
+
13
+ # Evals the config_file inside the specified context (usually a controller or view)
14
+ def self.eval_config(context)
15
+ context.instance_eval(SimpleNavigation.config_file)
16
+ end
17
+
18
+ # Starts processing the configuration
19
+ def self.run(&block)
20
+ block.call Configuration.instance
21
+ end
22
+
23
+ # Sets the config's default-settings
24
+ def initialize
25
+ @renderer = SimpleNavigation::Renderer::List
26
+ @selected_class = 'selected'
27
+ end
28
+
29
+ # Yields an SimpleNavigation::ItemContainer for adding navigation items
30
+ def items(&block)
31
+ @primary_navigation = ItemContainer.new
32
+ block.call @primary_navigation
33
+ end
34
+
35
+ # Returns true if the config_file has already been evaluated.
36
+ def loaded?
37
+ !@primary_navigation.nil?
38
+ end
39
+ end
40
+
41
+ end
@@ -0,0 +1,74 @@
1
+ #TODO: add :except and :only options to navigation method
2
+ module SimpleNavigation
3
+
4
+ # Adds methods for handling the current 'active' navigation to the controllers.
5
+ #
6
+ # On the controller class level, use the navigation method to set the active navigation for all actions in the controller.
7
+ #
8
+ # ==== Examples
9
+ # class AccountController << ActionController
10
+ # navigation :account
11
+ # ...
12
+ # end
13
+ #
14
+ # class AccountSettingsController << ActionController
15
+ # navigation :account, :settings
16
+ # ...
17
+ # end
18
+ #
19
+ # The first example sets the current_primary_navigation to :account for all actions. No active sub_navigation.
20
+ # The second example sets the current_primary_navigation to :account and the current_sub_navigation to :settings.
21
+ #
22
+ # On the controller instance level, use the current_navigation method to define the active navigation for a specific action.
23
+ # The navigation item that is set in current_navigation overrides the one defined on the controller class level (see navigation method).
24
+ #
25
+ # ==== Example
26
+ # class AccountController << ActionController
27
+ # navigation :account
28
+ #
29
+ # def your_special_action
30
+ # ...
31
+ # current_navigation :special
32
+ # end
33
+ # end
34
+ #
35
+ # This overrides :account as active navigation for your_special_action and sets it to :special.
36
+ #
37
+ # Note: The specified symbols must match the keys for your navigation items in your config/navigation.rb file.
38
+ module ControllerMethods
39
+ def self.included(base) #:nodoc:
40
+ base.class_eval do
41
+ extend ClassMethods
42
+ include InstanceMethods
43
+ helper SimpleNavigation::Helpers
44
+ end
45
+ end
46
+
47
+ module ClassMethods
48
+ # Sets the active navigation for all actions in this controller.
49
+ #
50
+ # The specified symbols must match the keys for your navigation items in your config/navigation.rb file.
51
+ def navigation(primary_navigation, sub_navigation=nil)
52
+ self.class_eval do
53
+ define_method :set_navigation do
54
+ current_navigation(primary_navigation, sub_navigation)
55
+ end
56
+ before_filter :set_navigation
57
+ end
58
+ end
59
+ end
60
+
61
+ module InstanceMethods
62
+
63
+ # Sets the active navigation. Call this method in any action to override the controller-wide active navigation
64
+ # specified by navigation.
65
+ #
66
+ # The specified symbols must match the keys for your navigation items in your config/navigation.rb file.
67
+ def current_navigation(primary_navigation, sub_navigation=nil)
68
+ @current_primary_navigation = primary_navigation
69
+ @current_secondary_navigation = sub_navigation
70
+ end
71
+ end
72
+
73
+ end
74
+ end
@@ -0,0 +1,51 @@
1
+ module SimpleNavigation
2
+
3
+ # View helpers to render the navigation.
4
+ #
5
+ # Use render_primary_navigation to render your primary navigation with the configured renderer.
6
+ # Use render_sub_navigation to render the sub navigation belonging to the active primary navigation.
7
+ # Use render_navigation to render the primary navigation with the corresponding sub navigation rendered inside primary navigation item which is active.
8
+ #
9
+ # ==== Examples (using Haml)
10
+ # #primary_navigation= render_primary_navigation
11
+ #
12
+ # #sub_navigation= render_sub_navigation
13
+ #
14
+ # #main_navigation= render_navigation
15
+ #
16
+ module Helpers
17
+
18
+ # Renders the navigation according to the specified <tt>level</tt>.
19
+ #
20
+ # The <tt>level</tt> defaults to :nested which renders the the sub_navigation for an active primary_navigation inside that active primary_navigation item.
21
+ #
22
+ # Other possible levels are
23
+ #
24
+ # :primary which only renders the primary_navigation (also see render_primary_navigation) and :secondary which only renders the sub_navigation (see render_sub_navigation).
25
+ def render_navigation(level = :nested)
26
+ SimpleNavigation::Configuration.eval_config(self) unless SimpleNavigation.config.loaded?
27
+ case level
28
+ when :primary:
29
+ SimpleNavigation.primary_navigation.render(@current_primary_navigation)
30
+ when :secondary:
31
+ primary = SimpleNavigation.primary_navigation[@current_primary_navigation]
32
+ primary.sub_navigation.render(@current_secondary_navigation) if primary && primary.sub_navigation
33
+ when :nested:
34
+ SimpleNavigation.primary_navigation.render(@current_primary_navigation, true, @current_secondary_navigation)
35
+ else
36
+ raise ArgumentError, "Invalid navigation level: #{level}"
37
+ end
38
+ end
39
+
40
+ # Renders the primary_navigation with the configured renderer. Calling render_navigation(:primary) has the same effect.
41
+ def render_primary_navigation
42
+ render_navigation(:primary)
43
+ end
44
+
45
+ # Renders the sub_navigation with the configured renderer. Calling render_navigation(:secondary) has the same effect.
46
+ def render_sub_navigation
47
+ render_navigation(:secondary)
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,40 @@
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
6
+
7
+ # see ItemContainer#item
8
+ def initialize(key, name, url, html_options, sub_nav_block)
9
+ @key = key
10
+ @name = name
11
+ @url = url
12
+ @html_options = html_options
13
+ if sub_nav_block
14
+ @sub_navigation = ItemContainer.new
15
+ sub_nav_block.call @sub_navigation
16
+ end
17
+ end
18
+
19
+ # Returns true if this navigation item should be rendered as 'selected' for the specified current_navigation.
20
+ def selected?(current_navigation)
21
+ key == current_navigation
22
+ end
23
+
24
+ # Returns the html-options hash for the item, i.e. the options specified for this item in the config-file.
25
+ # It also adds the 'selected' class to the list of classes if necessary.
26
+ def html_options(current_navigation)
27
+ default_options = {:id => key.to_s}
28
+ options = default_options.merge(@html_options)
29
+ options[:class] = [@html_options[:class], self.selected_class(current_navigation)].flatten.compact.join(' ')
30
+ options.delete(:class) if options[:class].blank?
31
+ options
32
+ end
33
+
34
+ def selected_class(current_navigation) #:nodoc:
35
+ selected?(current_navigation) ? SimpleNavigation.config.selected_class : nil
36
+ end
37
+
38
+
39
+ end
40
+ end
@@ -0,0 +1,43 @@
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
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>html_options</tt> can be used to specify attributes that will be included in the rendered navigation item (e.g. id, class etc.)
23
+ #
24
+ # The <tt>block</tt> - if specified - will hold the item's sub_navigation.
25
+ def item(key, name, url, html_options={}, &block)
26
+ @items << Item.new(key, name, url, html_options, block)
27
+ end
28
+
29
+ # Returns the Item with the specified key, nil otherwise.
30
+ def [](navi_key)
31
+ items.find {|i| i.key == navi_key}
32
+ end
33
+
34
+ # Renders the items in this ItemContainer using the configured renderer.
35
+ #
36
+ # Set <tt>include_sub_navigation</tt> to true if you want to nest the sub_navigation into the active primary_navigation
37
+ def render(current_navigation, include_sub_navigation=false, current_sub_navigation=nil)
38
+ self.renderer.new(current_navigation, current_sub_navigation).render(self, include_sub_navigation)
39
+ end
40
+
41
+ end
42
+
43
+ end
@@ -0,0 +1,30 @@
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
14
+
15
+ def initialize(current_navigation, current_sub_navigation=nil) #:nodoc:
16
+ @current_navigation = current_navigation
17
+ @current_sub_navigation = current_sub_navigation
18
+ end
19
+
20
+ # Renders the specified ItemContainer to HTML.
21
+ #
22
+ # If <tt>include_sub_navigation</tt> is set to true, the renderer should nest the sub_navigation for the active navigation
23
+ # inside that navigation item.
24
+ def render(item_container, include_sub_navigation=false)
25
+ raise 'subclass responsibility'
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,24 @@
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))
16
+ li_content << (item.sub_navigation.render(current_sub_navigation)) if include_sub_navigation && item.sub_navigation && item.selected?(current_navigation)
17
+ list << content_tag(:li, li_content, html_options)
18
+ end
19
+ content_tag(:ul, list_content, {:id => item_container.dom_id})
20
+ end
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,3 @@
1
+ config_file_path = File.join(RAILS_ROOT, 'config', 'navigation.rb')
2
+ SimpleNavigation.load_config(config_file_path) if File.exists?(config_file_path)
3
+ ActionController::Base.send(:include, SimpleNavigation::ControllerMethods)
@@ -0,0 +1,81 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe SimpleNavigation do
4
+
5
+ describe 'load_config' do
6
+
7
+ before(:each) do
8
+ @config_file = '"my_navigation_config"'
9
+ IO.stub!(:read).and_return(@config_file)
10
+ end
11
+
12
+ it "should load the navigation-configfile into a string" do
13
+ IO.should_receive(:read).with('./config/navigation.rb')
14
+ SimpleNavigation.load_config('./config/navigation.rb')
15
+ end
16
+ it "should store that string in a module-var" do
17
+ SimpleNavigation.load_config('./config/navigation.rb')
18
+ SimpleNavigation.config_file.should == @config_file
19
+ end
20
+ end
21
+
22
+ describe 'config' do
23
+ it {SimpleNavigation.config.should == SimpleNavigation::Configuration.instance}
24
+ end
25
+
26
+ end
27
+
28
+ describe SimpleNavigation::Configuration do
29
+
30
+ before(:each) do
31
+ @config = SimpleNavigation::Configuration.instance
32
+ end
33
+
34
+ describe 'self.run' do
35
+ it "should yield the singleton Configuration object" do
36
+ SimpleNavigation::Configuration.run do |c|
37
+ c.should == @config
38
+ end
39
+ end
40
+ end
41
+
42
+ describe 'self.eval_config' do
43
+ before(:each) do
44
+ @context = mock(:context)
45
+ @config_file = stub(:config_file)
46
+ SimpleNavigation.stub!(:config_file).and_return(@config_file)
47
+ end
48
+ it "should instance_eval the config_file-string inside the context" do
49
+ @context.should_receive(:instance_eval).with(@config_file)
50
+ SimpleNavigation::Configuration.eval_config(@context)
51
+ end
52
+ end
53
+
54
+ describe 'initialize' do
55
+ it "should set the List-Renderer as default upon initialize" do
56
+ @config.renderer.should == SimpleNavigation::Renderer::List
57
+ end
58
+ it "should set the selected_class to 'selected' as default" do
59
+ @config.selected_class.should == 'selected'
60
+ end
61
+ end
62
+ describe 'items' do
63
+ before(:each) do
64
+ @container = stub(:items_container)
65
+ SimpleNavigation::ItemContainer.stub!(:new).and_return(@container)
66
+ end
67
+ it "should should yield an new ItemContainer" do
68
+ @config.items do |container|
69
+ container.should == @container
70
+ end
71
+ end
72
+ it "should assign the ItemContainer to an instance-var" do
73
+ @config.items {}
74
+ @config.primary_navigation.should == @container
75
+ end
76
+ end
77
+
78
+
79
+ end
80
+
81
+
@@ -0,0 +1,75 @@
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
+ @controller.master_helper_module.included_modules.should include(SimpleNavigation::Helpers)
27
+ end
28
+ end
29
+
30
+ describe 'class_methods' do
31
+
32
+ describe 'navigation' do
33
+
34
+ def call_navigation(key1, key2=nil)
35
+ @controller.class_eval do
36
+ navigation key1, key2
37
+ end
38
+ end
39
+
40
+ it "should not have an instance-method 'set_navigation if navigation-method has not been called" do
41
+ @controller.respond_to?(:set_navigation).should be_false
42
+ end
43
+ it 'should create an instance-method "set_navigation" when being called' do
44
+ call_navigation(:key)
45
+ @controller.respond_to?(:set_navigation).should be_true
46
+ end
47
+ it 'the created method should call current_navigation with the specified keys' do
48
+ call_navigation(:primary, :secondary)
49
+ @controller.should_receive(:current_navigation).with(:primary, :secondary)
50
+ @controller.set_navigation
51
+ end
52
+ end
53
+
54
+ end
55
+
56
+ describe 'instance_methods' do
57
+
58
+ describe 'current_navigation' do
59
+ it "should set the current_primary_navigation as specified" do
60
+ @controller.current_navigation(:first)
61
+ @controller.instance_variable_get(:@current_primary_navigation).should == :first
62
+ end
63
+ it "should set the current_secondary_navigation as specified" do
64
+ @controller.current_navigation(:first, :second)
65
+ @controller.instance_variable_get(:@current_secondary_navigation).should == :second
66
+ end
67
+ it "should set the current_secondary_navigation to nil if no secondary is specified" do
68
+ @controller.current_navigation(:first)
69
+ @controller.instance_variable_get(:@current_secondary_navigation).should be_nil
70
+ end
71
+ end
72
+
73
+ end
74
+
75
+ end
@@ -0,0 +1,97 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe SimpleNavigation::Helpers do
4
+ class ControllerMock
5
+ include SimpleNavigation::Helpers
6
+ end
7
+
8
+ before(:each) do
9
+ @controller = ControllerMock.new
10
+ SimpleNavigation.config.stub!(:loaded?).and_return(true)
11
+ @primary_navigation = stub(:primary_navigation)
12
+ SimpleNavigation.stub!(:primary_navigation).and_return(@primary_navigation)
13
+ end
14
+
15
+ describe 'render_navigation' do
16
+ context 'primary' do
17
+ before(:each) do
18
+ @controller.instance_variable_set(:@current_primary_navigation, :current_primary)
19
+ end
20
+ it "should call render on the primary_navigation" do
21
+ @primary_navigation.should_receive(:render).with(:current_primary)
22
+ @controller.render_navigation(:primary)
23
+ end
24
+ end
25
+
26
+ context 'secondary' do
27
+ context 'with current_primary_navigation set' do
28
+ before(:each) do
29
+ @sub_navigation = stub(:sub_navigation, :null_object => true)
30
+ @primary_navigation.stub!(:[]).and_return(@sub_navigation)
31
+ @controller.instance_variable_set(:@current_primary_navigation, :current_primary)
32
+ @controller.instance_variable_set(:@current_secondary_navigation, :current_secondary)
33
+ end
34
+ it "should find the sub_navigation belonging to the current primary_navigation" do
35
+ @primary_navigation.should_receive(:[]).with(:current_primary)
36
+ @controller.render_navigation(:secondary)
37
+ end
38
+ it "should call render on the current primary_navigation's sub_navigation" do
39
+ @sub_navigation.should_receive(:render).with(:current_secondary)
40
+ @controller.render_navigation(:secondary)
41
+ end
42
+ end
43
+ context 'without current_primary_navigation set' do
44
+ before(:each) do
45
+ @primary_navigation.stub!(:[]).and_return(nil)
46
+ @controller.instance_variable_set(:@current_primary_navigation, nil)
47
+ end
48
+ it "should not raise an error" do
49
+ lambda{@controller.render_navigation(:secondary)}.should_not raise_error
50
+ end
51
+ end
52
+
53
+ end
54
+
55
+ context 'nested' do
56
+ before(:each) do
57
+ @controller.instance_variable_set(:@current_primary_navigation, :current_primary)
58
+ @controller.instance_variable_set(:@current_secondary_navigation, :current_secondary)
59
+ end
60
+ it "should call render on the primary navigation" do
61
+ @primary_navigation.should_receive(:render).with(anything, anything, anything)
62
+ @controller.render_navigation(:nested)
63
+ end
64
+ it "should call render with the current_primary_navigation" do
65
+ @primary_navigation.should_receive(:render).with(:current_primary, anything, anything)
66
+ @controller.render_navigation(:nested)
67
+ end
68
+ it "should call render with the include_subnavigation option set" do
69
+ @primary_navigation.should_receive(:render).with(anything, true, anything)
70
+ @controller.render_navigation(:nested)
71
+ end
72
+ it "should call render with the current_sub_navigation" do
73
+ @primary_navigation.should_receive(:render).with(anything, anything, :current_secondary)
74
+ @controller.render_navigation(:nested)
75
+ end
76
+ end
77
+
78
+ context 'unknown level' do
79
+ it {lambda {@controller.render_navigation(:unknown)}.should raise_error(ArgumentError)}
80
+ end
81
+ end
82
+
83
+ describe 'render_primary_navigation' do
84
+ it "should delegate to render_navigation(:primary)" do
85
+ @controller.should_receive(:render_navigation).with(:primary)
86
+ @controller.render_primary_navigation
87
+ end
88
+ end
89
+
90
+ describe 'render_sub_navigation' do
91
+ it "should delegate to render_navigation(:secondary)" do
92
+ @controller.should_receive(:render_navigation).with(:secondary)
93
+ @controller.render_sub_navigation
94
+ end
95
+ end
96
+
97
+ end
@@ -0,0 +1,94 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe SimpleNavigation::ItemContainer do
4
+ before(:each) do
5
+ @item_container = SimpleNavigation::ItemContainer.new
6
+ end
7
+ describe 'initialize' do
8
+ it "should set the renderer to the globally-configured renderer per default" do
9
+ SimpleNavigation::Configuration.instance.should_receive(:renderer)
10
+ @item_container = SimpleNavigation::ItemContainer.new
11
+ end
12
+ it "should have an empty items-array" do
13
+ @item_container = SimpleNavigation::ItemContainer.new
14
+ @item_container.items.should be_empty
15
+ end
16
+ end
17
+
18
+ describe 'item' do
19
+
20
+ context 'block given' do
21
+ before(:each) do
22
+ @sub_container = stub(:sub_container)
23
+ SimpleNavigation::ItemContainer.stub!(:new).and_return(@sub_container)
24
+ end
25
+
26
+ it "should should yield an new ItemContainer" do
27
+ @item_container.item('key', 'name', 'url', 'options') do |container|
28
+ container.should == @sub_container
29
+ end
30
+ end
31
+ it "should create a new Navigation-Item with the given params and the specified block" do
32
+ SimpleNavigation::Item.should_receive(:new).with('key', 'name', 'url', 'options', @proc)
33
+ @item_container.item('key', 'name', 'url', 'options', &@proc)
34
+ end
35
+ it "should add the created item to the list of items" do
36
+ @item_container.items.should_receive(:<<)
37
+ @item_container.item('key', 'name', 'url', 'options') {}
38
+ end
39
+ end
40
+
41
+ context 'no block given' do
42
+ it "should create a new Navigation_item with the given params and nil as sub_navi" do
43
+ SimpleNavigation::Item.should_receive(:new).with('key', 'name', 'url', 'options', nil)
44
+ @item_container.item('key', 'name', 'url', 'options')
45
+ end
46
+ it "should add the created item to the list of items" do
47
+ @item_container.items.should_receive(:<<)
48
+ @item_container.item('key', 'name', 'url', 'options')
49
+ end
50
+ end
51
+
52
+ end
53
+
54
+ describe '[]' do
55
+
56
+ before(:each) do
57
+ @item_container.item(:first, 'first', 'bla')
58
+ @item_container.item(:second, 'second', 'bla')
59
+ @item_container.item(:third, 'third', 'bla')
60
+ end
61
+
62
+ it "should return the item with the specified navi_key" do
63
+ @item_container[:second].name.should == 'second'
64
+ end
65
+ it "should return nil if no item exists for the specified navi_key" do
66
+ @item_container[:invalid].should be_nil
67
+ end
68
+ end
69
+
70
+ describe 'render' do
71
+ before(:each) do
72
+ @renderer = stub(:renderer)
73
+ @renderer_instance = stub(:renderer_instance, :null_object => true)
74
+ @renderer.stub!(:new).and_return(@renderer_instance)
75
+ @item_container.stub!(:renderer).and_return(@renderer)
76
+ @items = stub(:items)
77
+ @item_container.stub!(:items).and_return(@items)
78
+ end
79
+ it "should instatiate a renderer with the current_primary and current_secondary" do
80
+ @renderer.should_receive(:new).with(:current_navigation, nil)
81
+ @item_container.render(:current_navigation)
82
+ end
83
+ it "should call render on the renderer and pass self" do
84
+ @renderer_instance.should_receive(:render).with(@item_container, anything)
85
+ @item_container.render(:current_navigation)
86
+ end
87
+ it "should call render on the renderer and pass the include_sub_navigation option" do
88
+ @renderer_instance.should_receive(:render).with(anything, true)
89
+ @item_container.render(:current_navigation, true, :current_sub_navigation)
90
+ end
91
+
92
+ end
93
+
94
+ end
@@ -0,0 +1,101 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe SimpleNavigation::Item do
4
+
5
+ describe 'initialize' do
6
+
7
+ end
8
+
9
+ describe 'selected?' do
10
+ before(:each) do
11
+ @item = SimpleNavigation::Item.new(:my_key, 'name', 'url', {}, nil)
12
+ end
13
+ it {@item.selected?(:my_key).should be_true}
14
+ it {@item.selected?(:my_other_key).should be_false}
15
+ end
16
+
17
+ describe 'selected_class' do
18
+ before(:each) do
19
+ @item = SimpleNavigation::Item.new(:my_key, 'name', 'url', {}, nil)
20
+ end
21
+
22
+ context 'item is selected' do
23
+ before(:each) do
24
+ @item.stub!(:selected?).and_return(true)
25
+ end
26
+ it {@item.instance_eval {selected_class(:bla).should == 'selected'}}
27
+ end
28
+
29
+ context 'item is not selected' do
30
+ before(:each) do
31
+ @item.stub!(:selected?).and_return(false)
32
+ end
33
+ it {@item.instance_eval {selected_class(:bla).should == nil}}
34
+ end
35
+ end
36
+
37
+ describe 'html_options' do
38
+ describe 'class' do
39
+ context 'with classes defined in options' do
40
+ before(:each) do
41
+ @options = {:class => 'my_class'}
42
+ @item = SimpleNavigation::Item.new(:my_key, 'name', 'url', @options, nil)
43
+ end
44
+ context 'with item selected' do
45
+ before(:each) do
46
+ @item.stub!(:selected?).and_return(true)
47
+ end
48
+ it {@item.html_options(:bla)[:class].should == 'my_class selected'}
49
+ end
50
+
51
+ context 'with item not selected' do
52
+ before(:each) do
53
+ @item.stub!(:selected?).and_return(false)
54
+ end
55
+ it {@item.html_options(:bla)[:class].should == 'my_class'}
56
+ end
57
+ end
58
+
59
+ context 'without classes in options' do
60
+ before(:each) do
61
+ @options = {}
62
+ @item = SimpleNavigation::Item.new(:my_key, 'name', 'url', @options, nil)
63
+ end
64
+ context 'with item selected' do
65
+ before(:each) do
66
+ @item.stub!(:selected?).and_return(true)
67
+ end
68
+ it {@item.html_options(:bla)[:class].should == 'selected'}
69
+ end
70
+
71
+ context 'with item not selected' do
72
+ before(:each) do
73
+ @item.stub!(:selected?).and_return(false)
74
+ end
75
+ it {@item.html_options(:bla)[:class].should be_blank}
76
+ end
77
+ end
78
+ end
79
+
80
+ describe 'id' do
81
+ context 'with id defined in options' do
82
+ before(:each) do
83
+ @options = {:id => 'my_id'}
84
+ @item = SimpleNavigation::Item.new(:my_key, 'name', 'url', @options, nil)
85
+ end
86
+ it {@item.html_options(:bla)[:id].should == 'my_id'}
87
+ end
88
+
89
+ context 'with no id definied in options (using default id)' do
90
+ before(:each) do
91
+ @options = {}
92
+ @item = SimpleNavigation::Item.new(:my_key, 'name', 'url', @options, nil)
93
+ end
94
+ it {@item.html_options(:bla)[:id].should == 'my_key'}
95
+ end
96
+ end
97
+
98
+ end
99
+
100
+
101
+ end
@@ -0,0 +1,15 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
3
+ describe SimpleNavigation::Renderer::Base do
4
+ before(:each) do
5
+ @base_renderer = SimpleNavigation::Renderer::Base.new(:current_primary, :current_secondary)
6
+ end
7
+ it "should inclue ActionView::Helpers::UrlHelper" do
8
+ @base_renderer.should respond_to(:link_to)
9
+ end
10
+ it "should include ActionView::Helpers::TagHelper" do
11
+ @base_renderer.should respond_to(:content_tag)
12
+ end
13
+ it {@base_renderer.current_navigation.should == :current_primary}
14
+ it {@base_renderer.current_sub_navigation.should == :current_secondary}
15
+ end
@@ -0,0 +1,94 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+ require 'html/document' unless defined? HTML::Document
3
+
4
+ describe SimpleNavigation::Renderer::List do
5
+
6
+ describe 'render' do
7
+
8
+ def sub_items
9
+ [
10
+ SimpleNavigation::Item.new(:subnav1, 'subnav1', 'subnav1_url', {}, nil),
11
+ SimpleNavigation::Item.new(:subnav2, 'subnav2', 'subnav2_url', {}, nil)
12
+ ]
13
+ end
14
+
15
+ def primary_items
16
+ @item1 = SimpleNavigation::Item.new(:users, 'users', 'first_url', {:id => 'my_id'}, nil)
17
+ @item2 = SimpleNavigation::Item.new(:invoices, 'invoices', 'second_url', {}, nil)
18
+ @item3 = SimpleNavigation::Item.new(:accounts, 'accounts', 'third_url', {:style => 'float:right'}, nil)
19
+ @item2.instance_variable_set(:@sub_navigation, item_container(sub_items))
20
+ [@item1, @item2, @item3]
21
+ end
22
+
23
+ def item_container(items)
24
+ container = SimpleNavigation::ItemContainer.new
25
+ container.dom_id = 'nav_dom_id'
26
+ container.instance_variable_set(:@items, items)
27
+ container
28
+ end
29
+
30
+ def primary_navigation
31
+ @item_container = item_container(primary_items)
32
+ @item_container
33
+ end
34
+
35
+ def render(current_navigation=nil, include_subnav=false)
36
+ @renderer = SimpleNavigation::Renderer::List.new(current_navigation)
37
+ HTML::Document.new(@renderer.render(primary_navigation, include_subnav)).root
38
+ end
39
+
40
+ it "should render a ul-tag around the items" do
41
+ HTML::Selector.new('ul').select(render).should have(1).entries
42
+ end
43
+ it "the rendered ul-tag should have the specified dom_id" do
44
+ HTML::Selector.new('ul#nav_dom_id').select(render).should have(1).entries
45
+ end
46
+ it "should render a li tag for each item" do
47
+ HTML::Selector.new('li').select(render).should have(3).entries
48
+ end
49
+ it "should render an a-tag inside each li-tag" do
50
+ HTML::Selector.new('li a').select(render).should have(3).entries
51
+ end
52
+ it "should pass the specified html_options to the li element" do
53
+ HTML::Selector.new('li[style=float:right]').select(render).should have(1).entries
54
+ end
55
+ it "should give the li the id specified in the html_options" do
56
+ HTML::Selector.new('li#my_id').select(render).should have(1).entries
57
+ end
58
+ it "should give the li the default id (stringified key) if no id is specified in the html_options" do
59
+ HTML::Selector.new('ul li#invoices').select(render).should have(1).entries
60
+ end
61
+ it "should not apply the the default id where there is an id specified in the html_options" do
62
+ HTML::Selector.new('ul li#users').select(render).should be_empty
63
+ end
64
+
65
+ context 'with current_navigation set' do
66
+ it "should mark the matching li-item as selected (with the css_class specified in configuration)" do
67
+ HTML::Selector.new('li.selected').select(render(:invoices)).should have(1).entries
68
+ end
69
+ it "should also mark the links inside the selected li's as selected" do
70
+ HTML::Selector.new('li.selected a.selected').select(render(:invoices)).should have(1).entries
71
+ end
72
+
73
+ end
74
+
75
+ context 'without current_navigation set' do
76
+ it "should not mark any of the items as selected" do
77
+ HTML::Selector.new('li.selected').select(render).should be_empty
78
+ end
79
+ it "should not mark any links as selected" do
80
+ HTML::Selector.new('a.selected').select(render).should be_empty
81
+ end
82
+ end
83
+
84
+ context 'nested sub_navigation' do
85
+ it "should nest the current_primary's subnavigation inside the selected li-element" do
86
+ HTML::Selector.new('li.selected ul li').select(render(:invoices, true)).should have(2).entries
87
+ end
88
+ it "should be possible to identify sub items using an html selector (using ids)" do
89
+ HTML::Selector.new('#invoices #subnav1').select(render(:invoices, true)).should have(1).entries
90
+ end
91
+ end
92
+
93
+ end
94
+ end
@@ -0,0 +1,24 @@
1
+ ENV["RAILS_ENV"] = "test"
2
+ require 'rubygems'
3
+ require 'spec'
4
+ require 'active_support'
5
+ require 'action_controller'
6
+
7
+ RAILS_ROOT = './' unless defined? RAILS_ROOT
8
+
9
+ $:.unshift File.dirname(__FILE__)
10
+ $:.unshift File.join(File.dirname(__FILE__), '../lib')
11
+
12
+ require 'simple_navigation/configuration'
13
+ require 'simple_navigation/helpers'
14
+ require 'simple_navigation/controller_methods'
15
+ require 'simple_navigation/item'
16
+ require 'simple_navigation/item_container'
17
+ require 'simple_navigation/renderer/base'
18
+ require 'simple_navigation/renderer/list'
19
+
20
+ require 'simple_navigation'
21
+
22
+ # Spec::Runner.configure do |config|
23
+ # no special config
24
+ # endx
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: simple-navigation
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Andi Schacke
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-04-14 00:00:00 +02:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Simple Navigation is a ruby library for creating a navigation (optionally with sub navigation) for your rails app.
17
+ email: andreas.schacke@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README
24
+ files:
25
+ - CHANGELOG
26
+ - Rakefile
27
+ - VERSION.yml
28
+ - generators/navigation_config/USAGE
29
+ - generators/navigation_config/navigation_config_generator.rb
30
+ - generators/navigation_config/templates/config/navigation.rb
31
+ - lib/simple_navigation.rb
32
+ - lib/simple_navigation/configuration.rb
33
+ - lib/simple_navigation/controller_methods.rb
34
+ - lib/simple_navigation/helpers.rb
35
+ - lib/simple_navigation/item.rb
36
+ - lib/simple_navigation/item_container.rb
37
+ - lib/simple_navigation/renderer/base.rb
38
+ - lib/simple_navigation/renderer/list.rb
39
+ - rails/init.rb
40
+ - spec/lib/configuration_spec.rb
41
+ - spec/lib/controller_methods_spec.rb
42
+ - spec/lib/helpers_spec.rb
43
+ - spec/lib/item_container_spec.rb
44
+ - spec/lib/item_spec.rb
45
+ - spec/lib/renderer/base_spec.rb
46
+ - spec/lib/renderer/list_spec.rb
47
+ - spec/spec_helper.rb
48
+ - README
49
+ has_rdoc: true
50
+ homepage: http://github.com/andi/simple-navigation
51
+ post_install_message:
52
+ rdoc_options:
53
+ - --inline-source
54
+ - --charset=UTF-8
55
+ require_paths:
56
+ - lib
57
+ required_ruby_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: "0"
62
+ version:
63
+ required_rubygems_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: "0"
68
+ version:
69
+ requirements: []
70
+
71
+ rubyforge_project: andi
72
+ rubygems_version: 1.3.1
73
+ signing_key:
74
+ specification_version: 2
75
+ summary: Simple Navigation is a ruby library for creating a navigation (optionally with sub navigation) for your rails app.
76
+ test_files:
77
+ - spec/lib/configuration_spec.rb
78
+ - spec/lib/controller_methods_spec.rb
79
+ - spec/lib/helpers_spec.rb
80
+ - spec/lib/item_container_spec.rb
81
+ - spec/lib/item_spec.rb
82
+ - spec/lib/renderer/base_spec.rb
83
+ - spec/lib/renderer/list_spec.rb
84
+ - spec/spec_helper.rb