menumatic 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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