tabs_on_rails 0.8.1

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.
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