rocket_navigation 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,10 @@
1
+ module RocketNavigation
2
+ class Railtie < ::Rails::Railtie
3
+ initializer 'rocket_navigation.init' do |app|
4
+ ActionController::Base.send(:include, RocketNavigation::Helpers)
5
+ RocketNavigation::Helpers.instance_methods.each do |m|
6
+ ActionController::Base.send(:helper_method, m.to_sym)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,13 @@
1
+ require 'rocket_navigation/helpers'
2
+ require 'rocket_navigation/renderer/base'
3
+
4
+ module RocketNavigation
5
+ module Renderer
6
+ autoload :List, 'rocket_navigation/renderer/list'
7
+ autoload :Links, 'rocket_navigation/renderer/links'
8
+ autoload :Breadcrumbs, 'rocket_navigation/renderer/breadcrumbs'
9
+ autoload :BreadcrumbsOnRails, 'rocket_navigation/renderer/breadcrumbs_on_rails'
10
+ autoload :Text, 'rocket_navigation/renderer/text'
11
+ autoload :Json, 'rocket_navigation/renderer/json'
12
+ end
13
+ end
@@ -0,0 +1,159 @@
1
+ require 'forwardable'
2
+
3
+ module RocketNavigation
4
+ module Renderer
5
+ # This is the base class for all renderers.
6
+ #
7
+ # A renderer is responsible for rendering an ItemContainer and its
8
+ # containing items to HTML.
9
+ class Base
10
+ extend Forwardable
11
+ attr_reader :container, :options
12
+
13
+ def_delegators :container, :view_context
14
+ def_delegators :view_context, :link_to, :content_tag
15
+
16
+ def initialize(container, options = {})
17
+ @container = container
18
+ @options = options
19
+ end
20
+
21
+ def selected_class(type)
22
+ container.selected_class[type] || options[:selected_class][type]
23
+ end
24
+
25
+ def container_html
26
+ @container_html ||= container.container_html.merge(options[:container_html] || {})
27
+ end
28
+
29
+ # override this method if needed
30
+ def container_options
31
+ container_html
32
+ end
33
+
34
+ def base_item_html
35
+ @base_item_html ||= container.item_html.merge(options[:item_html] || {})
36
+ end
37
+
38
+ def item_html(item)
39
+ classes = Array.wrap(base_item_html[:class] || [])
40
+ if item.selected?
41
+ classes.push(selected_class(:item))
42
+ end
43
+ if item.active_branch?
44
+ classes.push(selected_class(:branch))
45
+ end
46
+
47
+ base_item_html.except(:class).merge({
48
+ class: classes.reject { |c| c.nil? }
49
+ })
50
+ end
51
+
52
+ # override this method if needed
53
+ def item_options(item)
54
+ item_html(item)
55
+ end
56
+
57
+ def base_link_html
58
+ @base_link_html ||= container.link_html.merge(options[:link_html] || {})
59
+ end
60
+
61
+ def link_html(item)
62
+ classes = Array.wrap(base_link_html[:class] || [])
63
+ if item.selected?
64
+ classes.push(selected_class(:link))
65
+ end
66
+ ret = base_link_html.except(:class)
67
+ ret.merge!({
68
+ class: classes.reject { |c| c.nil? }
69
+ })
70
+
71
+ unless item.method.blank?
72
+ ret.merge!({
73
+ method: method
74
+ })
75
+ end
76
+ ret
77
+ end
78
+
79
+ # override this method if needed
80
+ def link_options(item)
81
+ link_html(item)
82
+ end
83
+
84
+ def expand_all?
85
+ !options.key?(:expand_all) || options[:expand_all] == false
86
+ end
87
+
88
+ def level
89
+ options[:level] || :all
90
+ end
91
+
92
+ def skip_if_empty?
93
+ !!options[:skip_if_empty]
94
+ end
95
+
96
+ def include_sub_navigation?(item)
97
+ consider_sub_navigation?(item) && expand_sub_navigation?(item)
98
+ end
99
+
100
+ def render_sub_navigation_for(item)
101
+ item.sub_navigation.render(options)
102
+ end
103
+
104
+ # Renders the specified ItemContainer to HTML.
105
+ #
106
+ # When implementing a renderer, please consider to call
107
+ # include_sub_navigation? to determine whether an item's sub_navigation
108
+ # should be rendered or not.
109
+ def render(item_container)
110
+ fail NotImplementedError, 'subclass responsibility'
111
+ end
112
+
113
+ def consider_sub_navigation?(item)
114
+ return false unless item.sub_navigation
115
+
116
+ case level
117
+ when :all
118
+ true
119
+ when Range
120
+ item.sub_navigation.level <= level.max
121
+ else
122
+ false
123
+ end
124
+ end
125
+
126
+ def expand_sub_navigation?(item)
127
+ expand_all? || item.selected?
128
+ end
129
+
130
+ # to allow overriding when there is specific logic determining
131
+ # when a link should not be rendered (eg. breadcrumbs renderer
132
+ # does not render the final breadcrumb as a link when instructed
133
+ # not to do so.)
134
+ def suppress_link?(item)
135
+ item.url.nil?
136
+ end
137
+
138
+ # determine and return link or static content depending on
139
+ # item/renderer conditions.
140
+ def tag_for(item)
141
+ if suppress_link?(item)
142
+ suppressed_tag_for(item)
143
+ else
144
+ active_tag_for(item)
145
+ end
146
+ end
147
+
148
+ # render an item as a non-active link (span)
149
+ def suppressed_tag_for(item)
150
+ content_tag('span', item.name, link_options(item).except(:method))
151
+ end
152
+
153
+ # render an item as an active link (a)
154
+ def active_tag_for(item)
155
+ link_to(item.name, item.url, link_options(item))
156
+ end
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,58 @@
1
+ module RocketNavigation
2
+ module Renderer
3
+ # Renders an ItemContainer as a <div> element and its containing items as
4
+ # <a> elements.
5
+ # It only renders 'selected' elements.
6
+ #
7
+ # By default, the renderer sets the item's key as dom_id for the rendered
8
+ # <a> element unless the config option <tt>autogenerate_item_ids</tt> is
9
+ # set to false.
10
+ #
11
+ # The id can also be explicitely specified by setting the id in the
12
+ # html-options of the 'item' method in the config/navigation.rb file.
13
+ # The ItemContainer's dom_attributes are applied to the surrounding <div>
14
+ # element.
15
+ class Breadcrumbs < RocketNavigation::Renderer::Base
16
+ def render(item_container)
17
+ content = a_tags(item_container)
18
+ content_tag(
19
+ :div,
20
+ prefix_for(content) + content,
21
+ container_html
22
+ )
23
+ end
24
+
25
+ protected
26
+
27
+ def a_tags(item_container)
28
+ list = ActiveSupport::SafeBuffer.new
29
+ item_container.items.each do |item|
30
+ next unless item.selected?
31
+ list << tag_for(item)
32
+
33
+ if include_sub_navigation?(item)
34
+ list << join_with
35
+ list << a_tags(item.sub_navigation)
36
+ end
37
+ end
38
+ list
39
+ end
40
+
41
+ def join_with
42
+ @join_with ||= options[:join_with] || ' '.html_safe
43
+ end
44
+
45
+ def suppress_link?(item)
46
+ super || (options[:static_leaf] && item.active_leaf?)
47
+ end
48
+
49
+ def prefix_for(content)
50
+ if !content.empty? && options[:prefix]
51
+ options[:prefix]
52
+ else
53
+ ''
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,27 @@
1
+ module RocketNavigation
2
+ module Renderer
3
+ # Renders an ItemContainer as a <div> element and its containing items as
4
+ # <a> elements.
5
+ # It only renders 'selected' elements.
6
+ #
7
+ # By default, the renderer sets the item's key as dom_id for the rendered
8
+ # <a> element unless the config option <tt>autogenerate_item_ids</tt> is
9
+ # set to false.
10
+ #
11
+ # The id can also be explicitely specified by setting the id in the
12
+ # html-options of the 'item' method in the config/navigation.rb file.
13
+ # The ItemContainer's dom_attributes are applied to the surrounding <div>
14
+ # element.
15
+ class BreadcrumbsOnRails < RocketNavigation::Renderer::Base
16
+ def render(item_container)
17
+ item_container.items.each do |item|
18
+ next unless item.selected?
19
+ add_breadcrumb(item.name, item.url, item_html(item))
20
+ if include_sub_navigation?(item)
21
+ render(item.sub_navigation)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,29 @@
1
+ require 'json'
2
+
3
+ module RocketNavigation
4
+ module Renderer
5
+ # Renders the navigation items as a object tree serialized as a json string,
6
+ # can also output raw ruby Hashes
7
+ class Json < RocketNavigation::Renderer::Base
8
+ def render(item_container)
9
+ results = hash_render(item_container)
10
+ options[:as_hash] ? results : results.to_json
11
+ end
12
+
13
+ private
14
+
15
+ def hash_render(item_container)
16
+ return nil unless item_container
17
+
18
+ item_container.items.map do |item|
19
+ {
20
+ items: hash_render(item.sub_navigation),
21
+ name: item.name,
22
+ selected: item.selected?,
23
+ url: item.url
24
+ }
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,35 @@
1
+ module RocketNavigation
2
+ module Renderer
3
+ # Renders an ItemContainer as a <div> element and its containing items as
4
+ # <a> elements.
5
+ # It adds the 'selected' class to the <a> element that is currently active.
6
+ #
7
+ # The Links renderer cannot be used to render nested navigations. If you
8
+ # would like it to use with nested navigations, you have to render each
9
+ # level separately.
10
+ #
11
+ # By default, the renderer sets the item's key as dom_id for the rendered
12
+ # <a> element unless the config option <tt>autogenerate_item_ids</tt> is set
13
+ # to false.
14
+ # The id can also be explicitely specified by setting the id in the
15
+ # html-options of the 'item' method in the config/navigation.rb file.
16
+ # The ItemContainer's dom_attributes are applied to the surrounding <div>
17
+ # element.
18
+ class Links < RocketNavigation::Renderer::Base
19
+ def render(item_container)
20
+ div_content = ActiveSupport::SafeBuffer.new
21
+ item_container.items.each_with_index do |item, index|
22
+ div_content << tag_for(item)
23
+ unless index == item_container.items.length - 1
24
+ div_content << join_with
25
+ end
26
+ end
27
+ content_tag :div, div_content, container_html
28
+ end
29
+
30
+ def join_with
31
+ @join_with ||= options[:join_with] || ''.html_safe
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,45 @@
1
+ module RocketNavigation
2
+ module Renderer
3
+ # Renders an ItemContainer as a <ul> element and its containing items as
4
+ # <li> elements.
5
+ # It adds the 'selected' class to li element AND the link inside the li
6
+ # element that is currently active.
7
+ #
8
+ # If the sub navigation should be included (based on the level and
9
+ # expand_all options), it renders another <ul> containing the sub navigation
10
+ # inside the active <li> element.
11
+ #
12
+ # By default, the renderer sets the item's key as dom_id for the rendered
13
+ # <li> element unless the config option <tt>autogenerate_item_ids</tt> is
14
+ # set to false.
15
+ # The id can also be explicitely specified by setting the id in the
16
+ # html-options of the 'item' method in the config/navigation.rb file.
17
+ class List < RocketNavigation::Renderer::Base
18
+ def render(item_container)
19
+ if skip_if_empty? && item_container.empty?
20
+ ''.html_safe
21
+ else
22
+ tag = options[:ordered] ? :ol : :ul
23
+ content = list_content(item_container)
24
+ content_tag(tag, content, container_html)
25
+ end
26
+ end
27
+
28
+ def render_item(item)
29
+ li_content = tag_for(item)
30
+ if include_sub_navigation?(item)
31
+ li_content << render_sub_navigation_for(item)
32
+ end
33
+ content_tag(:li, li_content, item_options(item))
34
+ end
35
+
36
+ def list_content(item_container)
37
+ ret = ActiveSupport::SafeBuffer.new
38
+ item_container.items.each do |item|
39
+ ret << render_item(item)
40
+ end
41
+ ret
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,21 @@
1
+ module RocketNavigation
2
+ module Renderer
3
+ # Renders the 'chain' of selected navigation items as simple text items,
4
+ # joined with an optional separator (similar to breadcrumbs, but without
5
+ # markup).
6
+ class Text < RocketNavigation::Renderer::Base
7
+ def render(item_container)
8
+ list(item_container).compact.join(options[:join_with] || ' ')
9
+ end
10
+
11
+ private
12
+
13
+ def list(item_container)
14
+ item_container.items.keep_if(&:selected?).map do |item|
15
+ [item.name] +
16
+ (include_sub_navigation?(item) ? list(item.sub_navigation) : [])
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,3 @@
1
+ module RocketNavigation
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,38 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "rocket_navigation/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "rocket_navigation"
8
+ spec.version = RocketNavigation::VERSION
9
+ spec.authors = ["Gleb Tv"]
10
+ spec.email = ["glebtv@gmail.com"]
11
+
12
+ spec.summary = %q{rocket_navigation is a gem for creating navigation / menu (for Rails).}
13
+ spec.description = %q{Currently alpha qualiy, use at your own risk.}
14
+ spec.homepage = "https://github.com/rs-pro/rocket_navigation"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
+ f.match(%r{^(test|spec|features)/})
19
+ end
20
+ spec.bindir = "exe"
21
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.add_runtime_dependency 'activesupport', '>= 5.0'
25
+ spec.add_runtime_dependency 'actionpack', '>= 5.0'
26
+ spec.add_runtime_dependency 'actionview', '>= 5.0'
27
+
28
+ spec.add_development_dependency "bundler", "~> 1.16"
29
+ spec.add_development_dependency "rake", "~> 12.0"
30
+ spec.add_development_dependency "rspec", "~> 3.0"
31
+ spec.add_development_dependency "rspec-rails"
32
+ spec.add_development_dependency 'guard-rspec', '~> 4.2'
33
+ spec.add_development_dependency 'capybara'
34
+ spec.add_development_dependency 'simplecov'
35
+ spec.add_development_dependency 'rdoc'
36
+ spec.add_development_dependency 'rails'
37
+ spec.add_development_dependency 'tzinfo', '>= 0'
38
+ end