navigasmic 0.5.6 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. data/LICENSE +7 -1
  2. data/lib/generators/navigasmic/install/POST_INSTALL +6 -0
  3. data/lib/generators/navigasmic/install/install_generator.rb +17 -0
  4. data/lib/generators/navigasmic/install/templates/initializer.rb +145 -0
  5. data/lib/navigasmic.rb +5 -146
  6. data/lib/navigasmic/builders/crumb_builder.rb +20 -0
  7. data/lib/navigasmic/builders/list_builder.rb +90 -0
  8. data/lib/navigasmic/builders/map_builder.rb +77 -0
  9. data/lib/navigasmic/core/builders.rb +109 -0
  10. data/lib/navigasmic/core/configuration.rb +38 -0
  11. data/lib/navigasmic/core/item.rb +66 -0
  12. data/lib/navigasmic/rails.rb +2 -0
  13. data/lib/navigasmic/rails/engine.rb +9 -0
  14. data/lib/navigasmic/rails/view_helpers.rb +18 -0
  15. data/lib/navigasmic/version.rb +3 -0
  16. data/spec/dummy/Rakefile +7 -0
  17. data/spec/dummy/app/controllers/application_controller.rb +13 -0
  18. data/spec/dummy/app/controllers/blog/links_controller.rb +7 -0
  19. data/spec/dummy/app/controllers/blog/posts_controller.rb +7 -0
  20. data/spec/dummy/app/views/application/welcome.html.erb +4 -0
  21. data/spec/dummy/app/views/application/welcome.xml.builder +2 -0
  22. data/spec/dummy/app/views/blog/links/index.html +4 -0
  23. data/spec/dummy/app/views/blog/links/show.html +4 -0
  24. data/spec/dummy/app/views/blog/posts/index.html +4 -0
  25. data/spec/dummy/app/views/blog/posts/show.html +4 -0
  26. data/spec/dummy/app/views/layouts/_navigation.html.erb +73 -0
  27. data/spec/dummy/app/views/layouts/application.html.erb +40 -0
  28. data/spec/dummy/config.ru +4 -0
  29. data/spec/dummy/config/application.rb +57 -0
  30. data/spec/dummy/config/boot.rb +9 -0
  31. data/spec/dummy/config/environment.rb +5 -0
  32. data/spec/dummy/config/environments/development.rb +37 -0
  33. data/spec/dummy/config/environments/test.rb +37 -0
  34. data/spec/dummy/config/evergreen.rb +47 -0
  35. data/spec/dummy/config/initializers/additional_navigasmic.rb +14 -0
  36. data/spec/dummy/config/initializers/navigasmic.rb +145 -0
  37. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  38. data/spec/dummy/config/initializers/session_store.rb +8 -0
  39. data/spec/dummy/config/locales/en.yml +5 -0
  40. data/spec/dummy/config/routes.rb +68 -0
  41. data/spec/dummy/log/.gitkeep +0 -0
  42. data/spec/dummy/public/bootstrap.min.css +9 -0
  43. data/spec/dummy/public/bootstrap.min.js +6 -0
  44. data/spec/dummy/public/favicon.ico +0 -0
  45. data/spec/dummy/public/jquery.min.js +2 -0
  46. data/spec/dummy/script/rails +6 -0
  47. data/spec/spec_helper.rb +39 -0
  48. metadata +139 -63
  49. data/.document +0 -5
  50. data/README.textile +0 -276
  51. data/Rakefile +0 -57
  52. data/VERSION +0 -1
  53. data/lib/builders/html_builder.rb +0 -69
  54. data/lib/builders/xml_builder.rb +0 -51
  55. data/navigasmic.gemspec +0 -49
  56. data/test/navigasmic_test.rb +0 -7
  57. data/test/test_helper.rb +0 -10
data/LICENSE CHANGED
@@ -1,4 +1,10 @@
1
- Copyright (c) 2010 Jeremy Jackson
1
+ Navigasmic is a semantic way to build beautifully simple navigation
2
+ structures in Rails.
3
+
4
+ Documentation and other useful information can be found at
5
+ https://github.com/jejacks0n/navigasmic
6
+
7
+ Copyright (c) 2011 Jeremy Jackson
2
8
 
