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 ADDED
@@ -0,0 +1,5 @@
1
+ 0.0.1
2
+
3
+ * "release earlier, release often"
4
+
5
+
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
+
@@ -0,0 +1,14 @@
1
+ require 'pathname'
2
+
3
+ module HMenu
4
+
5
+ def self.rootdir_pathname
6
+ Pathname.new(__FILE__).dirname.realpath + '../..'
7
+ end
8
+
9
+
10
+ VERSION = '0.1.0'
11
+ # TODO: manage symlinks...
12
+ ROOTDIR = self.rootdir_pathname.to_s
13
+
14
+ end
data/lib/hmenu/css.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'hmenu/constants'
2
+
3
+ module HMenu
4
+ module CSS
5
+ def self.out
6
+ File.read "#{::HMenu::ROOTDIR}/css/hmenu.css"
7
+ end
8
+ end
9
+ end
10
+
@@ -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
@@ -0,0 +1,10 @@
1
+ require 'hmenu/constants'
2
+
3
+ module HMenu
4
+ module JS
5
+ def self.out
6
+ File.read "#{::HMenu::ROOTDIR}/js/hmenu.js"
7
+ end
8
+ end
9
+ end
10
+
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
@@ -0,0 +1,11 @@
1
+ require 'hmenu/constants'
2
+
3
+ module HMenu
4
+ autoload :CSS, 'hmenu/css'
5
+ autoload :JS, 'hmenu/js'
6
+ autoload :Node, 'hmenu/node'
7
+ end
8
+
9
+
10
+
11
+
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
+