tabs_on_rails 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.rdoc ADDED
@@ -0,0 +1,50 @@
1
+ = Changelog
2
+
3
+
4
+ == Release 0.8.1
5
+
6
+ * CHANGED: Controller#set_tab now uses #send instead of #instance_eval (better performance and more security)
7
+
8
+ * CHANGED: run test against Rails ~> 2.3.0 but ensure compatibility with Rails 2.2.x.
9
+
10
+
11
+ == Release 0.8.0
12
+
13
+ * FIXED: Invalid usage of the word namescope instead of namespace.
14
+
15
+ * FIXED: :current_tab? not available as helper method (closes #229).
16
+
17
+ * FIXED: GitHub now requires the Manifest file to be included in the repos.
18
+
19
+ * FIXED: Controller methods should be protected/private (closes #228).
20
+
21
+ * CHANGED: Status to Beta and bumped release (closes #227).
22
+
23
+ * REMOVED: Deprecated current_tab setter method. Use set_tab instead.
24
+
25
+
26
+ == Release 0.3.0
27
+
28
+ * ADDED: Support for namespaces in order to manage concurrent tab menus (closes #144).
29
+
30
+ * FIXED: `Uninitialized constant RAILS_DEFAULT_LOGGER (NameError)' error message when running tests outside a Rails environment.
31
+
32
+ * FIXED: Tests complains when Rails 2.3.2 is installed. This library is 100% compatible with Rails 2.3.2 but for now let's force tests to use Rails 2.2.2.
33
+
34
+ * CHANGED: current_tab= controller instance/class methods are now deprecated. Use set_tab instead.
35
+
36
+ * CHANGED: Calling tabs_tag with a custom builder as first parameter is now deprecated. Use :builder option instead.
37
+
38
+
39
+ == Release 0.2.0
40
+
41
+ * ADDED: The README file is definitely more useful now, filled up with some basic documentation.
42
+
43
+ * CHANGED: Use the standard way to initialize a Rails plugin when packaged as a GEM (closes #146).
44
+
45
+ * CHANGED: Removed development version warning (closes #145).
46
+
47
+
48
+ == Release 0.1.0
49
+
50
+ * Initial version
data/LICENSE.rdoc ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Simone Carletti
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Manifest ADDED
@@ -0,0 +1,23 @@
1
+ CHANGELOG.rdoc
2
+ init.rb
3
+ install.rb
4
+ lib/tabs_on_rails/controller_mixin.rb
5
+ lib/tabs_on_rails/tabs.rb
6
+ lib/tabs_on_rails/version.rb
7
+ lib/tabs_on_rails.rb
8
+ LICENSE.rdoc
9
+ Manifest
10
+ rails/init.rb
11
+ Rakefile
12
+ README.rdoc
13
+ tabs_on_rails.gemspec
14
+ tasks/tabs_on_rails_tasks.rake
15
+ test/builder_test.rb
16
+ test/controller_mixin_helpers_test.rb
17
+ test/controller_mixin_test.rb
18
+ test/controller_mixin_with_controller_test.rb
19
+ test/fixtures/mixin/standard.html.erb
20
+ test/tabs_builder_test.rb
21
+ test/tabs_on_rails_test.rb
22
+ test/test_helper.rb
23
+ uninstall.rb
data/README.rdoc ADDED
@@ -0,0 +1,270 @@
1
+ = TabsOnRails
2
+
3
+ TabsOnRails is a simple Rails plugin for creating and managing Tabs.
4
+ It provides helpers for creating tabs with a flexible interface.
5
+
6
+
7
+ == Requirements
8
+
9
+ * Ruby >= 1.8.6
10
+ * Rails >= 2.2
11
+
12
+ Note. TabsOnRails doesn't work with Rails 2.1 or previous versions (see {Ticket #245}[http://code.simonecarletti.com/issues/show/245]).
13
+
14
+
15
+ == Rails Installation
16
+
17
+ === As a Gem
18
+
19
+ This is the preferred way to install TabsOnRails and the best way if you want install a stable version.
20
+
21
+ $ gem install weppos-tabs_on_rails --source http://gems.github.com
22
+
23
+ You can specify the GEM dependency in your application environment.rb file:
24
+
25
+ Rails::Initializer.run do |config|
26
+
27
+ # other configurations
28
+
29
+ config.gem "weppos-tabs_on_rails", :lib => "tabs_on_rails", :source => "http://gems.github.com"
30
+ end
31
+
32
+ === As a Plugin
33
+
34
+ This is the preferred way if you want to live on the edge and install a development version.
35
+
36
+ $ script/plugin install git://github.com/weppos/tabs_on_rails.git
37
+
38
+
39
+ == Quick Start
40
+
41
+ In your template use the <tt>tabs_tag</tt> helper to create your tab.
42
+
43
+ <% tabs_tag do |tab| %>
44
+ <%= tab.home 'Homepage', root_path %>
45
+ <%= tab.dashboard 'Dashboard', dashboard_path %>
46
+ <%= tab.account 'Account', account_path %>
47
+ <% end %>
48
+
49
+ The example above produces the following HTML output.
50
+
51
+ <ul>
52
+ <li><a href="/">Homepage</a></li>
53
+ <li><a href="/dashboard">Dashboard</a></li>
54
+ <li><a href="/account">Account</a></li>
55
+ </ul>
56
+
57
+ The usage is similar to the Rails route file.
58
+ You create named tabs with the syntax <tt>tab.name_of_tab</tt>.
59
+
60
+ The name you use creating a tab is the same you're going to refer to in your controller
61
+ when you want to mark a tab as the current tab.
62
+
63
+ class DashboardController < ApplicationController
64
+ set_tab :dashboard
65
+ end
66
+
67
+ Now, if the action belongs to DashboardController, the template will automatically render the following HTML code.
68
+
69
+ <ul>
70
+ <li><a href="/">Homepage</a></li>
71
+ <li><span>Dashboard</span></li>
72
+ <li><a href="/account">Account</a></li>
73
+ </ul>
74
+
75
+ Use the <tt>current_tab</tt> helper method if you need to access the value of current tab in your controller or template.
76
+
77
+ class DashboardController < ApplicationController
78
+ set_tab :dashboard
79
+ end
80
+
81
+ # In your view
82
+ <p>The name of current tab is <%= current_tab %>.</p>
83
+
84
+
85
+ == Restricting set_tab scope
86
+
87
+ The <tt>set_tab</tt> method understands all options you are used to pass to a Rails controller filter.
88
+ In fact, behind the scenes this method uses a <tt>before_filter</tt> to store the tab in the <tt>@tab_stack</tt> variable.
89
+
90
+ Taking advantage of Rails filter options, you can restrict a tab to a selected group of actions in the same controller.
91
+
92
+ class PostsController < ApplicationController
93
+ set_tab :admin
94
+ set_tab :posts, :only => %w(index show)
95
+ end
96
+
97
+ class ApplicationController < ActionController::Base
98
+ set_tab :admin, :if => :admin_controller?
99
+
100
+ def admin_controller?
101
+ self.class.name =~ /^Admin(::|Controller)/
102
+ end
103
+ end
104
+
105
+
106
+ == Using Namespaces to create Multiple Tabs
107
+
108
+ Namespaces enable you to create and manage tabs in parallels. The best way to demonstrate namespace usage is with an example.
109
+
110
+ Let's assume your application provides a first level navigation menu with 3 elements: :home, :dashboard, :projects. The relationship between your tabs and your controllers is 1:1 so you should end up with the following source code.
111
+
112
+ class HomeController
113
+ set_tab :home
114
+ end
115
+
116
+ class DashboardController
117
+ set_tab :dashboard
118
+ end
119
+
120
+ class ProjectsController
121
+ set_tab :projects
122
+
123
+ def first; end
124
+ def second; end
125
+ def third; end
126
+ end
127
+
128
+ The project controller contains 3 actions and you might want to create a second-level navigation menu. This menu should reflect the navigation status of the user in the project page.
129
+
130
+ Without namespaces, you wouldn't be able to accomplish this task because you already set the current tab value to :projects. You need to create a parallel navigation menu and uniquely identify it with a custom namespace.
131
+ Let's call it :navigation.
132
+
133
+ class ProjectsController
134
+ set_tab :projects
135
+
136
+ # Create an other tab navigation level
137
+ set_tab :first, :navigation, :only => %w(first)
138
+ set_tab :second, :navigation, :only => %w(second)
139
+ set_tab :third, :navigation, :only => %w(third)
140
+
141
+ def first; end
142
+ def second; end
143
+ def third; end
144
+ end
145
+
146
+ Voilà! That's all you need to do. And you can create an unlimited number of namespaces as long as you use an unique name to identify them.
147
+
148
+ The default namespace is called :default. Passing :default as name is the same as don't using any namespace at all. The following lines are equivalent.
149
+
150
+ set_tab :projects
151
+ set_tab :projects, :default
152
+
153
+
154
+ === Rendering Tabs with Namespaces
155
+
156
+ To switch namespace in your template, just pass the :namespace option to the <tt>tabs_tag</tt> helper method.
157
+
158
+ <% tabs_tag do |tab| %>
159
+ <%= tab.home 'Homepage', root_path %>
160
+ <%= tab.dashboard 'Dashboard', dashboard_path %>
161
+ <%= tab.projects 'Projects', projects_path %>
162
+ <% end %>
163
+
164
+ <% tabs_tag :namespace => :navigation do |tab| %>
165
+ <%= tab.first 'First', first_project_path %>
166
+ <%= tab.second 'Second', second_project_path %>
167
+ <%= tab.third 'Account', third_project_path %>
168
+ <% end %>
169
+
170
+ === Namespace scope
171
+
172
+ As a bonus feature, the namespace name does need to be unique within current request scope, not necessarily across the entire application.
173
+
174
+ Back to the previous example, you can reuse the same namespace in the other controllers. In this way, you can reuse your templates as well.
175
+
176
+ class HomeController
177
+ set_tab :home
178
+ end
179
+
180
+ class DashboardController
181
+ set_tab :dashboard
182
+
183
+ set_tab :index, :navigation, :only => %w(index)
184
+ set_tab :common, :navigation, :only => %w(foo bar)
185
+
186
+ # ...
187
+ end
188
+
189
+ class ProjectsController
190
+ set_tab :projects
191
+
192
+ set_tab :first, :navigation, :only => %w(first)
193
+ set_tab :second, :navigation, :only => %w(second)
194
+ set_tab :third, :navigation, :only => %w(third)
195
+
196
+ # ...
197
+ end
198
+
199
+ == Tab Builders
200
+
201
+ The <tt>Builder</tt> is responsible for creating the tabs HTML code. This library is bundled with two <tt>Builders</tt>:
202
+
203
+ <tt>Tabs::Builder</tt>:: this is the abstract interface for any custom builder.
204
+ <tt>Tabs::TabsBuilder</tt>:: this is the default builder.
205
+
206
+ === Understanding the Builder
207
+
208
+ Builders act as formatters. A Builder incapsulates all the logic behind the tab creation including the code required to toggle tabs status.
209
+
210
+ When the <tt>tabs_tag</tt> helper is called, it creates a new <tt>Tabs</tt> instance with selected Builder.
211
+ If you don't provide a custom builder, then <tt>Tabs::TabsBuilder</tt> is used by default.
212
+
213
+ === Creating a custom Builder
214
+
215
+ All builders must extend the base <tt>Tabs::Builder</tt> class and implement at least the <tt>tab_for</tt> method.
216
+ Additional overridable methods include:
217
+
218
+ <tt>open_tabs</tt>:: the method called before the tab set
219
+ <tt>close_tabs</tt>:: the method called after the tab set
220
+ <tt>tab_for</tt>:: the method called to create a single tab item
221
+
222
+ The following example creates a custom tab builder called MainTabBuilder.
223
+
224
+ class MenuTabBuilder < TabsOnRails::Tabs::Builder
225
+ def tab_for(tab, name, options, item_options = {})
226
+ item_options[:class] = (current_tab?(tab) ? 'active' : '')
227
+ @context.content_tag(:li, item_options) do
228
+ @context.link_to(name, options)
229
+ end
230
+ end
231
+ end
232
+
233
+ === Using a custom Builder
234
+
235
+ In your view, simply pass the builder class to the <tt>tabs_tag</tt> method.
236
+
237
+ <% tabs_tag(:builder => MenuTabBuilder) do |tab| %>
238
+ <%= tab.home 'Homepage', root_path %>
239
+ <%= tab.dashboard, 'Dashboard', dashboard_path %>
240
+ <%= tab.account 'Account', account_path, :style => 'float: right;' %>
241
+ <% end %>
242
+
243
+ This is the final result.
244
+
245
+ <ul>
246
+ <li class=""><a href="/">Homepage</a></li>
247
+ <li class="active"><a href="/dashboard">Dashboard</a></li>
248
+ <li class="" style="float: right;"><a href="/account">Account</a></li>
249
+ </ul>
250
+
251
+ == Documentation
252
+
253
+ The library is still under development and this README file might not be contain the latest changes.
254
+ For the full documentation, development roadmap and more information please visit the {project page}[http://code.simonecarletti.com/wiki/tabsonrails].
255
+
256
+
257
+ == Credits
258
+
259
+ Author:: {Simone Carletti}[http://www.simonecarletti.com/] <weppos@weppos.net>
260
+
261
+
262
+ == Resources
263
+
264
+ * {Homepage}[http://code.simonecarletti.com/tabsonrails]
265
+ * {GitHub}[http://github.com/weppos/tabs_on_rails/]
266
+
267
+
268
+ == License
269
+
270
+ Copyright (c) 2009 Simone Carletti, TabsOnRails is released under the MIT license.
data/Rakefile ADDED
@@ -0,0 +1,52 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'echoe'
4
+
5
+ $:.unshift(File.dirname(__FILE__) + "/lib")
6
+ require 'tabs_on_rails'
7
+
8
+
9
+ PKG_NAME = ENV['PKG_NAME'] || TabsOnRails::GEM
10
+ PKG_VERSION = ENV['PKG_VERSION'] || TabsOnRails::VERSION
11
+ PKG_SUMMARY = "A simple Ruby on Rails plugin for creating and managing Tabs."
12
+ PKG_FILES = FileList.new("{lib,rails,tasks,test}/**/*") do |files|
13
+ files.include %w(*.{rdoc,rb})
14
+ files.include %w(Rakefile)
15
+ end
16
+ RUBYFORGE_PROJECT = nil
17
+
18
+ if ENV['SNAPSHOT'].to_i == 1
19
+ PKG_VERSION << "." << Time.now.utc.strftime("%Y%m%d%H%M%S")
20
+ end
21
+
22
+
23
+ Echoe.new(PKG_NAME, PKG_VERSION) do |p|
24
+ p.author = "Simone Carletti"
25
+ p.email = "weppos@weppos.net"
26
+ p.summary = PKG_SUMMARY
27
+ p.description = <<-EOD
28
+ TabsOnRails is a simple Ruby on Rails plugin for creating and managing Tabs. \
29
+ It provides helpers for creating tabs with a flexible interface.
30
+ EOD
31
+ p.url = "http://code.simonecarletti.com/tabsonrails"
32
+ p.project = RUBYFORGE_PROJECT
33
+
34
+ p.need_zip = true
35
+ p.rcov_options = ["--main << README.rdoc -x Rakefile -x rcov"]
36
+ p.rdoc_pattern = /^(lib|CHANGELOG.rdoc|README.rdoc|LICENSE.rdoc)/
37
+
38
+ p.development_dependencies += ["rake >=0.8",
39
+ "echoe >=3.1"]
40
+ end
41
+
42
+
43
+ begin
44
+ require 'code_statistics'
45
+ desc "Show library's code statistics"
46
+ task :stats do
47
+ CodeStatistics.new(["TabsOnRails", "lib"],
48
+ ["Tests", "test"]).to_s
49
+ end
50
+ rescue LoadError
51
+ puts "CodeStatistics (Rails) is not available"
52
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require File.join(File.dirname(__FILE__), 'rails', 'init')
data/install.rb ADDED
@@ -0,0 +1 @@
1
+ # Install hook code here
@@ -0,0 +1,132 @@
1
+ #
2
+ # = Tabs on Rails
3
+ #
4
+ # A simple Ruby on Rails plugin for creating and managing Tabs.
5
+ #
6
+ #
7
+ # Category:: Rails
8
+ # Package:: TabsOnRails
9
+ # Author:: Simone Carletti <weppos@weppos.net>
10
+ # License:: MIT License
11
+ #
12
+ #--
13
+ #
14
+ #++
15
+
16
+
17
+ module TabsOnRails
18
+
19
+ module ControllerMixin
20
+
21
+ def self.included(base)
22
+ base.extend ClassMethods
23
+ base.class_eval do
24
+ include InstanceMethods
25
+ helper HelperMethods
26
+ helper_method :current_tab, :current_tab?
27
+ end
28
+ end
29
+
30
+ module ClassMethods
31
+
32
+ # Sets the value for current tab to given name.
33
+ #
34
+ # set_tab :foo
35
+ #
36
+ # If you need to manage multiple tabs, then you can pass an optional namespace.
37
+ #
38
+ # set_tab :foo, :namespace
39
+ #
40
+ # The <tt>set_tab</tt> method understands all options you are used to pass to a Rails controller filter.
41
+ # In fact, behind the scenes this method uses a <tt>before_filter</tt>
42
+ # to store the tab in the <tt>@tab_stack</tt> variable.
43
+ # For example, you can set the tab only for a restricted group of actions in the same controller
44
+ # using the <tt>:only</tt> and <tt>:except</tt> options.
45
+ #
46
+ # ==== Examples
47
+ #
48
+ # set_tab :foo
49
+ # set_tab :foo, :except => :new
50
+ # set_tab :foo, :only => [ :index, :show ]
51
+ #
52
+ # set_tab :foo, :namespace
53
+ # set_tab :foo, :namespace, :only => [ :index, :show ]
54
+ #
55
+ def set_tab(*args)
56
+ options = args.extract_options!
57
+ name, namespace = args
58
+
59
+ before_filter(options) do |controller|
60
+ controller.send(:set_tab, name, namespace)
61
+ end
62
+ end
63
+
64
+ end
65
+
66
+ module InstanceMethods
67
+ protected
68
+
69
+ # Sets the value for current tab to given name.
70
+ # If you need to manage multiple tabs, then you can pass an optional namespace.
71
+ #
72
+ # ==== Examples
73
+ #
74
+ # set_tab :homepage
75
+ # set_tab :dashboard, :menu
76
+ #
77
+ def set_tab(name, namespace = nil)
78
+ tab_stack[namespace || :default] = name
79
+ end
80
+
81
+ # Returns the value for current tab in the default namespace,
82
+ # or nil if no tab has been set before.
83
+ # You can pass <tt>namespace</tt> to get the value of current tab for a different namespace.
84
+ #
85
+ # ==== Examples
86
+ #
87
+ # current_tab # => nil
88
+ # current_tab :menu # => nil
89
+ #
90
+ # set_tab :homepage
91
+ # set_tab :dashboard, :menu
92
+ #
93
+ # current_tab # => :homepage
94
+ # current_tab :menu # => :dashboard
95
+ #
96
+ def current_tab(namespace = nil)
97
+ tab_stack[namespace || :default]
98
+ end
99
+
100
+ # Returns whether the current tab in <tt>namespace</tt> matches <tt>name</tt>.
101
+ def current_tab?(name, namespace = nil)
102
+ current_tab(namespace).to_s == name.to_s
103
+ end
104
+
105
+ # Initializes and/or returns the tab stack.
106
+ # You won't probably need to use this method directly
107
+ # unless you are trying to hack the plugin architecture.
108
+ def tab_stack
109
+ @tab_stack ||= {}
110
+ end
111
+
112
+ end
113
+
114
+ module HelperMethods
115
+
116
+ def tabs_tag(options = {}, &block)
117
+ raise LocalJumpError, "no block given" unless block_given?
118
+
119
+ unless options.is_a?(Hash)
120
+ ActiveSupport::Deprecation.warn('tabs_tag takes a Hash of options, no longer a builder class. Use :builder => BuilderClass.', caller)
121
+ options = { :builder => options }
122
+ end
123
+ tabs = Tabs.new(self, { :namespace => :default }.merge(options))
124
+
125
+ concat(tabs.open_tabs.to_s)
126
+ yield tabs
127
+ concat(tabs.close_tabs.to_s)
128
+ end
129
+
130
+ end
131
+ end
132
+ end