3
9
  Permission is hereby granted, free of charge, to any person obtaining
4
10
  a copy of this software and associated documentation files (the
@@ -0,0 +1,6 @@
1
+ +============================================================================+
2
+ Congratulations! Navigasmic was successfully installed. Documentation and more
3
+ can be found at: https://github.com/jejacks0n/navigasmic
4
+
5
+ You should start defining some navigation in config/initializers/navigasmic.rb
6
+
@@ -0,0 +1,17 @@
1
+ module Navigasmic
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ source_root File.expand_path('../', __FILE__)
5
+
6
+ desc "Installs the Navigasmic initializer into your application."
7
+
8
+ def copy_initializer
9
+ copy_file 'templates/initializer.rb', 'config/initializers/navigasmic.rb'
10
+ end
11
+
12
+ def display_readme
13
+ readme 'POST_INSTALL' if behavior == :invoke
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,145 @@
1
+ Navigasmic.setup do |config|
2
+
3
+ # Defining Navigation Structures:
4
+ #
5
+ # You can begin by defining your navigation structures here. You can also define them directly in the view if you'd
6
+ # like, but it's recommended to eventually move them here to clean help up your views. You can read about Navigasmic
7
+ # at https://github.com/jejacks0n/navigasmic
8
+ #
9
+ # When you're defining navigation here, it's basically the same as if you were doing it in the view but the scope is
10
+ # different. It's important to understand that -- and use procs where you want things to execute in the view scope.
11
+ #
12
+ # Once you've defined some navigation structures and configured your builders you can render navigation in your views
13
+ # using the `semantic_navigation` view helper. You can also use the same syntax to define your navigation structures
14
+ # in your views, and eventually move them here (it's handy to prototype navigation/css by putting them in the views
15
+ # first).
16
+ #
17
+ # <%= semantic_navigation :primary %>
18
+ #
19
+ # You can optionally provided a :builder and :config option to the semantic_navigation view helper.
20
+ #
21
+ # <%= semantic_navigation :primary, config: :blockquote %>
22
+ # <%= semantic_navigation :primary, builder: Navigasmic::Builder::MapBuilder %>
23
+ #
24
+ # When defining navigation in your views just pass it a block (the same as here basically).
25
+ #
26
+ # <%= semantic_navigation :primary do |n| %>
27
+ # <% n.item 'About Me' %>
28
+ # <% end %>
29
+ #
30
+ # Here's a basic example:
31
+ config.semantic_navigation :primary do |n|
32
+
33
+ n.item 'Home', '/'
34
+
35
+ # Groups and Items:
36
+ #
37
+ # You can create a structure using `group`, and `item`. You can nest items inside groups or items. In the
38
+ # following example, the "Articles" item will always highlight on the blog/posts controller, and the nested article
39
+ # items will only highlight when on those specific pages. The "Links" item will be disabled unless the user is
40
+ # logged in.
41
+ #
42
+ #n.group 'Blog' do
43
+ # n.item 'Articles', controller: '/blog/posts' do
44
+ # n.item 'First Article', '/blog/posts/1'
45
+ # n.item 'Second Article', '/blog/posts/2', map: {changefreq: 'weekly'}
46
+ # end
47
+ # n.item 'Links', controller: '/blog/links', disabled_if: proc{ !logged_in? }
48
+ #end
49
+ #
50
+ # You can hide specific specific items or groups. Here we specify that the "About" section of navigation should
51
+ # only be displayed if the user is logged in.
52
+ #
53
+ #n.group 'About', hidden_unless: proc{ logged_in? } do
54
+ # n.item 'About Me', class: 'featured', link_html: {class: 'about-me'}
55
+ #end
56
+ #
57
+ # Scoping:
58
+ #
59
+ # Scoping is different than in the view here, so we've provided some nice things for you to get around that. In
60
+ # the above example we just provide '/' as what the home page is, but that may not be correct. You can also access
61
+ # the path helpers, using a proc, or by proxying them through the navigation object. Any method called on the
62
+ # navigation scope will be called within the view scope.
63
+ #
64
+ #n.item 'Home', proc{ root_path }
65
+ #n.item 'Home', n.root_path
66
+ #
67
+ # This proxy behavior can be used for I18n as well.
68
+ #
69
+ #n.item n.t('hello'), '/'
70
+
71
+ end
72
+
73
+
74
+ # Setting the Default Builder:
75
+ #
76
+ # By default the Navigasmic::Builder::ListBuilder is used unless otherwise specified.
77
+ #
78
+ # You can change this here:
79
+ #config.default_builder = MyCustomBuilder
80
+
81
+
82
+ # Configuring Builders:
83
+ #
84
+ # You can change various builder options here by specifying the builder you want to configure and the options you
85
+ # want to change.
86
+ #
87
+ # Changing the default ListBuilder options:
88
+ config.builder Navigasmic::Builder::ListBuilder do |builder|
89
+ builder.wrapper_class = 'semantic-navigation'
90
+ end
91
+
92
+
93
+ # Naming Builder Configurations:
94
+ #
95
+ # If you want to define a named configuration for a builder, just provide a hash with the name, and the builder to
96
+ # configure. The named configurations can then be used during rendering by specifying a `:config => :bootstrap`
97
+ # option to the `semantic_navigation` view helper.
98
+ #
99
+ # A Twitter Bootstrap configuration:
100
+ #
101
+ # Example usage:
102
+ #
103
+ # <%= semantic_navigation :primary, config: :bootstrap, class: 'nav-pills' %>
104
+ #
105
+ # Or to create a full navigation bar using twitter bootstrap you could use the following in your view:
106
+ # <div class="navbar">
107
+ # <div class="navbar-inner">
108
+ # <a class="brand" href="/">Title</a>
109
+ # <%= semantic_navigation :primary, config: :bootstrap %>
110
+ # </div>
111
+ # </div>
112
+ config.builder bootstrap: Navigasmic::Builder::ListBuilder do |builder|
113
+
114
+ # Set the nav and nav-pills css (you can also use 'nav nav-tabs') -- or remove them if you're using this inside a
115
+ # navbar.
116
+ builder.wrapper_class = 'nav nav-pills'
117
+
118
+ # Set the classed for items that have nested items, and that are nested items.
119
+ builder.has_nested_class = 'dropdown'
120
+ builder.is_nested_class = 'dropdown-menu'
121
+
122
+ # For dropdowns to work you'll need to include the bootstrap dropdown js
123
+ # For groups, we adjust the markup so they'll be clickable and be picked up by the javascript.
124
+ builder.label_generator = proc do |label, has_link, has_nested|
125
+ if !has_nested || has_link
126
+ "<span>#{label}</span>"
127
+ else
128
+ link_to("#{label}<b class='caret'></b>".html_safe, '#', class: 'dropdown-toggle', data: {toggle: 'dropdown'})
129
+ end
130
+ end
131
+
132
+ # For items, we adjust the links so they're '#', and do the same as for groups. This allows us to use more complex
133
+ # highlighting rules for dropdowns.
134
+ builder.link_generator = proc do |label, link, options, has_nested|
135
+ if has_nested
136
+ link = '#'
137
+ label << "<b class='caret'></b>"
138
+ options.merge!(class: 'dropdown-toggle', data: {toggle: 'dropdown'})
139
+ end
140
+ link_to(label, link, options)
141
+ end
142
+
143
+ end
144
+
145
+ end
data/lib/navigasmic.rb CHANGED
@@ -1,147 +1,6 @@
1
- # coding: utf-8
2
- require 'builders/html_builder'
3
- require 'builders/xml_builder'
1
+ require 'navigasmic/version'
2
+ require 'navigasmic/rails'
4
3
 
5
- module Navigasmic #:nodoc:
6
-
7
- # Semantic navigation helper methods
8
- #
9
- # Example Usage:
10
- #
11
- # <% semantic_navigation :primary, :html => {:class => 'primary'} do |n| %>
12
- # <%= n.item 'Blog Posts', :link => {:controller => 'posts'} %>
13
- # <% end %>
14
- #
15
- # <% semantic_navigation :primary, :builder => MyCustomBuilder do |n| %>
16
- # <%= n.group 'My Thoughts' do %>
17
- # <%= n.item 'Blog Posts', :link => {:controller => 'posts'} %>
18
- # <% end %>
19
- # <% end %>
20
- #
21
- # <% semantic_navigation :primary do |n| %>
22
- # <%= n.group 'My Thoughts' do %>
23
- # <%= n.item 'Blog Posts', :link => {:controller => 'posts'} do %>
24
- # <ul>
25
- # <%= n.item 'Recent Posts', :link => {:controller => 'posts', :action => 'recent'} %>
26
- # </ul>
27
- # <% end %>
28
- # <% end %>
29
- # <% end %>
30
- module SemanticNavigationHelper
31
-
32
- @@builder = ::Navigasmic::HtmlNavigationBuilder
33
- mattr_accessor :builder
34
-
35
- def semantic_navigation(name, *args, &proc)
36
- raise ArgumentError, "Missing block" unless block_given?
37
-
38
- options = args.extract_options!
39
-
40
- options[:html] ||= {}
41
- options[:html][:class] = add_html_class(options[:html][:class], 'semantic-navigation')
42
- options[:html][:id] ||= name.to_s.underscore unless options[:html].has_key?(:id)
43
-
44
- builder = options.delete(:builder) || @@builder
45
- builder.new(self, name, options, &proc)
46
- end
47
-
48
- def add_html_class(classnames, classname)
49
- out = (classnames.is_a?(String) ? classnames.split(' ') : []) << classname
50
- out.join(' ')
51
- end
52
-
53
- end
54
-
55
- #
56
- #
57
- #
58
- #
59
- #
60
- class NavigationItem
61
-
62
- attr_accessor :label, :link
63
-
64
- def initialize(label, options = {}, template = nil)
65
- @label = label
66
-
67
- if options[:link]
68
- @link = options[:link]
69
- elsif template.present?
70
- method = "#{label.to_s.underscore.gsub(/\s/, '_')}_path"
71
- @link = template.send(method) if template.respond_to? method
72
- end
73
- @link ||= {}
74
-
75
- @disabled_conditions = options[:disabled_if] || proc { false }
76
- @visible = options[:hidden_unless].nil? ? true : options[:hidden_unless].is_a?(Proc) ? template.instance_eval(&options[:hidden_unless]) : options[:hidden_unless]
77
-
78
- options[:highlights_on] = [options[:highlights_on]] if options[:highlights_on].kind_of?(Hash) || options[:highlights_on].kind_of?(String)
79
- @highlights_on = options[:highlights_on] || []
80
-
81
- if link?
82
- if @link.is_a?(Proc)
83
- @highlights_on << template.instance_eval(&@link)
84
- else
85
- @highlights_on << @link if link?
86
- end
87
- end
88
- end
89
-
90
- def link?
91
- @link && !@link.blank?
92
- end
93
-
94
- def disabled?
95
- @disabled_conditions.call
96
- end
97
-
98
- def hidden?
99
- !@visible
100
- end
101
-
102
- def highlighted?(path, params = {}, template = nil)
103
- params = clean_unwanted_keys(params)
104
- result = false
105
-
106
- @highlights_on.each do |highlight|
107
- highlighted = true
108
-
109
- case highlight
110
- when String
111
- highlighted &= path == highlight
112
- when Proc
113
- h = template.instance_eval(&highlight)
114
- raise 'proc highlighting rules must evaluate to TrueClass or FalseClass' unless (h.is_a?(TrueClass) || h.is_a?(FalseClass))
115
- highlighted &= h
116
- when Regexp
117
- highlighted &= path.match(highlight)
118
- when Hash
119
- h = clean_unwanted_keys(highlight)
120
- h.each_key do |key|
121
- h_key = h[key].to_s.dup
122
- h_key.gsub!(/^\//, '') if key == :controller
123
- highlighted &= h_key == params[key].to_s
124
- end
125
- else
126
- raise 'highlighting rules should be a String, Proc, Regexp or a Hash'
127
- end
128
-
129
- result |= highlighted
130
- end
131
-
132
- return result
133
- end
134
-
135
- private
136
-
137
- # removes unwanted keys from a Hash and returns a new hash
138
- def clean_unwanted_keys(hash)
139
- ignored_keys = [:only_path, :use_route]
140
- hash.dup.delete_if { |key, value| ignored_keys.include?(key) }
141
- end
142
-
143
- end
144
-
145
- end
146
-
147
- ActionController::Base.helper Navigasmic::SemanticNavigationHelper
4
+ require 'navigasmic/core/builders'
5
+ require 'navigasmic/core/configuration'
6
+ require 'navigasmic/core/item'
@@ -0,0 +1,20 @@
1
+ module Navigasmic::Builder
2
+ class CrumbBuilder < Base
3
+ class Configuration < Base::Configuration
4
+ end
5
+
6
+ def initialize(context, name, options, &block)
7
+ super
8
+ end
9
+
10
+ def render
11
+ end
12
+
13
+ def group(label = nil, options = {}, &block)
14
+ end
15
+
16
+ def item(label, *args, &block)
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,90 @@
1
+ module Navigasmic::Builder
2
+ class ListBuilder < Base
3
+ class Configuration < Base::Configuration
4
+
5
+ attr_accessor :wrapper_class, :has_nested_class, :is_nested_class, :disabled_class, :highlighted_class
6
+ attr_accessor :wrapper_tag, :group_tag, :item_tag
7
+ attr_accessor :link_generator, :label_generator
8
+
9
+ def initialize
10
+ # which keys (for other builder) should be removed from options
11
+ @excluded_keys = [:map]
12
+
13
+ # tag configurations
14
+ @wrapper_tag = :ul
15
+ @group_tag = :ul
16
+ @item_tag = :li
17
+
18
+ # class configurations
19
+ @wrapper_class = 'semantic-navigation'
20
+ @has_nested_class = 'has-nested'
21
+ @is_nested_class = 'is-nested'
22
+ @disabled_class = 'disabled'
23
+ @highlighted_class = 'active'
24
+
25
+ # generator callbacks
26
+ @link_generator = proc{ |label, link, options, is_nested| link_to(label, link, options.delete(:link_html)) }
27
+ @label_generator = proc{ |label, is_linked, is_nested| "<span>#{label}</span>" }
28
+
29
+ super
30
+ end
31
+ end
32
+
33
+ def initialize(context, name, options, &block)
34
+ super
35
+ @options[:id] ||= name.to_s.underscore unless @options.has_key?(:id)
36
+ @options[:class] = merge_classes!(@options, @config.wrapper_class)
37
+ end
38
+
39
+ def render
40
+ content_tag(@config.wrapper_tag, capture(&@definition), @options)
41
+ end
42
+
43
+ def group(label = nil, options = {}, &block)
44
+ raise ArgumentError, "Missing block for group" unless block_given?
45
+ return '' unless visible?(options)
46
+
47
+ concat(structure_for(label, false, options, &block))
48
+ end
49
+
50
+ def item(label, *args, &block)
51
+ options = args.extract_options!
52
+ options = flatten_and_eval_options(options)
53
+ return '' unless visible?(options)
54
+
55
+ item = Navigasmic::Item.new(self, label, extract_and_determine_link(label, options, *args), options)
56
+
57
+ merge_classes!(options, @config.disabled_class) if item.disabled?
58
+ merge_classes!(options, @config.highlighted_class) if item.highlights_on?(@context.request.path, @context.params)
59
+
60
+ concat(structure_for(label, item.link? ? item.link : false, options, &block))
61
+ end
62
+
63
+ private
64
+
65
+ def structure_for(label, link = false, options = {}, &block)
66
+ label = label_for(label, link, block_given?, options)
67
+
68
+ content = ''
69
+ if block_given?
70
+ merge_classes!(options, @config.has_nested_class)
71
+ content = content_tag(@config.group_tag, capture(&block), {class: @config.is_nested_class})
72
+ end
73
+
74
+ content_tag(@config.item_tag, "#{label}#{content}".html_safe, options)
75
+ end
76
+
77
+ def label_for(label, link, is_nested = false, options = {})
78
+ if label.present?
79
+ label = @context.instance_exec(label, !!link, is_nested, &@config.label_generator).html_safe
80
+ end
81
+ label = @context.instance_exec(label, link, options.delete(:link_html) || {}, is_nested, &@config.link_generator).html_safe if link
82
+ label
83
+ end
84
+
85
+ def merge_classes!(hash, classname)
86
+ hash[:class] = (hash[:class] ? "#{hash[:class]} " : '') << classname
87
+ end
88
+
89
+ end
90
+ end