hierarchical_menu 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/Changelog +5 -0
- data/README.rdoc +67 -0
- data/css/hmenu.css +17 -0
- data/css/hmenu.more.example.css +59 -0
- data/example.rb +43 -0
- data/js/hmenu.js +98 -0
- data/lib/hmenu/constants.rb +14 -0
- data/lib/hmenu/css.rb +10 -0
- data/lib/hmenu/extensions/tree.rb +76 -0
- data/lib/hmenu/js.rb +10 -0
- data/lib/hmenu/node.rb +98 -0
- data/lib/hmenu.rb +11 -0
- metadata +88 -0
data/README.rdoc
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
= Hierarchical Menu
|
2
|
+
|
3
|
+
Hierarchical menu, based on <tt>rubytree gem</tt>. Outputs html (other formats
|
4
|
+
planned) with optional JavaScript show/hide.
|
5
|
+
|
6
|
+
== Synopsis
|
7
|
+
|
8
|
+
require 'hmenu'
|
9
|
+
|
10
|
+
root = HMenu::Node.new('ROOT')
|
11
|
+
|
12
|
+
Simple example:
|
13
|
+
|
14
|
+
root.add_path('/aaa/bbb/ccc/eee', {
|
15
|
+
:name => 'test2',
|
16
|
+
:href => '/xxx/yyy/2.html',
|
17
|
+
})
|
18
|
+
|
19
|
+
With HTML list generator:
|
20
|
+
|
21
|
+
html_ul_simple = root.to_html_ul
|
22
|
+
|
23
|
+
You can add any extra/custom information:
|
24
|
+
|
25
|
+
root.add_path('/aaa/bbb/ccc/ddd', {
|
26
|
+
:name => 'test1',
|
27
|
+
:href => '/xxx/yyy/zzz.html',
|
28
|
+
:extra_info => Object.new
|
29
|
+
})
|
30
|
+
|
31
|
+
And then match within a code block to ``mangle'' the output:
|
32
|
+
|
33
|
+
html_ul = root.to_html_ul do |node, output|
|
34
|
+
output[:name] += ' (extra_info is just an Object)' if
|
35
|
+
node.content.respond_to? :[] and
|
36
|
+
node.content[:extra_info].class == Object
|
37
|
+
end
|
38
|
+
|
39
|
+
Some Style (HMenu::CSS), and some JavaScript code (HMenu::JS) to show/hide
|
40
|
+
submenus:
|
41
|
+
|
42
|
+
puts <<END # you may use a template system like ERB if you wish...
|
43
|
+
<head>
|
44
|
+
<script type="text/javascript">
|
45
|
+
#{HMenu::JS.out}
|
46
|
+
</script>
|
47
|
+
<style type="text/css">
|
48
|
+
#{HMenu::CSS.out}
|
49
|
+
#{File.read File.join HMenu::ROOTDIR, 'css/hmenu.more.example.css'}
|
50
|
+
</style>
|
51
|
+
</head>
|
52
|
+
<body onload="reset_menus();">
|
53
|
+
#{html_ul}
|
54
|
+
</body>
|
55
|
+
END
|
56
|
+
|
57
|
+
== Installation
|
58
|
+
|
59
|
+
gem install hierarchical_menu
|
60
|
+
|
61
|
+
== Author
|
62
|
+
Copyright 2010 Guido De Rosa <mailto:guido.derosa@vemarsas.it>
|
63
|
+
|
64
|
+
=== License
|
65
|
+
Same of {RubyTree}[http://rubytree.rubyforge.org/].
|
66
|
+
|
67
|
+
|
data/css/hmenu.css
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
.hmenu li { list-style: none; /* line-height: 1.5em; padding-left: 0; */ }
|
2
|
+
.hmenu ul { /* padding-left: 1em; margin-left: 0; */ }
|
3
|
+
.hmenu-item { }
|
4
|
+
.hmenu-submenu { }
|
5
|
+
|
6
|
+
.hmenu-bullet, .hmenu-bullet-nochildren {
|
7
|
+
width: 1.3em;
|
8
|
+
float: left;
|
9
|
+
text-align: center;
|
10
|
+
display: inline;
|
11
|
+
}
|
12
|
+
|
13
|
+
.hmenu-content {
|
14
|
+
display: inline;
|
15
|
+
}
|
16
|
+
|
17
|
+
.hmenu-bullet {cursor: pointer;}
|
@@ -0,0 +1,59 @@
|
|
1
|
+
/*
|
2
|
+
* Strongly based on OnBoard by Guido De Rosa <guido.derosa@vemarsas.it>
|
3
|
+
* http://github.com/gderosa/onboard/blob/6185d2459e75b3796f678a957507d6c42266ba56/views/css/default.css.erb
|
4
|
+
*/
|
5
|
+
|
6
|
+
a, .hmenu-bullet {
|
7
|
+
color: blue;
|
8
|
+
text-decoration: none;
|
9
|
+
}
|
10
|
+
|
11
|
+
a {
|
12
|
+
font-weight: bold;
|
13
|
+
}
|
14
|
+
|
15
|
+
a:hover {
|
16
|
+
color: white;
|
17
|
+
background: blue;
|
18
|
+
}
|
19
|
+
|
20
|
+
.hmenu-bullet:hover {
|
21
|
+
color: green;
|
22
|
+
}
|
23
|
+
|
24
|
+
.hmenu-content {
|
25
|
+
padding: 0 0.3em;
|
26
|
+
}
|
27
|
+
|
28
|
+
.menu-content a {
|
29
|
+
padding-left: 0;
|
30
|
+
padding-right: 0;
|
31
|
+
margin-left: 0;
|
32
|
+
padding-right: 0;
|
33
|
+
}
|
34
|
+
|
35
|
+
li span.hmenu-selected, li div.hmenu-selected {
|
36
|
+
font-weight: bold;
|
37
|
+
color: green;
|
38
|
+
}
|
39
|
+
|
40
|
+
li.hmenu-selected > .hmenu-bullet,
|
41
|
+
li.hmenu-selected > .hmenu-bullet-nochildren {
|
42
|
+
color: green;
|
43
|
+
}
|
44
|
+
|
45
|
+
/* border-aligment hack... */
|
46
|
+
ul.hmenu li.hmenu-selected, ul.hmenu-submenu li.hmenu-selected {
|
47
|
+
border-left: 1px green solid;
|
48
|
+
padding-left: 4px; /* 4px + 1px = 5px */
|
49
|
+
}
|
50
|
+
ul.hmenu li, ul.hmenu-submenu li {
|
51
|
+
padding: 0 5px; /* 4px + 1px = 5px */
|
52
|
+
}
|
53
|
+
|
54
|
+
span.hmenu-root, div.hmenu-root {
|
55
|
+
font-weight: bold;
|
56
|
+
border: none;
|
57
|
+
}
|
58
|
+
|
59
|
+
|
data/example.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
$LOAD_PATH.unshift File.dirname(__FILE__) + '/lib'
|
2
|
+
|
3
|
+
require 'hmenu'
|
4
|
+
|
5
|
+
root = HMenu::Node.new('ROOT')
|
6
|
+
|
7
|
+
root.add_path('/aaa/bbb/ccc/ddd', {
|
8
|
+
:name => 'test1',
|
9
|
+
:href => '/xxx/yyy/zzz.html',
|
10
|
+
:extra_info => Object.new
|
11
|
+
})
|
12
|
+
|
13
|
+
root.add_path('/aaa/bbb/ccc/eee', {
|
14
|
+
:name => 'test2',
|
15
|
+
:href => '/xxx/yyy/2.html',
|
16
|
+
})
|
17
|
+
|
18
|
+
root.add_path('/aaa/fff/ccc/eee', {
|
19
|
+
:name => 'test2',
|
20
|
+
:href => '/xxx/yyy/2.html',
|
21
|
+
})
|
22
|
+
|
23
|
+
html_ul = root.to_html_ul do |node, output| # code block is optional!
|
24
|
+
output[:name] += ' (extra_info is just an Object)' if
|
25
|
+
node.content.respond_to? :[] and
|
26
|
+
node.content[:extra_info].class == Object
|
27
|
+
end
|
28
|
+
|
29
|
+
puts <<END # you may use a template system like ERB if you wish...
|
30
|
+
<head>
|
31
|
+
<script type="text/javascript">
|
32
|
+
#{HMenu::JS.out}
|
33
|
+
</script>
|
34
|
+
<style type="text/css">
|
35
|
+
#{HMenu::CSS.out}
|
36
|
+
#{File.read File.join HMenu::ROOTDIR, 'css/hmenu.more.example.css'}
|
37
|
+
</style>
|
38
|
+
</head>
|
39
|
+
<body onload="reset_menus();">
|
40
|
+
#{html_ul}
|
41
|
+
</body>
|
42
|
+
END
|
43
|
+
|
data/js/hmenu.js
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
// Copyright 2010 Guido De Rosa
|
2
|
+
// License: same of http://RubyTree.rubyforge.org/
|
3
|
+
|
4
|
+
// stongly based on http://nadeausoftware.com/articles/2007/12/latency_friendly_hierarchical_menus_using_unicode_bullets_and_bit_javascript
|
5
|
+
|
6
|
+
/*
|
7
|
+
ITEM = '\u25E6'; // WHITE BULLET
|
8
|
+
OPEN = '\u229F'; // SQUARED MINUS
|
9
|
+
CLOSE = '\u229E'; // SQUARED PLUS
|
10
|
+
|
11
|
+
ITEM = '\u25E6'; // WHITE BULLET
|
12
|
+
OPEN = '-'; // MINUS SIGN
|
13
|
+
CLOSE = '+'; // PLUS SIGN
|
14
|
+
*/
|
15
|
+
|
16
|
+
ITEM = '\u25E6'; // WHITE BULLET
|
17
|
+
// ITEM = '\u25CF'; // BLACK CIRCLE
|
18
|
+
OPEN = '\u25BC'; // BLACK DOWN-POINTING TRIANGLE
|
19
|
+
CLOSE = '\u25BA'; // BLACK RIGHT-POINTING TRIANGLE
|
20
|
+
|
21
|
+
|
22
|
+
function toggle_submenu(e) {
|
23
|
+
if (e.innerHTML==OPEN || e.innerHTML==CLOSE) {
|
24
|
+
e.innerHTML=(e.innerHTML==OPEN) ? CLOSE : OPEN;
|
25
|
+
for (var c, p=e.parentNode, i=0; c=p.childNodes[i]; i++)
|
26
|
+
if (c.tagName=='UL') c.style.display=(c.style.display=='none') ? 'block' : 'none';
|
27
|
+
}
|
28
|
+
}
|
29
|
+
|
30
|
+
function reset_menus() {
|
31
|
+
var li_tags=document.getElementsByTagName('LI');
|
32
|
+
for (var li, i=0; li=li_tags[i]; i++) {
|
33
|
+
if (li.className.match('hmenu-item')) {
|
34
|
+
for (var c, j=0; c=li.childNodes[j]; j++) {
|
35
|
+
if (c.className.match('hmenu-bullet')) {
|
36
|
+
c.innerHTML=ITEM;
|
37
|
+
}
|
38
|
+
}
|
39
|
+
}
|
40
|
+
if (li.className.match('hmenu-submenu')) {
|
41
|
+
for (var c, j=0; c=li.childNodes[j]; j++) {
|
42
|
+
if (
|
43
|
+
c.tagName == 'UL' &&
|
44
|
+
any_descendant_className_match(c, 'hmenu-selected')
|
45
|
+
) {
|
46
|
+
expand(c);
|
47
|
+
} else if (
|
48
|
+
c.className.match('hmenu-bullet') &&
|
49
|
+
!c.parentNode.className.match('hmenu-selected') &&
|
50
|
+
//strict inequality
|
51
|
+
any_descendant_className_match(c.parentNode, 'hmenu-selected')
|
52
|
+
) {
|
53
|
+
expand(c);
|
54
|
+
} else {
|
55
|
+
collapse(c);
|
56
|
+
}
|
57
|
+
}
|
58
|
+
}
|
59
|
+
}
|
60
|
+
}
|
61
|
+
|
62
|
+
function collapse(e) {
|
63
|
+
if (e.className.match('hmenu-bullet')) {
|
64
|
+
e.innerHTML=CLOSE;
|
65
|
+
}
|
66
|
+
else if (e.tagName=='UL') {
|
67
|
+
e.style.display = 'none';
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
function expand(e) {
|
72
|
+
if (e.className.match('hmenu-bullet')) {
|
73
|
+
e.innerHTML=OPEN;
|
74
|
+
}
|
75
|
+
else if (e.tagName=='UL') {
|
76
|
+
e.style.display = 'block';
|
77
|
+
}
|
78
|
+
}
|
79
|
+
|
80
|
+
function any_descendant_className_match(element, klassName) {
|
81
|
+
if (element.className && element.className.match(klassName)) {
|
82
|
+
return true;
|
83
|
+
}
|
84
|
+
else if (element.hasChildNodes) {
|
85
|
+
for (var c, i=0; c=element.childNodes[i]; i++) {
|
86
|
+
if (any_descendant_className_match(c, klassName)) { // recursion
|
87
|
+
return true;
|
88
|
+
}
|
89
|
+
}
|
90
|
+
}
|
91
|
+
return false;
|
92
|
+
}
|
93
|
+
|
94
|
+
function debug(s) {
|
95
|
+
jsdbg = document.getElementById('jsdebug');
|
96
|
+
jsdbg.innerHTML = jsdbg.innerHTML + s;
|
97
|
+
}
|
98
|
+
|
data/lib/hmenu/css.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
# Copyright 2009, Guido De Rosa <job at guidoderosa . net>
|
2
|
+
# Distributed under the same terms of 'rubytree' --
|
3
|
+
# http://rubytre.rubyforge.org/
|
4
|
+
|
5
|
+
require 'tree'
|
6
|
+
|
7
|
+
module Tree
|
8
|
+
class TreeNode
|
9
|
+
def add_recursive(path, content)
|
10
|
+
#
|
11
|
+
# A leading slash in the path means that it is absolute (i.e. refers
|
12
|
+
# to the tree root)
|
13
|
+
#
|
14
|
+
# path may be an Array (instead of String), but this is intended for
|
15
|
+
# "private" use only (i.e. recursive calls)
|
16
|
+
#
|
17
|
+
if path.respond_to? :split
|
18
|
+
path = path.split('/')
|
19
|
+
end
|
20
|
+
if path[0] == "" # as a result of a leading slash in path string
|
21
|
+
path.shift
|
22
|
+
return self.root.add_recursive(path, content)
|
23
|
+
end
|
24
|
+
if path.length == 1
|
25
|
+
begin
|
26
|
+
node = self.class.new(path[0], content) # it may be a derived class
|
27
|
+
add node
|
28
|
+
return node
|
29
|
+
rescue RuntimeError # node already exists
|
30
|
+
self[path[0]].content = content
|
31
|
+
end
|
32
|
+
else
|
33
|
+
begin
|
34
|
+
add self.class.new(path[0], nil) # it may be a derived class
|
35
|
+
rescue RuntimeError # node already exists
|
36
|
+
# do nothing
|
37
|
+
end
|
38
|
+
first = path.shift
|
39
|
+
self[first].add_recursive(path, content)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
alias add_path add_recursive
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# example/test :
|
47
|
+
|
48
|
+
# You should get:
|
49
|
+
# -> like ("awesome content")
|
50
|
+
# /
|
51
|
+
# ROOT -> path -> to -> anything -> I -<
|
52
|
+
# \ \
|
53
|
+
# \ -> like2 ("awesome content2")
|
54
|
+
# \ \
|
55
|
+
# -> absolute -> path ("abs_path_content") \
|
56
|
+
# \
|
57
|
+
# sub
|
58
|
+
# |
|
59
|
+
# path
|
60
|
+
# ("sub_path_content")
|
61
|
+
if $0 == __FILE__
|
62
|
+
# TODO: use Ruby test frameworks
|
63
|
+
require 'pp'
|
64
|
+
root = Tree::TreeNode.new("ROOT", "my content")
|
65
|
+
node1 = root.add_recursive("path/to/anything/I/like", "awesome content")
|
66
|
+
node2 = root.add_recursive("/path/to/anything/I/like2", "awesome content2")
|
67
|
+
pp root
|
68
|
+
puts
|
69
|
+
pp root['path']['to']['anything']['I']['like'].content
|
70
|
+
pp root['path']['to']['anything']['I']['like2'].content
|
71
|
+
|
72
|
+
node2.add_recursive("sub/path", "sub_path_content")
|
73
|
+
node2.add_recursive("/absolute/path", "abs_path_content")
|
74
|
+
pp root['path']['to']['anything']['I']['like2']['sub']['path'].content
|
75
|
+
pp root['absolute']['path'].content
|
76
|
+
end
|
data/lib/hmenu/js.rb
ADDED
data/lib/hmenu/node.rb
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
# Thanks to: http://nadeausoftware.com/articles/2007/12/latency_friendly_hierarchical_menus_using_unicode_bullets_and_bit_javascript
|
2
|
+
|
3
|
+
require 'tree'
|
4
|
+
require 'hmenu/extensions/tree'
|
5
|
+
|
6
|
+
module HMenu
|
7
|
+
class Node < Tree::TreeNode
|
8
|
+
|
9
|
+
def to_html_ul(&block)
|
10
|
+
ctag = 'div'
|
11
|
+
btag = 'div'
|
12
|
+
|
13
|
+
o = content ? content.clone : nil
|
14
|
+
if block.respond_to? :call
|
15
|
+
block.call(self, o)
|
16
|
+
end
|
17
|
+
|
18
|
+
s = ""
|
19
|
+
|
20
|
+
hmenu_content_class = "hmenu-content"
|
21
|
+
|
22
|
+
hmenu_content_class << " hmenu-root" if isRoot?
|
23
|
+
|
24
|
+
if o
|
25
|
+
hmenu_content_class << ' ' << o[:extra_class] if o[:extra_class]
|
26
|
+
s << "<#{ctag} class=\"#{hmenu_content_class}\" title=\"#{(o[:desc] || '')}\">"
|
27
|
+
if o[:href]
|
28
|
+
s <<
|
29
|
+
"<a href=\"#{o[:href]}\">#{o[:name]}</a>"
|
30
|
+
elsif o[:name]
|
31
|
+
s << (o[:name] || '')
|
32
|
+
end
|
33
|
+
s << "</#{ctag}>"
|
34
|
+
else
|
35
|
+
s << "<#{ctag} class=\"#{hmenu_content_class}\">" << name.capitalize << "</#{ctag}>"
|
36
|
+
end
|
37
|
+
|
38
|
+
if hasChildren?
|
39
|
+
|
40
|
+
if isRoot?
|
41
|
+
s += '<ul class="hmenu">'
|
42
|
+
else
|
43
|
+
s += "<ul>"
|
44
|
+
end
|
45
|
+
|
46
|
+
children.sort.each do |child|
|
47
|
+
|
48
|
+
o = child.content ? child.content.clone : nil
|
49
|
+
if block.respond_to? :call
|
50
|
+
block.call(child, o)
|
51
|
+
end
|
52
|
+
|
53
|
+
css_li_class =
|
54
|
+
child.hasChildren? ?
|
55
|
+
'hmenu-submenu' :
|
56
|
+
'hmenu-item'
|
57
|
+
css_li_class << ' ' << o[:extra_class] if o and o[:extra_class]
|
58
|
+
css_bullet_class =
|
59
|
+
child.hasChildren? ?
|
60
|
+
'hmenu-bullet' :
|
61
|
+
'hmenu-bullet-nochildren'
|
62
|
+
|
63
|
+
s += "<li class=\"#{css_li_class}\">" << "<#{btag} class=\"#{css_bullet_class}\" onclick=\"toggle_submenu(this);\"></#{btag}>" << child.to_html_ul(&block) << "</li>"
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
s += "</ul>"
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
return s
|
72
|
+
end
|
73
|
+
|
74
|
+
def <=>(other) # for sorting
|
75
|
+
n <=> other.n
|
76
|
+
end
|
77
|
+
|
78
|
+
def n
|
79
|
+
begin
|
80
|
+
content[:n] ? content[:n] : 0
|
81
|
+
rescue
|
82
|
+
0
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def mangle_output(o, &block)
|
87
|
+
unless o
|
88
|
+
if block.respond_to? :call
|
89
|
+
o = {}
|
90
|
+
block.call(self, o)
|
91
|
+
else
|
92
|
+
o = content.dup
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
end
|
data/lib/hmenu.rb
ADDED
metadata
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hierarchical_menu
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
version: 0.1.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Guido De Rosa
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-09-27 00:00:00 +02:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: rubytree
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 0
|
30
|
+
version: "0"
|
31
|
+
type: :runtime
|
32
|
+
version_requirements: *id001
|
33
|
+
description: Ruby Tree based hierarchical menus with HTML output and JavaScript show/hide
|
34
|
+
email: guido.derosa@vemarsas.it
|
35
|
+
executables: []
|
36
|
+
|
37
|
+
extensions: []
|
38
|
+
|
39
|
+
extra_rdoc_files:
|
40
|
+
- README.rdoc
|
41
|
+
files:
|
42
|
+
- README.rdoc
|
43
|
+
- example.rb
|
44
|
+
- Changelog
|
45
|
+
- css/hmenu.css
|
46
|
+
- css/hmenu.more.example.css
|
47
|
+
- js/hmenu.js
|
48
|
+
- lib/hmenu.rb
|
49
|
+
- lib/hmenu/extensions/tree.rb
|
50
|
+
- lib/hmenu/constants.rb
|
51
|
+
- lib/hmenu/css.rb
|
52
|
+
- lib/hmenu/js.rb
|
53
|
+
- lib/hmenu/node.rb
|
54
|
+
has_rdoc: true
|
55
|
+
homepage: http://github.com/gderosa/hierarchical_menu
|
56
|
+
licenses: []
|
57
|
+
|
58
|
+
post_install_message:
|
59
|
+
rdoc_options:
|
60
|
+
- --main
|
61
|
+
- README.rdoc
|
62
|
+
require_paths:
|
63
|
+
- lib
|
64
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
segments:
|
70
|
+
- 0
|
71
|
+
version: "0"
|
72
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
segments:
|
78
|
+
- 0
|
79
|
+
version: "0"
|
80
|
+
requirements: []
|
81
|
+
|
82
|
+
rubyforge_project:
|
83
|
+
rubygems_version: 1.3.7
|
84
|
+
signing_key:
|
85
|
+
specification_version: 3
|
86
|
+
summary: Hierarchical menus with html output
|
87
|
+
test_files: []
|
88
|
+
|