activeadmin 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activeadmin might be problematic. Click here for more details.
- data/.document +5 -0
- data/.gitignore +25 -0
- data/Gemfile +16 -0
- data/LICENSE +20 -0
- data/README.rdoc +201 -0
- data/Rakefile +71 -0
- data/active_admin.gemspec +22 -0
- data/lib/active_admin.rb +229 -0
- data/lib/active_admin/action_builder.rb +60 -0
- data/lib/active_admin/action_items.rb +48 -0
- data/lib/active_admin/asset_registration.rb +34 -0
- data/lib/active_admin/breadcrumbs.rb +26 -0
- data/lib/active_admin/dashboards.rb +50 -0
- data/lib/active_admin/dashboards/dashboard_controller.rb +40 -0
- data/lib/active_admin/dashboards/renderer.rb +45 -0
- data/lib/active_admin/dashboards/section.rb +43 -0
- data/lib/active_admin/dashboards/section_renderer.rb +28 -0
- data/lib/active_admin/filters.rb +189 -0
- data/lib/active_admin/form_builder.rb +91 -0
- data/lib/active_admin/helpers/optional_display.rb +34 -0
- data/lib/active_admin/menu.rb +42 -0
- data/lib/active_admin/menu_item.rb +67 -0
- data/lib/active_admin/namespace.rb +111 -0
- data/lib/active_admin/page_config.rb +15 -0
- data/lib/active_admin/pages.rb +11 -0
- data/lib/active_admin/pages/base.rb +92 -0
- data/lib/active_admin/pages/edit.rb +21 -0
- data/lib/active_admin/pages/index.rb +58 -0
- data/lib/active_admin/pages/index/blog.rb +65 -0
- data/lib/active_admin/pages/index/table.rb +48 -0
- data/lib/active_admin/pages/index/thumbnails.rb +40 -0
- data/lib/active_admin/pages/new.rb +21 -0
- data/lib/active_admin/pages/show.rb +54 -0
- data/lib/active_admin/renderer.rb +72 -0
- data/lib/active_admin/resource.rb +96 -0
- data/lib/active_admin/resource_controller.rb +325 -0
- data/lib/active_admin/sidebar.rb +78 -0
- data/lib/active_admin/table_builder.rb +162 -0
- data/lib/active_admin/tabs_renderer.rb +39 -0
- data/lib/active_admin/version.rb +3 -0
- data/lib/active_admin/view_helpers.rb +106 -0
- data/lib/active_admin/views/active_admin_dashboard/index.html.erb +1 -0
- data/lib/active_admin/views/active_admin_default/edit.html.erb +1 -0
- data/lib/active_admin/views/active_admin_default/index.csv.erb +2 -0
- data/lib/active_admin/views/active_admin_default/index.html.erb +1 -0
- data/lib/active_admin/views/active_admin_default/new.html.erb +1 -0
- data/lib/active_admin/views/active_admin_default/show.html.erb +1 -0
- data/lib/active_admin/views/layouts/active_admin.html.erb +40 -0
- data/lib/activeadmin.rb +1 -0
- data/lib/generators/active_admin/install/install_generator.rb +31 -0
- data/lib/generators/active_admin/install/templates/active_admin.css +325 -0
- data/lib/generators/active_admin/install/templates/active_admin.js +10 -0
- data/lib/generators/active_admin/install/templates/active_admin.rb +47 -0
- data/lib/generators/active_admin/install/templates/active_admin_vendor.js +382 -0
- data/lib/generators/active_admin/install/templates/dashboards.rb +36 -0
- data/lib/generators/active_admin/install/templates/images/orderable.gif +0 -0
- data/lib/generators/active_admin/resource/resource_generator.rb +16 -0
- data/lib/generators/active_admin/resource/templates/admin.rb +3 -0
- data/spec/integration/dashboard_spec.rb +44 -0
- data/spec/integration/index_as_blog_spec.rb +65 -0
- data/spec/integration/index_as_csv_spec.rb +40 -0
- data/spec/integration/index_as_table_spec.rb +160 -0
- data/spec/integration/index_as_thumbnails_spec.rb +43 -0
- data/spec/integration/layout_spec.rb +82 -0
- data/spec/integration/new_view_spec.rb +52 -0
- data/spec/integration/show_view_spec.rb +91 -0
- data/spec/spec_helper.rb +104 -0
- data/spec/support/rails_template.rb +19 -0
- data/spec/unit/action_builder_spec.rb +76 -0
- data/spec/unit/action_items_spec.rb +41 -0
- data/spec/unit/active_admin_spec.rb +52 -0
- data/spec/unit/asset_registration_spec.rb +37 -0
- data/spec/unit/controller_filters_spec.rb +26 -0
- data/spec/unit/dashboard_section_spec.rb +63 -0
- data/spec/unit/dashboards_spec.rb +59 -0
- data/spec/unit/filter_form_builder_spec.rb +157 -0
- data/spec/unit/form_builder_spec.rb +238 -0
- data/spec/unit/menu_item_spec.rb +137 -0
- data/spec/unit/menu_spec.rb +53 -0
- data/spec/unit/namespace_spec.rb +107 -0
- data/spec/unit/registration_spec.rb +46 -0
- data/spec/unit/renderer_spec.rb +100 -0
- data/spec/unit/resource_controller_spec.rb +48 -0
- data/spec/unit/resource_spec.rb +197 -0
- data/spec/unit/routing_spec.rb +12 -0
- data/spec/unit/sidebar_spec.rb +96 -0
- data/spec/unit/table_builder_spec.rb +162 -0
- data/spec/unit/tabs_renderer_spec.rb +34 -0
- metadata +247 -0
@@ -0,0 +1,325 @@
|
|
1
|
+
require 'inherited_views'
|
2
|
+
require 'active_admin/pages'
|
3
|
+
|
4
|
+
module ActiveAdmin
|
5
|
+
class ResourceController < ::InheritedViews::Base
|
6
|
+
|
7
|
+
# Add our views to the view path
|
8
|
+
ActionController::Base.append_view_path File.expand_path('../views', __FILE__)
|
9
|
+
self.default_views = 'active_admin_default'
|
10
|
+
|
11
|
+
helper ::ActiveAdmin::ViewHelpers
|
12
|
+
|
13
|
+
layout 'active_admin'
|
14
|
+
|
15
|
+
class_inheritable_accessor :form_config
|
16
|
+
|
17
|
+
include ActiveAdmin::Breadcrumbs
|
18
|
+
include ActiveAdmin::Sidebar
|
19
|
+
include ActiveAdmin::ActionItems
|
20
|
+
include ActiveAdmin::Filters
|
21
|
+
include ActiveAdmin::ActionBuilder
|
22
|
+
|
23
|
+
respond_to :html, :xml, :json
|
24
|
+
respond_to :csv, :only => :index
|
25
|
+
|
26
|
+
add_breadcrumb "Dashboard", "/admin"
|
27
|
+
|
28
|
+
before_filter :add_section_breadcrumb
|
29
|
+
before_filter :set_current_tab
|
30
|
+
before_filter :setup_pagination_for_csv
|
31
|
+
|
32
|
+
class << self
|
33
|
+
# Reference to the Resource object which initialized
|
34
|
+
# this controller
|
35
|
+
attr_accessor :active_admin_config
|
36
|
+
|
37
|
+
def active_admin_config=(config)
|
38
|
+
@active_admin_config = config
|
39
|
+
defaults :resource_class => config.resource
|
40
|
+
end
|
41
|
+
|
42
|
+
def set_page_config(page, config)
|
43
|
+
active_admin_config.page_configs[page] = config
|
44
|
+
end
|
45
|
+
|
46
|
+
def get_page_config(page)
|
47
|
+
active_admin_config.page_configs[page]
|
48
|
+
end
|
49
|
+
|
50
|
+
def reset_page_config!(page)
|
51
|
+
active_admin_config.page_configs[page] = nil
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
# Setting the menu options
|
56
|
+
def menu(options = {})
|
57
|
+
active_admin_config.menu(options)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Scope this controller to some object which has a relation
|
61
|
+
# to the resource. Can either accept a block or a symbol
|
62
|
+
# of a method to call.
|
63
|
+
#
|
64
|
+
# Eg:
|
65
|
+
#
|
66
|
+
# ActiveAdmin.register Post do
|
67
|
+
# scope_to :current_user
|
68
|
+
# end
|
69
|
+
#
|
70
|
+
# Then every time we instantiate and object, it would call
|
71
|
+
#
|
72
|
+
# current_user.posts.build
|
73
|
+
#
|
74
|
+
# By default Active Admin will use the resource name to build a
|
75
|
+
# method to call as the association. If its different, you can
|
76
|
+
# pass in the association_method as an option.
|
77
|
+
#
|
78
|
+
# scope_to :current_user, :association_method => :blog_posts
|
79
|
+
#
|
80
|
+
# will result in the following
|
81
|
+
#
|
82
|
+
# current_user.blog_posts.build
|
83
|
+
#
|
84
|
+
def scope_to(*args, &block)
|
85
|
+
options = args.extract_options!
|
86
|
+
method = args.first
|
87
|
+
|
88
|
+
active_admin_config.scope_to = block_given? ? block : method
|
89
|
+
active_admin_config.scope_to_association_method = options[:association_method]
|
90
|
+
end
|
91
|
+
|
92
|
+
#
|
93
|
+
# Index Config
|
94
|
+
#
|
95
|
+
|
96
|
+
# Configure the index page for the resource
|
97
|
+
def index(options = {}, &block)
|
98
|
+
options[:as] ||= :table
|
99
|
+
set_page_config :index, ActiveAdmin::PageConfig.new(options, &block)
|
100
|
+
end
|
101
|
+
|
102
|
+
# Configure the show page for the resource
|
103
|
+
def show(options = {}, &block)
|
104
|
+
set_page_config :show, ActiveAdmin::PageConfig.new(options, &block)
|
105
|
+
end
|
106
|
+
|
107
|
+
# Define the getting and re-setter for each configurable page
|
108
|
+
[:index, :show].each do |page|
|
109
|
+
# eg: index_config
|
110
|
+
define_method :"#{page}_config" do
|
111
|
+
get_page_config(page)
|
112
|
+
end
|
113
|
+
|
114
|
+
# eg: reset_index_config!
|
115
|
+
define_method :"reset_#{page}_config!" do
|
116
|
+
reset_page_config! page
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
#
|
122
|
+
# Form Config
|
123
|
+
#
|
124
|
+
|
125
|
+
def form(options = {}, &block)
|
126
|
+
options[:block] = block
|
127
|
+
self.form_config = options
|
128
|
+
end
|
129
|
+
|
130
|
+
def form_config
|
131
|
+
read_inheritable_attribute(:form_config) || default_form_config
|
132
|
+
end
|
133
|
+
|
134
|
+
def reset_form_config!
|
135
|
+
self.form_config = nil
|
136
|
+
end
|
137
|
+
|
138
|
+
def default_form_config
|
139
|
+
config = {}
|
140
|
+
config[:block] = lambda do |f|
|
141
|
+
f.inputs
|
142
|
+
f.buttons
|
143
|
+
end
|
144
|
+
config
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
# Default Sidebar Sections
|
150
|
+
sidebar :filters, :only => :index do
|
151
|
+
active_admin_filters_form_for @search, filters_config
|
152
|
+
end
|
153
|
+
|
154
|
+
# Default Action Item Links
|
155
|
+
action_item :only => :show do
|
156
|
+
if controller.public_methods.include?('edit')
|
157
|
+
link_to "Edit #{active_admin_config.resource_name}", edit_resource_path(resource)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
action_item :only => :show do
|
162
|
+
if controller.public_methods.include?("destroy")
|
163
|
+
link_to "Delete #{active_admin_config.resource_name}",
|
164
|
+
resource_path(resource),
|
165
|
+
:method => :delete, :confirm => "Are you sure you want to delete this?"
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
action_item :except => [:new, :show] do
|
170
|
+
if controller.public_methods.include?('new')
|
171
|
+
link_to "New #{active_admin_config.resource_name}", new_resource_path
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
#
|
176
|
+
# Actions
|
177
|
+
#
|
178
|
+
|
179
|
+
def index
|
180
|
+
index! do |format|
|
181
|
+
format.html { render_or_default 'index' }
|
182
|
+
format.csv {
|
183
|
+
@csv_columns = resource_class.columns.collect{ |column| column.name.to_sym }
|
184
|
+
render_or_default 'index'
|
185
|
+
}
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
private
|
190
|
+
|
191
|
+
def collection
|
192
|
+
get_collection_ivar || set_collection_ivar(active_admin_collection)
|
193
|
+
end
|
194
|
+
|
195
|
+
def active_admin_collection
|
196
|
+
chain = scoped_collection
|
197
|
+
chain = sort_order(chain)
|
198
|
+
chain = search(chain)
|
199
|
+
chain = paginate(chain)
|
200
|
+
chain
|
201
|
+
end
|
202
|
+
|
203
|
+
# Override this method in your controllers to modify the start point
|
204
|
+
# of our searches and index.
|
205
|
+
#
|
206
|
+
# This method should return an ActiveRecord::Relation object so that
|
207
|
+
# the searching and filtering can be applied on top
|
208
|
+
def scoped_collection
|
209
|
+
end_of_association_chain
|
210
|
+
end
|
211
|
+
|
212
|
+
def begin_of_association_chain
|
213
|
+
return nil unless active_admin_config.scope_to
|
214
|
+
case active_admin_config.scope_to
|
215
|
+
when Proc
|
216
|
+
instance_eval &active_admin_config.scope_to
|
217
|
+
when Symbol
|
218
|
+
send active_admin_config.scope_to
|
219
|
+
else
|
220
|
+
raise ArgumentError, "#scope_to accepts a symbol or a block"
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
# Overriding from InheritedResources::BaseHelpers
|
225
|
+
#
|
226
|
+
# Returns the method for the association chain when using
|
227
|
+
# the scope_to option
|
228
|
+
def method_for_association_chain
|
229
|
+
active_admin_config.scope_to_association_method || super
|
230
|
+
end
|
231
|
+
|
232
|
+
# Allow more records for csv files
|
233
|
+
def setup_pagination_for_csv
|
234
|
+
@per_page = 10_000 if request.format == 'text/csv'
|
235
|
+
end
|
236
|
+
|
237
|
+
def paginate(chain)
|
238
|
+
chain.paginate(:page => params[:page], :per_page => @per_page || ActiveAdmin.default_per_page)
|
239
|
+
end
|
240
|
+
|
241
|
+
def sort_order(chain)
|
242
|
+
params[:order] ||= active_admin_config.sort_order
|
243
|
+
if params[:order] && params[:order] =~ /^([\w\_\.]+)_(desc|asc)$/
|
244
|
+
chain.order("#{$1} #{$2}")
|
245
|
+
else
|
246
|
+
chain # just return the chain
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
def search(chain)
|
251
|
+
@search = chain.search(clean_search_params(params[:q]))
|
252
|
+
end
|
253
|
+
|
254
|
+
def clean_search_params(search_params)
|
255
|
+
return {} unless search_params.is_a?(Hash)
|
256
|
+
search_params = search_params.dup
|
257
|
+
search_params.delete_if do |key, value|
|
258
|
+
value == ""
|
259
|
+
end
|
260
|
+
search_params
|
261
|
+
end
|
262
|
+
|
263
|
+
# Gets called as a before filter to set the section's breadcrumb
|
264
|
+
def add_section_breadcrumb
|
265
|
+
add_breadcrumb active_admin_config.plural_resource_name, collection_path
|
266
|
+
end
|
267
|
+
|
268
|
+
# Set's @current_tab to be name of the tab to mark as current
|
269
|
+
# Get's called through a before filter
|
270
|
+
def set_current_tab
|
271
|
+
@current_tab = active_admin_config.parent_menu_item_name ||
|
272
|
+
active_admin_config.menu_item_name
|
273
|
+
end
|
274
|
+
|
275
|
+
def active_admin_config
|
276
|
+
self.class.active_admin_config
|
277
|
+
end
|
278
|
+
helper_method :active_admin_config
|
279
|
+
|
280
|
+
def index_config
|
281
|
+
@index_config ||= self.class.index_config
|
282
|
+
end
|
283
|
+
helper_method :index_config
|
284
|
+
|
285
|
+
def show_config
|
286
|
+
@show_config ||= self.class.show_config
|
287
|
+
end
|
288
|
+
helper_method :show_config
|
289
|
+
|
290
|
+
def form_config
|
291
|
+
@form_config ||= self.class.form_config
|
292
|
+
end
|
293
|
+
helper_method :form_config
|
294
|
+
|
295
|
+
def current_menu
|
296
|
+
active_admin_config.namespace.menu
|
297
|
+
end
|
298
|
+
helper_method :current_menu
|
299
|
+
|
300
|
+
def skip_sidebar!
|
301
|
+
@skip_sidebar = true
|
302
|
+
end
|
303
|
+
helper_method :skip_sidebar!
|
304
|
+
|
305
|
+
def skip_sidebar?
|
306
|
+
@skip_sidebar == true
|
307
|
+
end
|
308
|
+
helper_method :skip_sidebar?
|
309
|
+
|
310
|
+
# Returns the renderer class to use for the given action.
|
311
|
+
#
|
312
|
+
# TODO: This needs to be wrapped into a default config as well
|
313
|
+
# as overrideable on each controller
|
314
|
+
def renderer_for(action)
|
315
|
+
{
|
316
|
+
:index => ::ActiveAdmin::Pages::Index,
|
317
|
+
:new => ::ActiveAdmin::Pages::New,
|
318
|
+
:show => ::ActiveAdmin::Pages::Show,
|
319
|
+
:edit => ::ActiveAdmin::Pages::Edit
|
320
|
+
}[action]
|
321
|
+
end
|
322
|
+
helper_method :renderer_for
|
323
|
+
|
324
|
+
end
|
325
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'active_admin/helpers/optional_display'
|
2
|
+
|
3
|
+
module ActiveAdmin
|
4
|
+
module Sidebar
|
5
|
+
|
6
|
+
def self.included(base)
|
7
|
+
base.send :extend, ClassMethods
|
8
|
+
base.class_inheritable_accessor :sidebar_sections
|
9
|
+
base.sidebar_sections = []
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
|
14
|
+
def sidebar(name, options = {}, &block)
|
15
|
+
self.sidebar_sections << ActiveAdmin::Sidebar::Section.new(name, options, &block)
|
16
|
+
end
|
17
|
+
|
18
|
+
def clear_sidebar_sections!
|
19
|
+
self.sidebar_sections = []
|
20
|
+
end
|
21
|
+
|
22
|
+
def sidebar_sections_for(action)
|
23
|
+
sidebar_sections.select{|section| section.display_on?(action) }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class Section
|
28
|
+
include ActiveAdmin::OptionalDisplay
|
29
|
+
|
30
|
+
attr_accessor :name, :options, :block
|
31
|
+
|
32
|
+
def initialize(name, options = {}, &block)
|
33
|
+
@name, @options, @block = name, options, block
|
34
|
+
normalize_display_options!
|
35
|
+
end
|
36
|
+
|
37
|
+
# The id gets used for the div in the view
|
38
|
+
def id
|
39
|
+
name.to_s.downcase.underscore + '_sidebar_section'
|
40
|
+
end
|
41
|
+
|
42
|
+
# The title gets displayed within the section in the view
|
43
|
+
def title
|
44
|
+
name.to_s.titlecase
|
45
|
+
end
|
46
|
+
|
47
|
+
# If a block is not passed in, the name of the partial to render
|
48
|
+
def partial_name
|
49
|
+
options[:partial] || "#{name.to_s.downcase.gsub(' ', '_')}_sidebar"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class Renderer < ActiveAdmin::Renderer
|
54
|
+
def to_html(sidebar_sections)
|
55
|
+
sidebar_sections.collect do |section|
|
56
|
+
title = content_tag :h3, section.title
|
57
|
+
content = content_tag :div, sidebar_content(section)
|
58
|
+
|
59
|
+
content_tag :div, :class => 'sidebar_section', :id => section.id do
|
60
|
+
title + content
|
61
|
+
end
|
62
|
+
end.join
|
63
|
+
end
|
64
|
+
|
65
|
+
# If a block exists, render the block. Otherwise render a partial
|
66
|
+
def sidebar_content(section)
|
67
|
+
if section.block
|
68
|
+
instance_eval(§ion.block)
|
69
|
+
else
|
70
|
+
capture do
|
71
|
+
render section.partial_name
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
module ActiveAdmin
|
2
|
+
class TableBuilder
|
3
|
+
|
4
|
+
attr_reader :columns
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@columns = []
|
8
|
+
yield self if block_given?
|
9
|
+
end
|
10
|
+
|
11
|
+
def column(*args, &block)
|
12
|
+
@columns << Column.new(*args, &block)
|
13
|
+
end
|
14
|
+
|
15
|
+
# This method allows you to add many columns at
|
16
|
+
# once or returns the list of all columns.
|
17
|
+
#
|
18
|
+
# TableBuilder.new do |t|
|
19
|
+
# t.columns :first, :second, :third
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# OR
|
23
|
+
#
|
24
|
+
# builder.columns #=> [:first, :second, :third]
|
25
|
+
def columns(first_column = nil, *more)
|
26
|
+
return @columns unless first_column
|
27
|
+
[first_column, more].flatten.each do |c|
|
28
|
+
column(c)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Helper method to quickly render a table builder
|
33
|
+
def to_html(view, collection, options)
|
34
|
+
Renderer.new(view).to_html(self, collection, options)
|
35
|
+
end
|
36
|
+
|
37
|
+
class Renderer < ActiveAdmin::Renderer
|
38
|
+
def to_html(builder, collection, options = {})
|
39
|
+
@builder, @collection = builder, collection
|
40
|
+
@sortable = options.delete(:sortable) || false
|
41
|
+
table_options = {
|
42
|
+
:border => 0,
|
43
|
+
:cellpadding => 0,
|
44
|
+
:cellspacing => 0
|
45
|
+
}.merge(options)
|
46
|
+
content_tag :table, table_options do
|
47
|
+
table_head + table_body
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def columns
|
52
|
+
@columns ||= @builder.columns.select do |column|
|
53
|
+
instance_eval &column.conditional_block
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def sortable?
|
58
|
+
@sortable
|
59
|
+
end
|
60
|
+
|
61
|
+
def table_head
|
62
|
+
content_tag :thead do
|
63
|
+
columns.collect do |column|
|
64
|
+
if sortable? && column.sortable?
|
65
|
+
sortable_header_for column.title, column.sort_key
|
66
|
+
else
|
67
|
+
content_tag :th, column.title
|
68
|
+
end
|
69
|
+
end.join
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def table_body
|
74
|
+
content_tag :tbody do
|
75
|
+
@collection.collect{|item| table_row(item) }.join
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def table_row(item)
|
80
|
+
content_tag :tr, :class => cycle('odd', 'even') do
|
81
|
+
columns.collect{|column| table_cell(column, item) }.join
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def resource
|
86
|
+
@resource
|
87
|
+
end
|
88
|
+
|
89
|
+
def table_cell(column, item)
|
90
|
+
row_content = call_method_or_proc_on(item, column.data) || ""
|
91
|
+
l(row_content) if [Date, DateTime, Time].include?(row_content)
|
92
|
+
content_tag :td, row_content
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
class Column
|
98
|
+
|
99
|
+
attr_accessor :title, :data
|
100
|
+
|
101
|
+
def initialize(*args, &block)
|
102
|
+
@options = default_options.merge(args.last.is_a?(::Hash) ? args.pop : {})
|
103
|
+
@title = pretty_title args[0]
|
104
|
+
@data = args[1] || args[0]
|
105
|
+
@data = block if block
|
106
|
+
end
|
107
|
+
|
108
|
+
def sortable?
|
109
|
+
if @data.is_a?(Proc)
|
110
|
+
[String, Symbol].include?(@options[:sortable].class)
|
111
|
+
else
|
112
|
+
@options[:sortable]
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
#
|
117
|
+
# Returns the key to be used for sorting this column
|
118
|
+
#
|
119
|
+
# Defaults to the column's method if its a symbol
|
120
|
+
# column :username
|
121
|
+
# # => Sort key will be set to 'username'
|
122
|
+
#
|
123
|
+
# You can set the sort key by passing a string or symbol
|
124
|
+
# to the sortable option:
|
125
|
+
# column :username, :sortable => 'other_column_to_sort_on'
|
126
|
+
#
|
127
|
+
# If you pass a block to be rendered for this column, the column
|
128
|
+
# will not be sortable unless you pass a string to sortable to
|
129
|
+
# sort the column on:
|
130
|
+
#
|
131
|
+
# column('Username', :sortable => 'login'){ @user.pretty_name }
|
132
|
+
# # => Sort key will be 'login'
|
133
|
+
#
|
134
|
+
def sort_key
|
135
|
+
if @options[:sortable] == true || @options[:sortable] == false
|
136
|
+
@data.to_s
|
137
|
+
else
|
138
|
+
@options[:sortable].to_s
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def conditional_block
|
143
|
+
@options[:if]
|
144
|
+
end
|
145
|
+
|
146
|
+
private
|
147
|
+
|
148
|
+
def pretty_title(raw)
|
149
|
+
raw.is_a?(Symbol) ? raw.to_s.split('_').collect{|s| s.capitalize }.join(' ') : raw
|
150
|
+
end
|
151
|
+
|
152
|
+
def default_options
|
153
|
+
{
|
154
|
+
:sortable => true,
|
155
|
+
:if => proc{ true }
|
156
|
+
}
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|
162
|
+
end
|