jordanyeo-simple-navigation 3.11.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.
Files changed (52) hide show
  1. data/CHANGELOG +265 -0
  2. data/Gemfile +17 -0
  3. data/README +22 -0
  4. data/Rakefile +47 -0
  5. data/VERSION +1 -0
  6. data/generators/navigation_config/USAGE +1 -0
  7. data/generators/navigation_config/navigation_config_generator.rb +8 -0
  8. data/generators/navigation_config/templates/config/navigation.rb +76 -0
  9. data/lib/generators/navigation_config/navigation_config_generator.rb +12 -0
  10. data/lib/simple-navigation.rb +1 -0
  11. data/lib/simple_navigation.rb +167 -0
  12. data/lib/simple_navigation/adapters.rb +10 -0
  13. data/lib/simple_navigation/adapters/base.rb +37 -0
  14. data/lib/simple_navigation/adapters/nanoc.rb +45 -0
  15. data/lib/simple_navigation/adapters/padrino.rb +20 -0
  16. data/lib/simple_navigation/adapters/rails.rb +93 -0
  17. data/lib/simple_navigation/adapters/sinatra.rb +69 -0
  18. data/lib/simple_navigation/core.rb +5 -0
  19. data/lib/simple_navigation/core/configuration.rb +72 -0
  20. data/lib/simple_navigation/core/item.rb +144 -0
  21. data/lib/simple_navigation/core/item_adapter.rb +63 -0
  22. data/lib/simple_navigation/core/item_container.rb +147 -0
  23. data/lib/simple_navigation/core/items_provider.rb +35 -0
  24. data/lib/simple_navigation/rails_controller_methods.rb +144 -0
  25. data/lib/simple_navigation/rendering.rb +12 -0
  26. data/lib/simple_navigation/rendering/helpers.rb +123 -0
  27. data/lib/simple_navigation/rendering/renderer/base.rb +107 -0
  28. data/lib/simple_navigation/rendering/renderer/breadcrumbs.rb +59 -0
  29. data/lib/simple_navigation/rendering/renderer/json.rb +29 -0
  30. data/lib/simple_navigation/rendering/renderer/links.rb +32 -0
  31. data/lib/simple_navigation/rendering/renderer/list.rb +29 -0
  32. data/lib/simple_navigation/rendering/renderer/text.rb +26 -0
  33. data/rails/init.rb +1 -0
  34. data/spec/lib/simple_navigation/adapters/padrino_spec.rb +31 -0
  35. data/spec/lib/simple_navigation/adapters/rails_spec.rb +287 -0
  36. data/spec/lib/simple_navigation/adapters/sinatra_spec.rb +80 -0
  37. data/spec/lib/simple_navigation/core/configuration_spec.rb +128 -0
  38. data/spec/lib/simple_navigation/core/item_adapter_spec.rb +212 -0
  39. data/spec/lib/simple_navigation/core/item_container_spec.rb +451 -0
  40. data/spec/lib/simple_navigation/core/item_spec.rb +566 -0
  41. data/spec/lib/simple_navigation/core/items_provider_spec.rb +60 -0
  42. data/spec/lib/simple_navigation/rails_controller_methods_spec.rb +249 -0
  43. data/spec/lib/simple_navigation/rendering/helpers_spec.rb +276 -0
  44. data/spec/lib/simple_navigation/rendering/renderer/base_spec.rb +199 -0
  45. data/spec/lib/simple_navigation/rendering/renderer/breadcrumbs_spec.rb +101 -0
  46. data/spec/lib/simple_navigation/rendering/renderer/json_spec.rb +48 -0
  47. data/spec/lib/simple_navigation/rendering/renderer/links_spec.rb +64 -0
  48. data/spec/lib/simple_navigation/rendering/renderer/list_spec.rb +211 -0
  49. data/spec/lib/simple_navigation/rendering/renderer/text_spec.rb +41 -0
  50. data/spec/lib/simple_navigation_spec.rb +307 -0
  51. data/spec/spec_helper.rb +108 -0
  52. metadata +199 -0
