jordanyeo-simple-navigation 3.11.0

Sign up to get free protection for your applications and to get access to all the features.
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