navigasmic 0.5.6 → 1.0.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 (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