menumatic 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.DS_Store ADDED
Binary file
data/.autotest ADDED
@@ -0,0 +1 @@
1
+ require 'autotest/growl'
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in menumatic.gemspec
4
+ gemspec
5
+
6
+ gem 'rspec'
7
+ gem 'autotest'
8
+ gem 'autotest-growl'
9
+ gem 'factory_girl'
10
+ gem 'rails', '~>3.0.4'
data/Gemfile.lock ADDED
@@ -0,0 +1,95 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ menumatic (0.0.1)
5
+
6
+ GEM
7
+ remote: http://rubygems.org/
8
+ specs:
9
+ ZenTest (4.5.0)
10
+ abstract (1.0.0)
11
+ actionmailer (3.0.5)
12
+ actionpack (= 3.0.5)
13
+ mail (~> 2.2.15)
14
+ actionpack (3.0.5)
15
+ activemodel (= 3.0.5)
16
+ activesupport (= 3.0.5)
17
+ builder (~> 2.1.2)
18
+ erubis (~> 2.6.6)
19
+ i18n (~> 0.4)
20
+ rack (~> 1.2.1)
21
+ rack-mount (~> 0.6.13)
22
+ rack-test (~> 0.5.7)
23
+ tzinfo (~> 0.3.23)
24
+ activemodel (3.0.5)
25
+ activesupport (= 3.0.5)
26
+ builder (~> 2.1.2)
27
+ i18n (~> 0.4)
28
+ activerecord (3.0.5)
29
+ activemodel (= 3.0.5)
30
+ activesupport (= 3.0.5)
31
+ arel (~> 2.0.2)
32
+ tzinfo (~> 0.3.23)
33
+ activeresource (3.0.5)
34
+ activemodel (= 3.0.5)
35
+ activesupport (= 3.0.5)
36
+ activesupport (3.0.5)
37
+ arel (2.0.9)
38
+ autotest (4.4.6)
39
+ ZenTest (>= 4.4.1)
40
+ autotest-growl (0.2.9)
41
+ builder (2.1.2)
42
+ diff-lcs (1.1.2)
43
+ erubis (2.6.6)
44
+ abstract (>= 1.0.0)
45
+ factory_girl (1.3.2)
46
+ i18n (0.5.0)
47
+ mail (2.2.15)
48
+ activesupport (>= 2.3.6)
49
+ i18n (>= 0.4.0)
50
+ mime-types (~> 1.16)
51
+ treetop (~> 1.4.8)
52
+ mime-types (1.16)
53
+ polyglot (0.3.1)
54
+ rack (1.2.1)
55
+ rack-mount (0.6.13)
56
+ rack (>= 1.0.0)
57
+ rack-test (0.5.7)
58
+ rack (>= 1.0)
59
+ rails (3.0.5)
60
+ actionmailer (= 3.0.5)
61
+ actionpack (= 3.0.5)
62
+ activerecord (= 3.0.5)
63
+ activeresource (= 3.0.5)
64
+ activesupport (= 3.0.5)
65
+ bundler (~> 1.0)
66
+ railties (= 3.0.5)
67
+ railties (3.0.5)
68
+ actionpack (= 3.0.5)
69
+ activesupport (= 3.0.5)
70
+ rake (>= 0.8.7)
71
+ thor (~> 0.14.4)
72
+ rake (0.8.7)
73
+ rspec (2.5.0)
74
+ rspec-core (~> 2.5.0)
75
+ rspec-expectations (~> 2.5.0)
76
+ rspec-mocks (~> 2.5.0)
77
+ rspec-core (2.5.1)
78
+ rspec-expectations (2.5.0)
79
+ diff-lcs (~> 1.1.2)
80
+ rspec-mocks (2.5.0)
81
+ thor (0.14.6)
82
+ treetop (1.4.9)
83
+ polyglot (>= 0.3.1)
84
+ tzinfo (0.3.24)
85
+
86
+ PLATFORMS
87
+ ruby
88
+
89
+ DEPENDENCIES
90
+ autotest
91
+ autotest-growl
92
+ factory_girl
93
+ menumatic!
94
+ rails (~> 3.0.4)
95
+ rspec
data/LICENSE ADDED
@@ -0,0 +1,24 @@
1
+ Open Source Initiative OSI - The MIT License:Licensing
2
+
3
+ The MIT License
4
+
5
+ Copyright (c) 2011 Nicholas Bruning
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to deal
9
+ in the Software without restriction, including without limitation the rights
10
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included in
15
+ all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ THE SOFTWARE.
24
+
data/README.md ADDED
@@ -0,0 +1,144 @@
1
+ # Menumatic
2
+
3
+ Menumatic is a _Rails 3 exclusive_ gem which aids in developing HTML
4
+ navigation menus.
5
+
6
+
7
+ ## Philosophy
8
+
9
+ When designing Menumatic, I wanted a way in which I could remove
10
+ navigation logic from the view all together, but also keep configuration
11
+ to a bare minimum and (hopefully) stick to the principle of
12
+ 'convention-over-configuration'.
13
+
14
+ Menumatic considers navigations to be more like models as opposed to
15
+ views. As such, navigations are defined in the `app/navigation`
16
+ directory, and rendered in the view with a simple helper method.
17
+
18
+
19
+ # Getting Started
20
+
21
+ Include the gem in your `Gemfile` like so:
22
+
23
+ gem 'menumatic'
24
+
25
+ Then update your bundle:
26
+
27
+ $ bundle
28
+
29
+ You can then get started by generating a new navigation:
30
+
31
+ $ rails g navigation
32
+
33
+ This will create the file `app/navigation/application_navigation.rb` which you can use to
34
+ define the structure of your navigation items.
35
+
36
+ If you want to use the bundled stylesheet (nothing fancy, but quite serviceable - enough to get you up and running), add the following to your
37
+ layout:
38
+
39
+ <%= stylesheet_link_tag "application_navigation" %>
40
+
41
+
42
+ # Using Menumatic
43
+
44
+ Navigations are stored in `app/navigation`. The default navigation is
45
+ given a name of 'application', however you can specify the name in the
46
+ generator:
47
+
48
+ $ rails g navigation application
49
+
50
+ Which will generate a navigation called
51
+ `app/navigation/application_navigation.rb` and the basic stylesheet.
52
+
53
+ Inside your navigation file, you can then define the structure of your
54
+ navigation, here is an example taken from the [Menumatic example
55
+ application](http://github.com/thetron/menumatic-sample-application):
56
+
57
+ navigate_to "Home", home_path, :active_on => [:home_path, :root_path]
58
+ navigate_to "About", about_path
59
+ navigate_to "Store", store_on_special_path do |store|
60
+ store.navigate_to "On special", store_on_special_path
61
+ store.navigate_to "Coming soon", store_coming_soon_path
62
+ store.navigate_to "Categories", store_categories_path do |categories|
63
+ categories.navigate_to "Shirts", store_categories_shirts_path
64
+ categories.navigate_to "Pants", store_categories_pants_path
65
+ categories.navigate_to "Hats", store_categories_hats_path
66
+ categories.navigate_to "Accessories", store_categories_accessories_path
67
+ categories.navigate_to "Sporks", store_categories_sporks_path
68
+ end
69
+ end
70
+ navigate_to "Contact us", contact_us_path
71
+ navigate_to "Admin", admin_path if current_user.is_admin?
72
+
73
+ When creating your navigation you effectively have two methods at your
74
+ disposal: `navigate_to` and `group`
75
+
76
+ `navigate_to` creates a navigation item in your menu, and works very
77
+ similar to Rails' built-in `link_to` helper. It also accepts a few other
78
+ options, which are listed below.
79
+
80
+ To display your navigation in your view, simply use the menumatic
81
+ helper:
82
+
83
+ # app/views/layouts/application.html.erb
84
+ <!-- snip -->
85
+ <header>
86
+ <nav>
87
+ <%= navigation :application %>
88
+ </nav>
89
+ </header>
90
+
91
+ Which will give you a full-semantic, auto-highlighted navigation.
92
+
93
+
94
+ ## Rendering specific navigation levels
95
+
96
+ By default, Menumatic displays your navigation as a set of nested
97
+ unordered lists. However, if you need to break up your layout, this is
98
+ easily achiveable:
99
+
100
+
101
+ # app/views/layouts/application.html.erb
102
+ <!-- snip -->
103
+ <header>
104
+ <nav>
105
+ <%= navigation :application, :level => :primary %>
106
+ </nav>
107
+ </header>
108
+
109
+ <div class="sub_navigation">
110
+ <%= navigation :application, :levels => [:secondary, :tertiary] %>
111
+ </div>
112
+
113
+ The above example would render the top-level navigation in the
114
+ `<header>` and everything else in the `sub_navigation` div below.
115
+
116
+
117
+ ## Sitemap generation
118
+
119
+ Menumatic can also optionally generate a sitemap.xml. To include a
120
+
121
+ sitemap in your site, simply add this line to your `config/routes.rb`
122
+
123
+ sitemap_for :application # or the name of your navigation
124
+
125
+
126
+ # Todo
127
+
128
+ I have some big ideas for Menumatic, but there should be enough
129
+ functionality in there to service the vast majority of web apps. If you have
130
+ any feature requests or questions, feel free to [open an issue](http://github.com/thetron/menumatic/issues) - I'd love to get
131
+ some feedback!
132
+
133
+ This is what I have planned for some future releases:
134
+
135
+ * __Tests__ I know I should've been doing this properly from the start,
136
+ but i'm still trying to get my head around TDD. However, this is definitely a
137
+ big priority for Menumatic.
138
+
139
+ * __More configuration options__
140
+
141
+
142
+ # Credits
143
+
144
+ I'd like to thank [Jordan Lewis](http://github.com/jordan-lewis) for his CSS styling skills.
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
data/TODO.md ADDED
@@ -0,0 +1,36 @@
1
+ # Menumatic - TODO
2
+
3
+ ## Refactor
4
+
5
+ `Menumatic::Navigation::Item::Base` needs to become the superclass of the two navigator options:
6
+ - Menumatic::Navigation::Item::Group
7
+ - Menumatic::Navigation::Item::Link
8
+
9
+ The difference between these two, is that `Link` will have significanly
10
+ more attributes, and also have included
11
+ `Menumatic::Navigation::Item::Renderers`. Additionally, the 'root' of
12
+ any Menumatic::Navigation::Base, will be converted into a `Group` with
13
+ `id = :root`.
14
+
15
+ This will allow us to handle the render chain much more logically, and
16
+ hopefully produce some cleaner code.
17
+
18
+ ## Selective Navigation rendering
19
+
20
+ This should be the next highest priority, and we need to consider how to
21
+ pass the requested groups and chain position through the render process,
22
+ to make sure no link is left behind.
23
+
24
+ ## Sitemap generation
25
+
26
+ Create a helper method for the routes.rb file (similar to `devise_for`):
27
+
28
+ sitemap :application
29
+
30
+ Which will create a route for sitemap.xml and automatically generate and
31
+ handle the requests that go through to it. The sitemap will be generated
32
+ from the navigation specified in the sitemap helper. This will include
33
+ all links and groups (except those not visible by default from
34
+ conditional effects).
35
+
36
+
@@ -0,0 +1,5 @@
1
+ class Menumatic::SitemapController < ApplicationController
2
+ respond_to :xml
3
+ def index
4
+ end
5
+ end
@@ -0,0 +1,4 @@
1
+ xml.instruct!
2
+ xml.urlset :xmlns => "http://www.sitemaps.org/schemas/sitemap/0.9" do
3
+ sitemap(xml, params[:navigation_id])
4
+ end
data/lib/.DS_Store ADDED
Binary file
@@ -0,0 +1,3 @@
1
+ To create a new MenuMatic navigation in your Rails app, simply do:
2
+
3
+ rails generate menumatic:navigation main
@@ -0,0 +1,23 @@
1
+ module Menumatic
2
+ module Generators
3
+ class NavigationGenerator < Rails::Generators::Base
4
+ desc "Creates a new navigation file"
5
+ source_root File.expand_path('../templates', __FILE__)
6
+ argument :navigation_name, :type => :string, :default => "application"
7
+ class_option :stylesheet, :type => :boolean, :default => true, :description => "Include stylesheet file"
8
+
9
+ def generate_navigation
10
+ template "navigation.rb", "app/navigation/#{file_name}_navigation.rb"
11
+ end
12
+
13
+ def generate_stylesheet
14
+ template "stylesheet.css", "public/stylesheets/#{file_name}_navigation.css" unless options.skip_stylesheet?
15
+ end
16
+
17
+ private
18
+ def file_name
19
+ navigation_name.underscore
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,3 @@
1
+ class <%= file_name.camelize %>Navigation < Menumatic::Navigation::Base
2
+ navigate_to "Home", root_path
3
+ end
@@ -0,0 +1,73 @@
1
+ ul.navigation.<%= file_name %>, ul.navigation.<%= file_name %> ul {
2
+ font-family:Tahoma,Arial,sans-serif; font-size:12px; margin:0px; padding:0px;
3
+ width: 100%;
4
+ background: #ccc;
5
+ display:block;
6
+ position:absolute;
7
+ top:30px;
8
+ left: 0;
9
+ list-style:none;
10
+ padding:0;
11
+ margin: 0;
12
+ }
13
+
14
+ ul.navigation.<%= file_name %>.level_1 > li > a{
15
+ padding: 8px 10px;
16
+ }
17
+
18
+ ul.navigation.<%= file_name %> li {
19
+ margin:0;
20
+ padding:0 10px;
21
+ list-style:none;
22
+ float:left;
23
+ height: 30px;
24
+ }
25
+ ul.navigation.<%= file_name %> li:hover,
26
+ ul.navigation.<%= file_name %> li.active { color:#FFF; text-decoration:none; }
27
+ ul.navigation.<%= file_name %> li a {
28
+ padding:0 10px;
29
+ margin:0;
30
+ color:#FFF;
31
+ text-decoration: none;
32
+ display: block;
33
+ }
34
+
35
+
36
+ /* Level 1 */
37
+ ul.navigation.<%= file_name %>.level_1 { position: relative; top: 0; }
38
+ ul.navigation.<%= file_name %>.level_1 > li.active,
39
+ ul.navigation.<%= file_name %>.level_1 > li.active:hover { background:#444; }
40
+ ul.navigation.<%= file_name %>.level_1 > li:hover { background:#689cfe; }
41
+
42
+ /* Levels 2+ */
43
+ ul.navigation.<%= file_name %>.level_1 { background: #3b7df6; }
44
+ ul.navigation.<%= file_name %> ul.level_2 { background: #444; }
45
+ ul.navigation.<%= file_name %> ul.level_3 { background: #666; }
46
+ ul.navigation.<%= file_name %> ul.level_4 { background: #828282; }
47
+
48
+ ul.navigation.<%= file_name %> ul li a {
49
+ height: 20px;
50
+ margin-top: 5px;
51
+ line-height: 20px;
52
+ }
53
+ ul.navigation.<%= file_name %> ul li a:hover,
54
+ ul.navigation.<%= file_name %> ul li.active > a {
55
+ background:#b3b3b3;
56
+ color:#FFF;
57
+ text-decoration:none;
58
+ -webkit-border-radius: 5px;
59
+ -moz-border-radius: 5px;
60
+ border-radius: 5px;
61
+ }
62
+
63
+ ul.navigation.<%= file_name %>.depth_1 { height: 30px; }
64
+ ul.navigation.<%= file_name %>.depth_2 { height: 60px; }
65
+ ul.navigation.<%= file_name %>.depth_3 { height: 90px; }
66
+ ul.navigation.<%= file_name %>.depth_4 { height: 120px; }
67
+ ul.navigation.<%= file_name %>.depth_5 { height: 150px; }
68
+ ul.navigation.<%= file_name %>.depth_6 { height: 180px; }
69
+ ul.navigation.<%= file_name %>.depth_7 { height: 210px; }
70
+ ul.navigation.<%= file_name %>.depth_8 { height: 240px; }
71
+ ul.navigation.<%= file_name %>.depth_9 { height: 270px; }
72
+ ul.navigation.<%= file_name %>.depth_10 { height: 300px; }
73
+
Binary file
@@ -0,0 +1,4 @@
1
+ module Menumatic
2
+ class Engine < Rails::Engine
3
+ end
4
+ end
@@ -0,0 +1,36 @@
1
+ module Menumatic
2
+ module Helpers
3
+ module NavigationHelper
4
+ def navigation(navigation_id = "application", options = {})
5
+ options[:level] ||= nil # single level to render, overrides any other level settings
6
+ options[:levels] ||= [options[:level]].delete_if{ |l| l.blank? }
7
+
8
+ options[:group] ||= nil
9
+ options[:groups] ||= [options[:groups]].delete_if{ |g| g.blank? }
10
+
11
+ options[:class] ||= ""
12
+ options[:class] += "navigation #{navigation_id}"
13
+
14
+ navigation = load_navigation(navigation_id)
15
+ navigation.root.render(request, options)
16
+ end
17
+
18
+ def sitemap(document, navigation_id = "application", options = {})
19
+ navigation = load_navigation(navigation_id)
20
+ navigation.root.render_sitemap(document, request, options)
21
+ end
22
+
23
+ def load_navigation(navigation_id)
24
+ # Eager load the requested navgation (allows for use of normal if/unless statements)
25
+ Menumatic::Navigation::Base.destroy_all
26
+ load "app/navigation/#{navigation_id}_navigation.rb"
27
+ Menumatic::Navigation::Base.get(navigation_id)
28
+ end
29
+
30
+ def navigation_group(navigation_id, group_id, options = {})
31
+ options = options.merge({:group => group_id})
32
+ navigation(navigation_id, options)
33
+ end
34
+ end
35
+ end
36
+ end
Binary file
@@ -0,0 +1,13 @@
1
+ module Menumatic
2
+ module Navigation
3
+ module Item
4
+ class Group < Menumatic::Navigation::Item::Base
5
+ attr_accessor :group_id
6
+ def initialize(*args)
7
+ super
8
+ self.group_id = args[0]
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,19 @@
1
+ module Menumatic
2
+ module Navigation
3
+ module Item
4
+ class Link < Menumatic::Navigation::Item::Base
5
+ attr_accessor :label, :destination, :active_paths
6
+ def initialize(*args)
7
+ super
8
+ self.label = args[0]
9
+ self.destination = args[1]
10
+
11
+ if args.length > 2
12
+ options = args[2]
13
+ self.active_paths = options[:active_paths]
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,17 @@
1
+ module Menumatic
2
+ module Navigation
3
+ module Item
4
+ module Navigators
5
+ def navigate_to(label, destination, options = {})
6
+ item = add_item(Menumatic::Navigation::Item::Link.new(label, destination, options))
7
+ yield item if block_given?
8
+ end
9
+
10
+ def group(id, options = {})
11
+ item = add_item(Menumatic::Navigation::Item::Group.new(id, options))
12
+ yield item if block_given?
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,109 @@
1
+ module Menumatic
2
+ module Navigation
3
+ module Item
4
+ module Renderers
5
+ include ActionView::Helpers::UrlHelper
6
+ @@level_options = [:primary, :secondary, :tertiary, :quarternary, :quinary, :senary, :septenary, :octonary, :nonary, :denary]
7
+
8
+ def render(request, options = {})
9
+ options[:current_level] ||= 0
10
+
11
+ html_options = {}
12
+ html_options[:class] = options[:class]
13
+ options.delete(:class)
14
+ options = options.merge({})
15
+ options[:current_level] += 1
16
+
17
+ options[:show] ||= :active
18
+ options[:wrapper_tag] ||= :ul
19
+ options[:item_tag] ||= :li
20
+
21
+ # render list
22
+ list = self.items.map { |item| item.render(request, options) }.join("")
23
+ html_options[:class] ||= ""
24
+ html_options[:class] = (html_options[:class].split(" ") + (self.is_active?(request) ? ["active"] : ["inactive"])).join(" ")
25
+
26
+ unless list.blank?
27
+ list_options = html_options.merge({})
28
+ list_options[:class] += " level_#{options[:current_level]}"
29
+ list_options[:class] += " depth_#{count_active_descendants(request)}" if options[:current_level] == 1
30
+ if on_valid_level?(options[:levels], options[:current_level]) || options[:current_level] == 1
31
+ list = content_tag(options[:wrapper_tag], list.html_safe, list_options)
32
+ else
33
+ list = list.html_safe
34
+ end
35
+ end
36
+
37
+ # render link
38
+ link = ""
39
+ link = link_to(self.label, self.destination).html_safe if self.is_link? && !options[:group]
40
+
41
+ if on_valid_level?(options[:levels], options[:current_level])
42
+ if options[:current_level] == 1 || (self.is_group? && options[:group] == self.group_id)
43
+ list.html_safe
44
+ elsif options[:show] == :all || self.is_active?(request)
45
+ content_tag(options[:item_tag], link.to_s + list.to_s, html_options).to_s.html_safe
46
+ elsif self.is_link?
47
+ content_tag(options[:item_tag], link, html_options).to_s.html_safe
48
+ end
49
+ elsif self.is_active?(request)
50
+ list.html_safe
51
+ end
52
+ end
53
+
54
+ def render_sitemap(document, request, options = {})
55
+ if is_link?
56
+ unless self.destination[0...10] == "javascript"
57
+ document.url do
58
+ if self.destination[0...4] == "http"
59
+ document.loc self.destination
60
+ else
61
+ document.loc request.protocol + request.host_with_port + self.destination
62
+ end
63
+ document.changefreq "weekly"
64
+ end
65
+ end
66
+ end
67
+ self.items.each{ |item| item.render_sitemap(document, request, options) }
68
+ end
69
+
70
+ def is_active?(request)
71
+ has_active_descendant?(request) || paths_match?(request)
72
+ end
73
+
74
+ def has_active_descendant?(request, include_self = true)
75
+ self.items.each do |item|
76
+ return true if item.has_active_descendant?(request)
77
+ end
78
+ return true if paths_match?(request) if include_self
79
+ false
80
+ end
81
+
82
+ def count_active_descendants(request)
83
+ self.items.each do |item|
84
+ return item.count_active_descendants(request) + 1 if item.has_active_descendant?(request)
85
+ end
86
+
87
+ if (self.paths_match?(request) && !self.has_active_descendant?(request, false) && self.items.count > 0)
88
+ return 1
89
+ elsif (self.is_group? && !self.has_active_descendant?(request)) || (self.paths_match?(request) && !self.has_active_descendant?(request, false))
90
+ return 0
91
+ end
92
+ 0
93
+ end
94
+
95
+ def paths_match?(request)
96
+ request.fullpath == self.destination || request.url == self.destination if self.is_link?
97
+ end
98
+
99
+ def on_valid_level?(levels, current_level)
100
+ levels_to_i(levels).include?(current_level-1) || levels.empty?
101
+ end
102
+
103
+ def levels_to_i(levels_in_words)
104
+ levels_in_words.map{ |word| @@level_options.index(word.to_sym) + 1 }
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,31 @@
1
+ module Menumatic
2
+ module Navigation
3
+ module Item
4
+ class Base
5
+ attr_accessor :items, :options
6
+
7
+ include Menumatic::Navigation::Item::Renderers
8
+ include Menumatic::Navigation::Item::Navigators
9
+
10
+ def initialize(*args)
11
+ self.options = args.last
12
+ self.items = []
13
+ end
14
+
15
+ def is_link?
16
+ self.is_a? Menumatic::Navigation::Item::Link
17
+ end
18
+
19
+ def is_group?
20
+ self.is_a? Menumatic::Navigation::Item::Group
21
+ end
22
+
23
+ private
24
+ def add_item(item)
25
+ self.items << item
26
+ item
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,55 @@
1
+ module Menumatic
2
+ module Navigation
3
+ class Base
4
+ include ActionView::Helpers
5
+ @@navigations = {}
6
+ attr_accessor :id, :root
7
+
8
+ class << self
9
+ def navigate_to(label, destination, options = {})
10
+ if block_given?
11
+ item = self.get_instance.root.navigate_to(label, destination, options, &Proc.new)
12
+ else
13
+ item = self.get_instance.root.navigate_to(label, destination, options)
14
+ end
15
+ end
16
+
17
+ def group(id)
18
+ if block_given?
19
+ group = self.get_instance.root.group(id, &Proc.new)
20
+ else
21
+ group = self.get_instance.root.group(id)
22
+ end
23
+ end
24
+
25
+ def get_instance
26
+ id = self.name.split("Navigation").first.underscore.to_sym
27
+ @@navigations[id] = self.new(id) unless @@navigations.has_key?(id)
28
+ @@navigations[id]
29
+ end
30
+
31
+ def get(id)
32
+ unless @@navigations.has_key?(id)
33
+ Module.const_get("#{id.to_s.camelize}Navigation").get_instance
34
+ end
35
+ @@navigations[id]
36
+ end
37
+
38
+ def destroy_all
39
+ @@navigations = {}
40
+ end
41
+ end
42
+
43
+ def initialize(id)
44
+ self.id = id
45
+ self.root = Menumatic::Navigation::Item::Group.new("#{id}_root".to_sym)
46
+ end
47
+
48
+ def items
49
+ self.root.items
50
+ end
51
+
52
+ end
53
+ end
54
+ end
55
+
@@ -0,0 +1,7 @@
1
+ module ActionDispatch::Routing
2
+ class Mapper
3
+ def sitemap_for(navigation)
4
+ self.match 'sitemap.xml'=> 'menumatic/sitemap#index', :format => :xml, :navigation_id => navigation
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ module Menumatic
2
+ VERSION = "0.1.0"
3
+ end
data/lib/menumatic.rb ADDED
@@ -0,0 +1,23 @@
1
+ module Menumatic
2
+ module Helpers
3
+ autoload :NavigationHelper, 'menumatic/helpers/navigation_helper'
4
+ ActionController::Base.helper(Menumatic::Helpers::NavigationHelper)
5
+ end
6
+
7
+ module Navigation
8
+ module Item
9
+ autoload :Renderers, 'menumatic/navigation/item/renderers'
10
+ autoload :Navigators, 'menumatic/navigation/item/navigators'
11
+ autoload :Group, 'menumatic/navigation/item/group'
12
+ autoload :Link, 'menumatic/navigation/item/link'
13
+ autoload :Base, 'menumatic/navigation/item'
14
+ end
15
+ autoload :Base, 'menumatic/navigation'
16
+ end
17
+
18
+ #autoload :Mapper, 'menumatic/action_dispatch/routing/mapper'
19
+ #autoload :SitemapController, '../app/controllers/menumatic
20
+ end
21
+
22
+ require 'menumatic/rails/routes'
23
+ require 'menumatic/engine'
data/menumatic.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "menumatic/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "menumatic"
7
+ s.version = Menumatic::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Nicholas Bruning"]
10
+ s.email = ["nicholas@bruning.com.au"]
11
+ s.homepage = ""
12
+ s.summary = %q{Menumatic is a Rails 3 gem which aims to simplify building complex website navigation}
13
+ s.description = %q{Menumatic is a Rails 3 exclusive gem which aims to take all the fuss and clutter out of developing semantic, usable navigation menus.}
14
+
15
+ s.rubyforge_project = "menumatic"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+ end
data/spec/factories.rb ADDED
@@ -0,0 +1,6 @@
1
+ Factory.define :request do |f|
2
+ f.full_path '/'
3
+ f.host 'lvh.me'
4
+ f.port '3000'
5
+ f.url 'http://lvh.me:3000/'
6
+ end
data/spec/link_spec.rb ADDED
@@ -0,0 +1,52 @@
1
+ require 'spec_helper'
2
+ require 'active_resource/http_mock'
3
+
4
+ describe Menumatic::Navigation::Item::Link do
5
+
6
+ before :each do
7
+ @label = "Search"
8
+ @destination = "/search"
9
+ @options = {}
10
+ @link = Menumatic::Navigation::Item::Link.new(@label, @destination, @options)
11
+
12
+ ActiveResource::HttpMock.respond_to do |mock|
13
+ mock.get '/search', {}, ''
14
+ end
15
+ end
16
+
17
+ it "should have a label" do
18
+ @link.should respond_to(:label)
19
+ @link.label.should == @label
20
+ end
21
+
22
+ it "should have a destination" do
23
+ @link.should respond_to(:destination)
24
+ @link.destination.should == @destination
25
+ end
26
+
27
+ it "should be a link" do
28
+ @link.is_link?.should == true
29
+ end
30
+
31
+ it "should not be a group" do
32
+ @link.is_group?.should == false
33
+ end
34
+
35
+ it "should be active when destination is the same as the request path" do
36
+ request = ActiveResource::Request.new(:get, @link.destination)
37
+ @link.is_active?(request).should == true
38
+ end
39
+
40
+ it "should not be active when destination is not the same as the request path" do
41
+ @link.is_active?(request).should == false
42
+ end
43
+
44
+ it "should be able to parent links"
45
+ it "should be able to parent groups"
46
+
47
+ it "should render a list item containing only a link when it has no children"
48
+ it "should render a list item containing only a link when it has no active descendants"
49
+ it "should render a list item containing an active link when active"
50
+ it "should render a list item containing a list of its children when active"
51
+ it "should render a list item containing an active link and a list of its children when it has an active descendant"
52
+ end
@@ -0,0 +1,9 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require 'action_controller'
5
+ require 'menumatic'
6
+
7
+ RSpec.configure do |config|
8
+
9
+ end
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: menumatic
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Nicholas Bruning
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-03-08 00:00:00 +11:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: Menumatic is a Rails 3 exclusive gem which aims to take all the fuss and clutter out of developing semantic, usable navigation menus.
23
+ email:
24
+ - nicholas@bruning.com.au
25
+ executables: []
26
+
27
+ extensions: []
28
+
29
+ extra_rdoc_files: []
30
+
31
+ files:
32
+ - .DS_Store
33
+ - .autotest
34
+ - .gitignore
35
+ - .rspec
36
+ - Gemfile
37
+ - Gemfile.lock
38
+ - LICENSE
39
+ - README.md
40
+ - Rakefile
41
+ - TODO.md
42
+ - app/controllers/menumatic/sitemap_controller.rb
43
+ - app/views/menumatic/sitemap/index.xml.builder
44
+ - lib/.DS_Store
45
+ - lib/generators/menumatic/USAGE
46
+ - lib/generators/menumatic/navigation_generator.rb
47
+ - lib/generators/menumatic/templates/navigation.rb
48
+ - lib/generators/menumatic/templates/stylesheet.css
49
+ - lib/menumatic.rb
50
+ - lib/menumatic/.DS_Store
51
+ - lib/menumatic/engine.rb
52
+ - lib/menumatic/helpers/navigation_helper.rb
53
+ - lib/menumatic/navigation.rb
54
+ - lib/menumatic/navigation/.DS_Store
55
+ - lib/menumatic/navigation/item.rb
56
+ - lib/menumatic/navigation/item/group.rb
57
+ - lib/menumatic/navigation/item/link.rb
58
+ - lib/menumatic/navigation/item/navigators.rb
59
+ - lib/menumatic/navigation/item/renderers.rb
60
+ - lib/menumatic/rails/routes.rb
61
+ - lib/menumatic/version.rb
62
+ - menumatic.gemspec
63
+ - spec/factories.rb
64
+ - spec/link_spec.rb
65
+ - spec/spec_helper.rb
66
+ has_rdoc: true
67
+ homepage: ""
68
+ licenses: []
69
+
70
+ post_install_message:
71
+ rdoc_options: []
72
+
73
+ require_paths:
74
+ - lib
75
+ required_ruby_version: !ruby/object:Gem::Requirement
76
+ none: false
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ hash: 3
81
+ segments:
82
+ - 0
83
+ version: "0"
84
+ required_rubygems_version: !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ hash: 3
90
+ segments:
91
+ - 0
92
+ version: "0"
93
+ requirements: []
94
+
95
+ rubyforge_project: menumatic
96
+ rubygems_version: 1.3.7
97
+ signing_key:
98
+ specification_version: 3
99
+ summary: Menumatic is a Rails 3 gem which aims to simplify building complex website navigation
100
+ test_files:
101
+ - spec/factories.rb
102
+ - spec/link_spec.rb
103
+ - spec/spec_helper.rb