makandra-navy 0.1 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +116 -0
- data/assets/cucumber/navy_steps.rb +36 -0
- data/assets/javascripts/navy.js +81 -0
- data/lib/navy/version.rb +1 -1
- metadata +7 -3
data/README.markdown
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
Navy
|
2
|
+
====
|
3
|
+
|
4
|
+
Navy support rendering for horizontal, multi-level navigation bars. Sections are dynamic and can depend on user permissions etc.
|
5
|
+
|
6
|
+
Some of the features are:
|
7
|
+
|
8
|
+
- A simple but powerful DSL to describe the navigation structure
|
9
|
+
- Subnavigations can be previewed by clicking an expand arrow
|
10
|
+
- Sections that don't fit into the navigation bar are automatically moved into a dropdown
|
11
|
+
|
12
|
+
|
13
|
+
How it works
|
14
|
+
-----------
|
15
|
+
|
16
|
+
The gem provides the DSL to specify the navigation structure as well as a renderer that outputs appropriate HTML.
|
17
|
+
|
18
|
+
To style it, we provide a sample .sass stylesheet you have to copy and include into your stylesheet, as well as adapt to your design.
|
19
|
+
|
20
|
+
The javascript functionality is provided in navy.js that you have to copy and include in your application.
|
21
|
+
|
22
|
+
|
23
|
+
Caveats
|
24
|
+
-------
|
25
|
+
|
26
|
+
The gem should be considered in an alpha state.
|
27
|
+
|
28
|
+
Styles are not very flexible yet, it might be hard to adapt them to your needs.
|
29
|
+
|
30
|
+
The standard styles do not work well with old browsers (e.g. IE 8).
|
31
|
+
|
32
|
+
The JavaScript features are somewhat dependent on the CSS (to determine when sections will be collapsed). In particular, you have to make sure that the dropdown arrow floats correctly right of the navigation sections.
|
33
|
+
|
34
|
+
Some assets have to be copied manually, there is no generator yet.
|
35
|
+
|
36
|
+
|
37
|
+
Installation
|
38
|
+
------------
|
39
|
+
|
40
|
+
Put this into your Gemfile:
|
41
|
+
|
42
|
+
gem 'makandra-navy', :require => 'navy'
|
43
|
+
|
44
|
+
|
45
|
+
Copy stylesheets, javascripts and (perhaps) cucumber steps from /assets into your project.
|
46
|
+
|
47
|
+
|
48
|
+
|
49
|
+
Usage
|
50
|
+
-----
|
51
|
+
|
52
|
+
Navigation structure is defined with a class like this (somewhere in your load path):
|
53
|
+
|
54
|
+
class Navigation
|
55
|
+
include Navy::Description
|
56
|
+
|
57
|
+
navigation :main do
|
58
|
+
|
59
|
+
section :dashboard, "Dashboard", root_path
|
60
|
+
|
61
|
+
if current_user.admin?
|
62
|
+
section :admin, 'Admin' do
|
63
|
+
section :admin_users, "Users", admin_users_path
|
64
|
+
|
65
|
+
if current_user.may_admin_projects?
|
66
|
+
section :admin_projects, "Projects", admin_projects_path
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
navigation :footer do
|
73
|
+
section :terms, "Terms and Conditions", terms_and_conditions_path
|
74
|
+
section :imprint, "Imprint", imprint_path
|
75
|
+
end
|
76
|
+
|
77
|
+
navigation :user do |user|
|
78
|
+
section :settings, "Settings", user_settings_path(user)
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
This is all evaluated in your view context, so helpers will work.
|
85
|
+
|
86
|
+
To actually render a navigation, do this in your view:
|
87
|
+
|
88
|
+
<%= render_navigation Navigation.main, :collapse => true %>
|
89
|
+
|
90
|
+
<%= render_navigation Navigation.footer %>
|
91
|
+
|
92
|
+
<%= render_navigation Navigation.user(current_user) %>
|
93
|
+
|
94
|
+
The `:collapse => true` option enables the automatic moving of navigation sections into a dropdown if they do not fit.
|
95
|
+
|
96
|
+
|
97
|
+
Cucumber
|
98
|
+
-------
|
99
|
+
|
100
|
+
There are some cucumber steps in /assets.
|
101
|
+
|
102
|
+
The most important one is:
|
103
|
+
|
104
|
+
|
105
|
+
When I open the "Admin" section
|
106
|
+
|
107
|
+
|
108
|
+
To open submenu entries, use
|
109
|
+
|
110
|
+
When I open the "Admin > Projects" section
|
111
|
+
|
112
|
+
|
113
|
+
Credits
|
114
|
+
-------
|
115
|
+
|
116
|
+
Tobias Kraze, Henning Koch
|
@@ -0,0 +1,36 @@
|
|
1
|
+
When /^I open the "([^"]*)" (?:section|tab)$/ do |all_labels|
|
2
|
+
labels = all_labels.split('>').collect(&:squish)
|
3
|
+
if Capybara.current_session.driver.is_a? Capybara::Driver::Selenium
|
4
|
+
if labels.size == 2
|
5
|
+
When "I expand the \"#{labels.first}\" section"
|
6
|
+
end
|
7
|
+
When "I follow \"#{labels.last}\" within \".navy-level-#{labels.size}\""
|
8
|
+
else
|
9
|
+
opens = nil
|
10
|
+
section = nil
|
11
|
+
labels.each_with_index do |label, index|
|
12
|
+
scope = "div[data-navy-navigation-level='#{index + 1}']"
|
13
|
+
if opens
|
14
|
+
scope << "[data-navy-opened-by='#{opens}']"
|
15
|
+
end
|
16
|
+
scope << ' a'
|
17
|
+
page.should have_css(scope, :text => label)
|
18
|
+
section = find(scope, :text => label)
|
19
|
+
opens = section["data-navy-opens"]
|
20
|
+
end
|
21
|
+
section.click
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
When /^I expand the "([^"]*)" (?:section|tab)$/ do |label|
|
26
|
+
page.execute_script("$('.navy-level-1 .navy-section:contains(\"#{label}\") .navy-section-expander').click()")
|
27
|
+
end
|
28
|
+
|
29
|
+
Then /^there should( not)? be a "([^"]*)" (?:section|tab)$/ do |negate, label|
|
30
|
+
expectation = negate ? "should_not" : "should"
|
31
|
+
page.send(expectation, have_css(".navy-navigation", :text => label))
|
32
|
+
end
|
33
|
+
|
34
|
+
Then /^I should be in the "([^"]*)" (?:section|tab)$/ do |label|
|
35
|
+
page.should have_css(".navy-navigation .navy-active", :text => label)
|
36
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
(function() {
|
2
|
+
|
3
|
+
function unexpand($navigation, level) {
|
4
|
+
$navigation.find('.navy-navigation-bar[data-navy-navigation-level="' + (level + 1) + '"].navy-hidden').hide();
|
5
|
+
$navigation.find('.navy-navigation-bar[data-navy-navigation-level="' + (level + 1) + '"].navy-current').show();
|
6
|
+
var $thisBar = $navigation.find('.navy-navigation-bar[data-navy-navigation-level="' + level + '"]');
|
7
|
+
$thisBar.find('.navy-section-expanded').removeClass('navy-section-expanded navy-active');
|
8
|
+
$thisBar.find('.navy-section.navy-current').addClass('navy-active');
|
9
|
+
}
|
10
|
+
|
11
|
+
function expand($navigation, level, idToOpen) {
|
12
|
+
unexpand($navigation, level);
|
13
|
+
$navigation.find('.navy-navigation-bar[data-navy-navigation-level="' + (level + 1) + '"]').hide();
|
14
|
+
$navigation.find('.navy-navigation-bar[data-navy-opened-by="' + idToOpen + '"][data-navy-navigation-level="' + (level + 1) + '"]').show();
|
15
|
+
var $thisBar = $navigation.find('.navy-navigation-bar[data-navy-navigation-level="' + level + '"]');
|
16
|
+
$thisBar.find('.navy-current').removeClass('navy-active');
|
17
|
+
}
|
18
|
+
|
19
|
+
function layout() {
|
20
|
+
$('.navy-navigation .navy-navigation-dropdown').each(function() {
|
21
|
+
var $dropdown = $(this);
|
22
|
+
var $bar = $dropdown.closest('.navy-navigation-bar');
|
23
|
+
var $layouted_sections = $bar.find('.navy-layouted-sections');
|
24
|
+
var $dropdown_sections = $bar.find('.navy-dropdown-sections');
|
25
|
+
$dropdown_sections.find('.navy-section').appendTo($layouted_sections);
|
26
|
+
if ( $layouted_sections.find('.navy-section:last').offset().top > $layouted_sections.find('.navy-section:first').offset().top ) {
|
27
|
+
var barTop = $bar.offset().top;
|
28
|
+
while ( $dropdown.offset().top > barTop ) {
|
29
|
+
var $last_section = $layouted_sections.find('.navy-section:not(.navy-current):last')
|
30
|
+
$last_section.detach().prependTo($dropdown_sections);
|
31
|
+
if ( $last_section.length == 0 ) break;
|
32
|
+
}
|
33
|
+
}
|
34
|
+
if ( $dropdown_sections.find('.navy-section').length > 0 ) {
|
35
|
+
$dropdown.css('visibility', 'visible');
|
36
|
+
} else {
|
37
|
+
$dropdown.css('visibility', 'hidden');
|
38
|
+
}
|
39
|
+
});
|
40
|
+
}
|
41
|
+
|
42
|
+
function sectionExpanderClicked() {
|
43
|
+
var $section = $(this).closest('.navy-section');
|
44
|
+
var level = Number($section.closest('.navy-navigation-bar').data('navy-navigation-level'));
|
45
|
+
var openId = $section.data('navy-opens');
|
46
|
+
if ( $section.hasClass('navy-section-expanded') ) {
|
47
|
+
unexpand($section.closest('.navy-navigation'), level, openId);
|
48
|
+
} else {
|
49
|
+
expand($section.closest('.navy-navigation'), level, openId);
|
50
|
+
$section.addClass('navy-section-expanded navy-active');
|
51
|
+
}
|
52
|
+
return false;
|
53
|
+
}
|
54
|
+
|
55
|
+
function navigationDropdownClicked() {
|
56
|
+
var $dropdownExpander = $(this);
|
57
|
+
var $dropdown = $dropdownExpander.closest('.navy-navigation-dropdown');
|
58
|
+
if ( $dropdownExpander.hasClass('navy-section-expanded') ) {
|
59
|
+
$dropdownExpander.removeClass('navy-section-expanded navy-active');
|
60
|
+
$dropdown.find('.navy-dropdown-sections').hide();
|
61
|
+
} else {
|
62
|
+
$dropdownExpander.addClass('navy-section-expanded navy-active');
|
63
|
+
$dropdown.find('.navy-dropdown-sections').show();
|
64
|
+
}
|
65
|
+
}
|
66
|
+
|
67
|
+
function init() {
|
68
|
+
$(function() {
|
69
|
+
$('.navy-navigation .navy-section-expander').live('click', sectionExpanderClicked);
|
70
|
+
|
71
|
+
// difficult to handle in selenium, since it now depends on browser width
|
72
|
+
$('.navy-navigation .navy-dropdown-expander').live('click', navigationDropdownClicked);
|
73
|
+
|
74
|
+
$(window).resize(layout);
|
75
|
+
|
76
|
+
layout();
|
77
|
+
});
|
78
|
+
}
|
79
|
+
|
80
|
+
return { init: init, unexpand: unexpand };
|
81
|
+
})().init();
|
data/lib/navy/version.rb
CHANGED
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: makandra-navy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 25
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 1
|
9
|
-
|
9
|
+
- 1
|
10
|
+
version: 0.1.1
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Tobias Kraze
|
@@ -15,7 +16,7 @@ autorequire:
|
|
15
16
|
bindir: bin
|
16
17
|
cert_chain: []
|
17
18
|
|
18
|
-
date: 2012-04-
|
19
|
+
date: 2012-04-20 00:00:00 Z
|
19
20
|
dependencies:
|
20
21
|
- !ruby/object:Gem::Dependency
|
21
22
|
name: actionpack
|
@@ -43,7 +44,10 @@ extra_rdoc_files: []
|
|
43
44
|
files:
|
44
45
|
- .gitignore
|
45
46
|
- Gemfile
|
47
|
+
- README.markdown
|
46
48
|
- Rakefile
|
49
|
+
- assets/cucumber/navy_steps.rb
|
50
|
+
- assets/javascripts/navy.js
|
47
51
|
- assets/sass/_navy.sass
|
48
52
|
- lib/navy.rb
|
49
53
|
- lib/navy/description.rb
|