@@ -0,0 +1,12 @@
1
+ class NavigationConfigGenerator < Rails::Generators::Base
2
+ def self.source_root
3
+ @source_root ||= File.expand_path(File.join(File.dirname(__FILE__),'..','..','..','generators','navigation_config', 'templates'))
4
+ end
5
+
6
+ desc 'Creates a template config file for the simple-navigation plugin. You will find the generated file in config/navigation.rb.'
7
+ def navigation_config
8
+ copy_file('config/navigation.rb', 'config/navigation.rb')
9
+ say File.read(File.expand_path(File.join(File.dirname(__FILE__),'..','..','..','README')))
10
+ end
11
+
12
+ end
@@ -0,0 +1 @@
1
+ require 'simple_navigation'
@@ -0,0 +1,167 @@
1
+ # cherry picking active_support stuff
2
+ require 'active_support/core_ext/array'
3
+ require 'active_support/core_ext/hash'
4
+ require 'active_support/core_ext/module/attribute_accessors'
5
+
6
+ require 'simple_navigation/core'
7
+ require 'simple_navigation/rendering'
8
+ require 'simple_navigation/adapters'
9
+
10
+ require 'forwardable'
11
+
12
+ # A plugin for generating a simple navigation. See README for resources on usage instructions.
13
+ module SimpleNavigation
14
+
15
+ mattr_accessor :adapter_class, :adapter, :config_files, :config_file_paths, :default_renderer, :registered_renderers, :root, :environment
16
+
17
+ # Cache for loaded config files
18
+ self.config_files = {}
19
+
20
+ # Allows for multiple config_file_paths. Needed if a plugin itself uses simple-navigation and therefore has its own config file
21
+ self.config_file_paths = []
22
+
23
+ # Maps renderer keys to classes. The keys serve as shortcut in the render_navigation calls (:renderer => :list)
24
+ self.registered_renderers = {
25
+ :list => SimpleNavigation::Renderer::List,
26
+ :links => SimpleNavigation::Renderer::Links,
27
+ :breadcrumbs => SimpleNavigation::Renderer::Breadcrumbs,
28
+ :text => SimpleNavigation::Renderer::Text,
29
+ :json => SimpleNavigation::Renderer::Json
30
+ }
31
+
32
+ class << self
33
+ extend Forwardable
34
+
35
+ def_delegators :adapter, :request, :request_uri, :request_path, :context_for_eval, :current_page?
36
+ def_delegators :adapter_class, :register
37
+
38
+ # Sets the root path and current environment as specified. Also sets the default config_file_path.
39
+ def set_env(root, environment)
40
+ self.root = root
41
+ self.environment = environment
42
+ self.config_file_paths << SimpleNavigation.default_config_file_path
43
+ end
44
+
45
+ # Returns the current framework in which the plugin is running.
46
+ def framework
47
+ return :rails if defined?(Rails)
48
+ return :padrino if defined?(Padrino)
49
+ return :sinatra if defined?(Sinatra)
50
+ return :nanoc if defined?(Nanoc3)
51
+ raise 'simple_navigation currently only works for Rails, Sinatra and Padrino apps'
52
+ end
53
+
54
+ # Loads the adapter for the current framework
55
+ def load_adapter
56
+ self.adapter_class = case framework
57
+ when :rails
58
+ SimpleNavigation::Adapters::Rails
59
+ when :sinatra
60
+ SimpleNavigation::Adapters::Sinatra
61
+ when :padrino
62
+ SimpleNavigation::Adapters::Padrino
63
+ when :nanoc
64
+ SimpleNavigation::Adapters::Nanoc
65
+ end
66
+ end
67
+
68
+ # Creates a new adapter instance based on the context in which render_navigation has been called.
69
+ def init_adapter_from(context)
70
+ self.adapter = self.adapter_class.new(context)
71
+ end
72
+
73
+ def default_config_file_path
74
+ File.join(SimpleNavigation.root, 'config')
75
+ end
76
+
77
+ # Returns true if the config_file for specified context does exist.
78
+ def config_file?(navigation_context = :default)
79
+ !!config_file(navigation_context)
80
+ end
81
+
82
+ # Returns the path to the config file for the given navigation context or nil if no matching config file can be found.
83
+ # If multiple config_paths are set, it returns the first matching path.
84
+ def config_file(navigation_context = :default)
85
+ config_file_paths.collect { |path| File.join(path, config_file_name(navigation_context)) }.detect {|full_path| File.exists?(full_path)}
86
+ end
87
+
88
+ # Returns the name of the config file for the given navigation_context
89
+ def config_file_name(navigation_context = :default)
90
+ prefix = navigation_context == :default ? '' : "#{navigation_context.to_s.underscore}_"
91
+ "#{prefix}navigation.rb"
92
+ end
93
+
94
+ # Resets the list of config_file_paths to the specified path
95
+ def config_file_path=(path)
96
+ self.config_file_paths = [path]
97
+ end
98
+
99
+ # Reads the config_file for the specified navigation_context and stores it for later evaluation.
100
+ def load_config(navigation_context = :default)
101
+ raise "Config file '#{config_file_name(navigation_context)}' not found in path(s) #{config_file_paths.join(', ')}!" unless config_file?(navigation_context)
102
+ if self.environment == 'production'
103
+ self.config_files[navigation_context] ||= IO.read(config_file(navigation_context))
104
+ else
105
+ self.config_files[navigation_context] = IO.read(config_file(navigation_context))
106
+ end
107
+ end
108
+
109
+ # Returns the singleton instance of the SimpleNavigation::Configuration
110
+ def config
111
+ SimpleNavigation::Configuration.instance
112
+ end
113
+
114
+ # Returns the ItemContainer that contains the items for the primary navigation
115
+ def primary_navigation
116
+ config.primary_navigation
117
+ end
118
+
119
+ # Returns the active item container for the specified level. Valid levels are
120
+ # * :all - in this case the primary_navigation is returned.
121
+ # * :leaves - the 'deepest' active item_container will be returned
122
+ # * a specific level - the active item_container for the specified level will be returned
123
+ # * a range of levels - the active item_container for the range's minimum will be returned
124
+ #
125
+ # Returns nil if there is no active item_container for the specified level.
126
+ def active_item_container_for(level)
127
+ case level
128
+ when :all
129
+ self.primary_navigation
130
+ when :leaves
131
+ self.primary_navigation.active_leaf_container
132
+ when Integer
133
+ self.primary_navigation.active_item_container_for(level)
134
+ when Range
135
+ self.primary_navigation.active_item_container_for(level.min)
136
+ else
137
+ raise ArgumentError, "Invalid navigation level: #{level}"
138
+ end
139
+ end
140
+
141
+ # Registers a renderer.
142
+ #
143
+ # === Example
144
+ # To register your own renderer:
145
+ #
146
+ # SimpleNavigation.register_renderer :my_renderer => My::RendererClass
147
+ #
148
+ # Then in the view you can call:
149
+ #
150
+ # render_navigation(:renderer => :my_renderer)
151
+ def register_renderer(renderer_hash)
152
+ self.registered_renderers.merge!(renderer_hash)
153
+ end
154
+
155
+ private
156
+
157
+ def apply_defaults(options)
158
+ options[:level] = options.delete(:levels) if options[:levels]
159
+ {:context => :default, :level => :all}.merge(options)
160
+ end
161
+
162
+
163
+ end
164
+
165
+ end
166
+
167
+ SimpleNavigation.load_adapter
@@ -0,0 +1,10 @@
1
+ require 'simple_navigation/adapters/base'
2
+
3
+ module SimpleNavigation
4
+ module Adapters
5
+ autoload :Rails, 'simple_navigation/adapters/rails'
6
+ autoload :Padrino, 'simple_navigation/adapters/padrino'
7
+ autoload :Sinatra, 'simple_navigation/adapters/sinatra'
8
+ autoload :Nanoc, 'simple_navigation/adapters/nanoc'
9
+ end
10
+ end
@@ -0,0 +1,37 @@
1
+ module SimpleNavigation
2
+ module Adapters
3
+
4
+ # This is the base class for all adapters. This class mainly exists for documenting reasons.
5
+ # It lists all the methods that an adapter should implement.
6
+ #
7
+ class Base
8
+ attr_reader :context, :request
9
+
10
+ # This method is usually called when the framework is initialized.
11
+ # It should call SimpleNavigation.set_env and install SimpleNavigation::Helpers where appropriate.
12
+ def self.register; end
13
+
14
+ # Returns the full path incl. query params
15
+ def request_uri; end
16
+
17
+ # Returns the path without query params
18
+ def request_path; end
19
+
20
+ # Returns the context in which the config files will be evaluated
21
+ def context_for_eval; end
22
+
23
+ # Returns true if the current request's url matches the specified url.
24
+ # Used to determine if an item should be autohighlighted.
25
+ def current_page?(url); end
26
+
27
+ # Returns a link with the specified name, url and options.
28
+ # Used for rendering.
29
+ def link_to(name, url, options={}); end
30
+
31
+ # Returns a tag of the specified type, content and options.
32
+ # Used for rendering.
33
+ def content_tag(type, content, options={}); end
34
+
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,45 @@
1
+ module SimpleNavigation
2
+ module Adapters
3
+ class Nanoc < Base
4
+ class << self
5
+ def register(root)
6
+ SimpleNavigation.set_env(root, 'development')
7
+ Nanoc3::Context.send(:include, SimpleNavigation::Helpers)
8
+ end
9
+ end
10
+
11
+ def initialize(ctx)
12
+ @context = ctx
13
+ end
14
+
15
+ # Returns the context in which the config files will be evaluated
16
+ def context_for_eval
17
+ context
18
+ end
19
+
20
+ # Returns true if the current request's url matches the specified url.
21
+ # Used to determine if an item should be autohighlighted.
22
+ def current_page?(url)
23
+ path = context.item.path
24
+ path && path.chop == url
25
+ end
26
+
27
+ # Returns a link with the specified name, url and options.
28
+ # Used for rendering.
29
+ def link_to(name, url, options={})
30
+ "<a href='#{url}' #{to_attributes(options)}>#{name}</a>"
31
+ end
32
+
33
+ # Returns a tag of the specified type, content and options.
34
+ # Used for rendering.
35
+ def content_tag(type, content, options={})
36
+ "<#{type} #{to_attributes(options)}>#{content}</#{type}>"
37
+ end
38
+
39
+ private
40
+ def to_attributes(options)
41
+ options.map {|k, v| v.nil? ? nil : "#{k}='#{v}'"}.compact.join(' ')
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,20 @@
1
+ module SimpleNavigation
2
+ module Adapters
3
+ class Padrino < Sinatra
4
+
5
+ def self.register
6
+ SimpleNavigation.set_env(PADRINO_ROOT, PADRINO_ENV)
7
+ ::Padrino::Application.send(:helpers, SimpleNavigation::Helpers)
8
+ end
9
+
10
+ def link_to(name, url, options={})
11
+ context.link_to(name, url, options)
12
+ end
13
+
14
+ def content_tag(type, content, options={})
15
+ context.content_tag(type, content.html_safe, options)
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,93 @@
1
+ module SimpleNavigation
2
+ module Adapters
3
+ class Rails < Base
4
+
5
+ attr_reader :controller, :template
6
+
7
+ def self.register
8
+ SimpleNavigation.set_env(rails_root, rails_env)
9
+ ActionController::Base.send(:include, SimpleNavigation::Helpers)
10
+ SimpleNavigation::Helpers.instance_methods.each do |m|
11
+ ActionController::Base.send(:helper_method, m.to_sym)
12
+ end
13
+ end
14
+
15
+ def initialize(context)
16
+ @controller = extract_controller_from context
17
+ @template = template_from @controller
18
+ @request = @template.request if @template
19
+ end
20
+
21
+ def request_uri
22
+ return '' unless request
23
+ return request.fullpath if request.respond_to?(:fullpath)
24
+ request.request_uri
25
+ end
26
+
27
+ def request_path
28
+ return '' unless request
29
+ request.path
30
+ end
31
+
32
+ def context_for_eval
33
+ raise 'no context set for evaluation the config file' unless template || controller
34
+ template || controller
35
+ end
36
+
37
+ def current_page?(url)
38
+ template.current_page?(url) if template
39
+ end
40
+
41
+ def link_to(name, url, options={})
42
+ template.link_to(html_safe(name), url, options) if template
43
+ end
44
+
45
+ def content_tag(type, content, options={})
46
+ template.content_tag(type, html_safe(content), options) if template
47
+ end
48
+
49
+ protected
50
+
51
+ def self.rails_root
52
+ gte_rails3? ? ::Rails.root : ::RAILS_ROOT
53
+ end
54
+
55
+ def self.rails_env
56
+ gte_rails3? ? ::Rails.env : ::RAILS_ENV
57
+ end
58
+
59
+ def self.gte_rails3?
60
+ ::Rails::VERSION::MAJOR >= 3
61
+ end
62
+
63
+ def template_from(controller)
64
+ controller.respond_to?(:view_context) ? controller.view_context : controller.instance_variable_get(:@template)
65
+ end
66
+
67
+ # Marks the specified input as html_safe (for Rails3). Does nothing if html_safe is not defined on input.
68
+ #
69
+ def html_safe(input)
70
+ input.respond_to?(:html_safe) ? input.html_safe : input
71
+ end
72
+
73
+ # Extracts a controller from the context.
74
+ def extract_controller_from(context)
75
+ context.respond_to?(:controller) ?
76
+ context.controller || context :
77
+ context
78
+ end
79
+
80
+ end
81
+ end
82
+ end
83
+
84
+ # Initializer for Rails3
85
+ if defined?(Rails) && SimpleNavigation::Adapters::Rails.gte_rails3?
86
+ module SimpleNavigation
87
+ class Railtie < Rails::Railtie
88
+ initializer "simple_navigation.register" do |app|
89
+ SimpleNavigation.register
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,69 @@
1
+ require 'cgi'
2
+
3
+ module SimpleNavigation
4
+ module Adapters
5
+ class Sinatra < Base
6
+
7
+ def self.register
8
+ SimpleNavigation.set_env(sinatra_root, sinatra_environment)
9
+ ::Sinatra::Application.send(:helpers, SimpleNavigation::Helpers)
10
+ end
11
+
12
+ def initialize(context)
13
+ @context = context
14
+ @request = context.request
15
+ end
16
+
17
+ def context_for_eval
18
+ raise 'no context set for evaluation the config file' unless context
19
+ context
20
+ end
21
+
22
+ def request_uri
23
+ request.fullpath
24
+ end
25
+
26
+ def request_path
27
+ request.path
28
+ end
29
+
30
+ def current_page?(url)
31
+ url_string = CGI.unescape(url)
32
+ if url_string.index("?")
33
+ uri = request_uri
34
+ else
35
+ uri = request_uri.split('?').first
36
+ end
37
+ uri = CGI.unescape(uri)
38
+ if url_string =~ /^\w+:\/\//
39
+ url_string == "#{request.scheme}://#{request.host_with_port}#{uri}"
40
+ else
41
+ url_string == uri
42
+ end
43
+ end
44
+
45
+ def link_to(name, url, options={})
46
+ "<a href='#{url}'#{to_attributes(options)}>#{name}</a>"
47
+ end
48
+
49
+ def content_tag(type, content, options={})
50
+ "<#{type}#{to_attributes(options)}>#{content}</#{type}>"
51
+ end
52
+
53
+ protected
54
+
55
+ def self.sinatra_root
56
+ ::Sinatra::Application.root
57
+ end
58
+
59
+ def self.sinatra_environment
60
+ ::Sinatra::Application.environment
61
+ end
62
+
63
+ def to_attributes(options)
64
+ options.map {|k, v| v.nil? ? '' : " #{k}='#{v}'"}.join
65
+ end
66
+
67
+ end
68
+ end
69
+ end