simple_admin 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/.rspec +2 -0
- data/Gemfile +12 -0
- data/README.rdoc +318 -0
- data/Rakefile +67 -0
- data/TODO.rdoc +4 -0
- data/app/assets/images/simple_admin/active_admin/admin_notes_icon.png +0 -0
- data/app/assets/images/simple_admin/active_admin/loading.gif +0 -0
- data/app/assets/images/simple_admin/active_admin/nested_menu_arrow.gif +0 -0
- data/app/assets/images/simple_admin/active_admin/nested_menu_arrow_dark.gif +0 -0
- data/app/assets/images/simple_admin/active_admin/orderable.png +0 -0
- data/app/assets/javascripts/simple_admin/active_admin.js +434 -0
- data/app/assets/stylesheets/simple_admin/active_admin.css +1445 -0
- data/app/controllers/simple_admin/admin_controller.rb +117 -0
- data/app/helpers/simple_admin/admin_helper.rb +11 -0
- data/app/helpers/simple_admin/display_helper.rb +38 -0
- data/app/helpers/simple_admin/filter_helper.rb +147 -0
- data/app/helpers/simple_admin/header_helper.rb +60 -0
- data/app/helpers/simple_admin/path_helper.rb +12 -0
- data/app/helpers/simple_admin/sidebar_helper.rb +9 -0
- data/app/helpers/simple_admin/table_helper.rb +39 -0
- data/app/helpers/simple_admin/title_helper.rb +35 -0
- data/app/views/layouts/simple_admin.html.erb +41 -0
- data/app/views/simple_admin/admin/_form.html.erb +16 -0
- data/app/views/simple_admin/admin/edit.html.erb +7 -0
- data/app/views/simple_admin/admin/index.csv.erb +19 -0
- data/app/views/simple_admin/admin/index.html.erb +82 -0
- data/app/views/simple_admin/admin/new.html.erb +7 -0
- data/app/views/simple_admin/admin/show.html.erb +22 -0
- data/config/routes.rb +8 -0
- data/lib/rails/generators/simple_admin/simple_admin_generator.rb +33 -0
- data/lib/rails/generators/simple_admin/templates/initializer.rb +76 -0
- data/lib/simple_admin.rb +100 -0
- data/lib/simple_admin/attributes.rb +80 -0
- data/lib/simple_admin/breadcrumbs.rb +24 -0
- data/lib/simple_admin/builder.rb +35 -0
- data/lib/simple_admin/engine.rb +8 -0
- data/lib/simple_admin/filters.rb +5 -0
- data/lib/simple_admin/interface.rb +55 -0
- data/lib/simple_admin/section.rb +30 -0
- data/lib/simple_admin/version.rb +3 -0
- data/rails/init.rb +2 -0
- data/simple_admin.gemspec +34 -0
- data/spec/acceptance/admin_thing_spec.rb +13 -0
- data/spec/controllers/simple_admin/admin_controller_spec.rb +95 -0
- data/spec/factories.rb +14 -0
- data/spec/simple_admin/attributes_spec.rb +106 -0
- data/spec/simple_admin/breadcrumbs_spec.rb +18 -0
- data/spec/simple_admin/builder_spec.rb +57 -0
- data/spec/simple_admin/engine_spec.rb +9 -0
- data/spec/simple_admin/filters_spec.rb +16 -0
- data/spec/simple_admin/interface_spec.rb +98 -0
- data/spec/simple_admin/section_spec.rb +63 -0
- data/spec/simple_admin/simple_admin_spec.rb +68 -0
- data/spec/spec_helper.rb +32 -0
- metadata +285 -0
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'kaminari'
|
2
|
+
require 'meta_search'
|
3
|
+
|
4
|
+
module SimpleAdmin
|
5
|
+
class AdminController < ::ApplicationController
|
6
|
+
before_filter :require_user
|
7
|
+
before_filter :lookup_interface
|
8
|
+
before_filter :lookup_resource, :only => [:show, :edit, :update, :destroy]
|
9
|
+
before_filter :handle_before
|
10
|
+
|
11
|
+
unloadable
|
12
|
+
|
13
|
+
respond_to :csv, :json, :xml, :html
|
14
|
+
|
15
|
+
helper SimpleAdmin::AdminHelper
|
16
|
+
|
17
|
+
layout 'simple_admin'
|
18
|
+
|
19
|
+
def index
|
20
|
+
@collection = @interface.constant
|
21
|
+
@collection = @collection.order("#{@interface.constant.table_name}.#{$1} #{$2}") if params[:order] && params[:order] =~ /^([\w\_\.]+)_(desc|asc)$/
|
22
|
+
@collection = @collection.metasearch(clean_search_params(params))
|
23
|
+
@collection = @collection.page(params[:page]).per(@per_page || SimpleAdmin.default_per_page) if params[:format].blank? || params[:format] == 'html'
|
24
|
+
respond_with(@collection)
|
25
|
+
end
|
26
|
+
|
27
|
+
def show
|
28
|
+
@resource = @interface.constant.find(params[:id])
|
29
|
+
respond_with(@resource)
|
30
|
+
end
|
31
|
+
|
32
|
+
def new
|
33
|
+
@resource = @interface.constant.new
|
34
|
+
respond_with(@resource)
|
35
|
+
end
|
36
|
+
|
37
|
+
def edit
|
38
|
+
respond_with(@resource)
|
39
|
+
end
|
40
|
+
|
41
|
+
def create
|
42
|
+
@resource = @interface.constant.new(params[@interface.member.to_sym])
|
43
|
+
# respond_with will fail without explicit urls
|
44
|
+
respond_to do |format|
|
45
|
+
if @resource.save
|
46
|
+
format.html { redirect_to send("simple_admin_#{@interface.member}_path", @resource), :notice => "#{@interface.member.titleize} was successfully created." }
|
47
|
+
format.json { render :json => @resource, :status => :created, :location => send("simple_admin_#{@interface.member}_path", @resource) }
|
48
|
+
format.xml { render :xml => @resource, :status => :created, :location => send("simple_admin_#{@interface.member}_path", @resource) }
|
49
|
+
else
|
50
|
+
format.html { render :action => "new" }
|
51
|
+
format.json { render :json => @resource.errors, :status => :unprocessable_entity }
|
52
|
+
format.xml { render :xml => @resource.errors, :status => :unprocessable_entity }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def update
|
58
|
+
# respond_with will fail without explicit urls
|
59
|
+
respond_to do |format|
|
60
|
+
if @resource.update_attributes(params[@interface.member.to_sym])
|
61
|
+
format.html { redirect_to send("simple_admin_#{@interface.member}_path", @resource), :notice => "#{@interface.member.titleize} was successfully updated." }
|
62
|
+
format.json { head :ok }
|
63
|
+
format.xml { head :ok }
|
64
|
+
else
|
65
|
+
format.html { render :action => "edit" }
|
66
|
+
format.json { render :json => @resource.errors, :status => :unprocessable_entity }
|
67
|
+
format.xml { render :xml => @resource.errors, :status => :unprocessable_entity }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def destroy
|
73
|
+
@resource.destroy
|
74
|
+
# respond_with will fail without explicit urls
|
75
|
+
respond_to do |format|
|
76
|
+
format.html { redirect_to send("simple_admin_#{@interface.collection}_path") }
|
77
|
+
format.json { head :ok }
|
78
|
+
format.xml { head :ok }
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
protected
|
83
|
+
|
84
|
+
def require_user
|
85
|
+
send(SimpleAdmin.require_user_method) if SimpleAdmin.require_user_method
|
86
|
+
end
|
87
|
+
|
88
|
+
def lookup_interface
|
89
|
+
SimpleAdmin.registered.each do |interface|
|
90
|
+
@interface = interface if interface.collection == params[:interface]
|
91
|
+
end
|
92
|
+
# This should not be reached, routing should catch errors before this point
|
93
|
+
raise UnknownAdminInterface.new("Could not find the interface for simple admin") unless @interface
|
94
|
+
end
|
95
|
+
|
96
|
+
def lookup_resource
|
97
|
+
@resource = @interface.constant.find(params[:id])
|
98
|
+
end
|
99
|
+
|
100
|
+
def handle_before
|
101
|
+
@interface.before.each do |before|
|
102
|
+
next unless before[:actions].include?(params[:action].to_sym)
|
103
|
+
instance_eval(&before[:data])
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def clean_search_params(search_params)
|
108
|
+
return {} unless search_params.is_a?(Hash)
|
109
|
+
search_params = search_params.dup
|
110
|
+
search_params.delete_if do |key, value|
|
111
|
+
value == "" ||
|
112
|
+
["utf8", "scope", "commit", "action", "order", "interface", "controller", "format"].include?(key)
|
113
|
+
end
|
114
|
+
search_params
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module SimpleAdmin
|
2
|
+
module AdminHelper
|
3
|
+
include SimpleAdmin::TitleHelper
|
4
|
+
include SimpleAdmin::HeaderHelper
|
5
|
+
include SimpleAdmin::TableHelper
|
6
|
+
include SimpleAdmin::DisplayHelper
|
7
|
+
include SimpleAdmin::FilterHelper
|
8
|
+
include SimpleAdmin::SidebarHelper
|
9
|
+
include SimpleAdmin::PathHelper
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module SimpleAdmin
|
2
|
+
module DisplayHelper
|
3
|
+
|
4
|
+
# Return a pretty string for any object
|
5
|
+
# Date Time are formatted via #localize with :format => :long
|
6
|
+
# ActiveRecord objects are formatted via #auto_link
|
7
|
+
# We attempt to #display_name of any other objects
|
8
|
+
def pretty_format(object)
|
9
|
+
case object
|
10
|
+
when String
|
11
|
+
object
|
12
|
+
when Date, Time
|
13
|
+
localize(object, :format => :long)
|
14
|
+
else
|
15
|
+
(object.respond_to?(:display_name) && object.send(:display_name)) ||
|
16
|
+
(object.respond_to?(:full_name) && object.send(:full_name)) ||
|
17
|
+
(object.respond_to?(:name) && object.send(:name)) ||
|
18
|
+
(object.respond_to?(:username) && object.send(:username)) ||
|
19
|
+
(object.respond_to?(:login) && object.send(:login)) ||
|
20
|
+
(object.respond_to?(:title) && object.send(:title)) ||
|
21
|
+
(object.respond_to?(:email) && object.send(:email)) ||
|
22
|
+
(object.respond_to?(:to_s) && object.send(:to_s)) ||
|
23
|
+
"#{object}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def data_for(col)
|
28
|
+
value = if col.data
|
29
|
+
col.data.call(@resource, col)
|
30
|
+
elsif col.attribute.to_s =~ /^([\w]+)_id$/ && @resource.respond_to?($1.to_sym)
|
31
|
+
pretty_format(@resource.send($1))
|
32
|
+
else
|
33
|
+
pretty_format(@resource.send(col.attribute))
|
34
|
+
end
|
35
|
+
value ||= content_tag(:span, 'Empty', :class => 'empty')
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
module SimpleAdmin
|
2
|
+
module FilterHelper
|
3
|
+
def filter_for(method, klass, options={})
|
4
|
+
options ||= {}
|
5
|
+
options[:as] ||= default_filter_type(klass, method)
|
6
|
+
return "" unless options[:as]
|
7
|
+
field_type = options.delete(:as)
|
8
|
+
content_tag :div, :class => "filter_form_field filter_#{field_type}" do
|
9
|
+
send("filter_#{field_type}_input", klass, method, options)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def filter_string_input(klass, method, options = {})
|
14
|
+
field_name = "#{method}_contains"
|
15
|
+
|
16
|
+
[ label(field_name, "Search #{method.to_s.titlecase}"),
|
17
|
+
text_field_tag(field_name, params[field_name] || '')
|
18
|
+
].join("\n").html_safe
|
19
|
+
end
|
20
|
+
|
21
|
+
def filter_date_range_input(klass, method, options = {})
|
22
|
+
gt_field_name = "#{method}_gte"
|
23
|
+
lt_field_name = "#{method}_lte"
|
24
|
+
|
25
|
+
[ label(gt_field_name, method.to_s.titlecase),
|
26
|
+
filter_date_text_field(klass, gt_field_name),
|
27
|
+
" - ",
|
28
|
+
filter_date_text_field(klass, lt_field_name)
|
29
|
+
].join("\n").html_safe
|
30
|
+
end
|
31
|
+
|
32
|
+
def filter_date_text_field(klass, method)
|
33
|
+
current_value = params[method] || ''
|
34
|
+
text_field_tag(method, current_value.respond_to?(:strftime) ? current_value.strftime("%Y-%m-%d") : current_value, :size => 12, :class => "datepicker", :max => 10)
|
35
|
+
end
|
36
|
+
|
37
|
+
def filter_numeric_input(klass, method, options = {})
|
38
|
+
filters = numeric_filters_for_method(method, options.delete(:filters) || default_numeric_filters)
|
39
|
+
current_filter = current_numeric_scope(klass, filters)
|
40
|
+
filter_select = select_tag '', options_for_select(filters, current_filter), :onchange => "document.getElementById('#{method}_numeric').name = '' + this.value + '';"
|
41
|
+
filter_input = text_field_tag(current_filter, params[current_filter] || '', :size => 10, :id => "#{method}_numeric")
|
42
|
+
|
43
|
+
[ label_tag(method), filter_select, " ", filter_input].join("\n").html_safe
|
44
|
+
end
|
45
|
+
|
46
|
+
def numeric_filters_for_method(method, filters)
|
47
|
+
filters.collect{|scope| [scope[0], [method,scope[1]].join("_") ] }
|
48
|
+
end
|
49
|
+
|
50
|
+
# Returns the scope for which we are currently searching. If no search is available
|
51
|
+
# it returns the first scope
|
52
|
+
def current_numeric_scope(klass, filters)
|
53
|
+
filters[1..-1].inject(filters.first){|a,b| params[b[1].to_sym] ? b : a }[1]
|
54
|
+
end
|
55
|
+
|
56
|
+
def default_numeric_filters
|
57
|
+
[['Equal To', 'eq'], ['Greater Than', 'gt'], ['Less Than', 'lt']]
|
58
|
+
end
|
59
|
+
|
60
|
+
def filter_select_input(klass, method, options = {})
|
61
|
+
association_name = method.to_s.gsub(/_id$/, '').to_sym
|
62
|
+
input_name = if reflection = reflection_for(klass, association_name)
|
63
|
+
if [:has_and_belongs_to_many, :has_many].include?(reflection.macro)
|
64
|
+
"#{association_name.to_s.singularize}_ids"
|
65
|
+
else
|
66
|
+
reflection.options[:foreign_key] || "#{association_name}_id"
|
67
|
+
end
|
68
|
+
else
|
69
|
+
association_name
|
70
|
+
end
|
71
|
+
input_name = (input_name + "_eq").to_sym
|
72
|
+
collection = find_collection_for_column(klass, association_name, options)
|
73
|
+
[ label(input_name, method.to_s.titlecase),
|
74
|
+
select_tag(input_name, options_for_select(collection, params[input_name]), :include_blank => options[:include_blank] || 'Any')
|
75
|
+
].join("\n").html_safe
|
76
|
+
end
|
77
|
+
|
78
|
+
def find_collection_for_column(klass, column, options) #:nodoc:
|
79
|
+
collection = if options[:collection]
|
80
|
+
options.delete(:collection)
|
81
|
+
elsif reflection = reflection_for(klass, column)
|
82
|
+
options[:find_options] ||= {}
|
83
|
+
if conditions = reflection.options[:conditions]
|
84
|
+
options[:find_options][:conditions] = reflection.klass.merge_conditions(conditions, options[:find_options][:conditions])
|
85
|
+
end
|
86
|
+
reflection.klass.find(:all, options[:find_options])
|
87
|
+
else
|
88
|
+
boolean_collection(klass, column, options)
|
89
|
+
end
|
90
|
+
collection = collection.to_a if collection.is_a?(Hash)
|
91
|
+
collection.map { |o| [pretty_format(o), o.id] }
|
92
|
+
end
|
93
|
+
|
94
|
+
def boolean_collection(klass, column, options)
|
95
|
+
[['Yes', true], ['No', false]]
|
96
|
+
end
|
97
|
+
|
98
|
+
def filter_check_boxes_input(klass, method, options = {})
|
99
|
+
input_name = (generate_association_input_name(method).to_s + "_in").to_sym
|
100
|
+
collection = find_collection_for_column(method, options)
|
101
|
+
selected_values = klass.send(input_name) || []
|
102
|
+
checkboxes = template.content_tag :div, :class => "check_boxes_wrapper" do
|
103
|
+
collection.map do |c|
|
104
|
+
label = c.is_a?(Array) ? c.first : c
|
105
|
+
value = c.is_a?(Array) ? c.last : c
|
106
|
+
"<label><input type=\"checkbox\" name=\"#{input_name}[]\" value=\"#{value}\" #{selected_values.include?(value) ? "checked" : ""}/> #{label}</label>"
|
107
|
+
end.join("\n").html_safe
|
108
|
+
end
|
109
|
+
|
110
|
+
[ label(input_name, method.to_s.titlecase),
|
111
|
+
checkboxes
|
112
|
+
].join("\n").html_safe
|
113
|
+
end
|
114
|
+
|
115
|
+
# Returns the default filter type for a given attribute
|
116
|
+
def default_filter_type(klass, method)
|
117
|
+
if column = column_for(klass, method)
|
118
|
+
case column.type
|
119
|
+
when :date, :datetime
|
120
|
+
return :date_range
|
121
|
+
when :string, :text
|
122
|
+
return :string
|
123
|
+
when :integer
|
124
|
+
return :select if reflection_for(klass, method.to_s.gsub('_id','').to_sym)
|
125
|
+
return :numeric
|
126
|
+
when :float, :decimal
|
127
|
+
return :numeric
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
if reflection = reflection_for(klass, method)
|
132
|
+
return :select if reflection.macro == :belongs_to && !reflection.options[:polymorphic]
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# Returns the column for an attribute on the object being searched
|
137
|
+
# if it exists. Otherwise returns nil
|
138
|
+
def column_for(klass, method)
|
139
|
+
klass.columns_hash[method.to_s] if klass.respond_to?(:columns_hash)
|
140
|
+
end
|
141
|
+
|
142
|
+
# Returns the association reflection for the method if it exists
|
143
|
+
def reflection_for(klass, method)
|
144
|
+
klass.reflect_on_association(method) if klass.respond_to?(:reflect_on_association)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module SimpleAdmin
|
2
|
+
module HeaderHelper
|
3
|
+
def tabs
|
4
|
+
content_tag :ul, :id => 'tabs' do
|
5
|
+
SimpleAdmin.registered.collect do |interface|
|
6
|
+
content_tag :li, :id => interface.collection, :class => "#{'current' if @interface == interface}" do
|
7
|
+
link_to interface.collection.titlecase, send("simple_admin_#{interface.collection}_path".to_sym)
|
8
|
+
end
|
9
|
+
end.join.html_safe
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def utility_nav
|
14
|
+
content_tag :p, :id => 'utility_nav' do
|
15
|
+
if SimpleAdmin.current_user_method && send(SimpleAdmin.current_user_method)
|
16
|
+
content = "".html_safe
|
17
|
+
content << content_tag(:span, send(SimpleAdmin.current_user_name_method), :class => "current_user") if SimpleAdmin.current_user_name_method
|
18
|
+
content << link_to("Logout", Rails.application.routes.url_helpers.logout_path) if Rails.application.routes.url_helpers.respond_to?(:logout_path)
|
19
|
+
content
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def breadcrumbs
|
25
|
+
content_tag :span, :class => 'breadcrumb' do
|
26
|
+
SimpleAdmin::Breadcrumbs.parse(request.fullpath, params[:action]).collect do |crumb|
|
27
|
+
link_to(crumb.first, crumb.last) +
|
28
|
+
content_tag(:span, ' / ', :class => 'breadcrumb_sep')
|
29
|
+
end.join.html_safe
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def action_items
|
34
|
+
content_tag :div, :class => "action_items" do
|
35
|
+
content = ""
|
36
|
+
# If we are currently showing, then check for edit and destroy action items
|
37
|
+
if params[:action].to_sym == :show
|
38
|
+
if controller.action_methods.include?('edit')
|
39
|
+
content << link_to("Edit #{@interface.member.titlecase}",
|
40
|
+
send("edit_simple_admin_#{@interface.member}_path", @object))
|
41
|
+
end
|
42
|
+
content << " "
|
43
|
+
if controller.action_methods.include?("destroy")
|
44
|
+
content << link_to("Delete #{@interface.member.titlecase}",
|
45
|
+
send("simple_admin_#{@interface.member}_path", @object),
|
46
|
+
:method => :delete, :confirm => "Are you sure you want to delete this?")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
# If we are not showing an item or creating a new one, then check for new action items
|
50
|
+
unless [:new, :show].include?(params[:action].to_sym)
|
51
|
+
if controller.action_methods.include?('new')
|
52
|
+
content << link_to("New #{@interface.member.titlecase}",
|
53
|
+
send("new_simple_admin_#{@interface.member}_path"))
|
54
|
+
end
|
55
|
+
end
|
56
|
+
content.html_safe
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module SimpleAdmin
|
2
|
+
module TableHelper
|
3
|
+
def sortable_header_classes_for(col)
|
4
|
+
sort = current_sort
|
5
|
+
classes = []
|
6
|
+
classes << "sortable" if col.sortable
|
7
|
+
classes << "sorted-#{sort[1]}" if sort[0] == col.sort_key
|
8
|
+
classes.join(' ')
|
9
|
+
end
|
10
|
+
|
11
|
+
# Returns an array for the current sort order
|
12
|
+
# current_sort[0] #=> sort_key
|
13
|
+
# current_sort[1] #=> asc | desc
|
14
|
+
def current_sort
|
15
|
+
if params[:order] && params[:order] =~ /^([\w\_\.]+)_(desc|asc)$/
|
16
|
+
[$1,$2]
|
17
|
+
else
|
18
|
+
[]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns the order to use for a given sort key
|
23
|
+
#
|
24
|
+
# Default is to use 'desc'. If the current sort key is
|
25
|
+
# 'desc' it will return 'asc'
|
26
|
+
def order_for_sort_key(sort_key)
|
27
|
+
current_key, current_order = current_sort
|
28
|
+
return 'desc' unless current_key == sort_key
|
29
|
+
current_order == 'desc' ? 'asc' : 'desc'
|
30
|
+
end
|
31
|
+
|
32
|
+
def resource_actions(object)
|
33
|
+
links = link_to "View", send("simple_admin_#{@interface.member}_path", object), :class => "member_link view_link"
|
34
|
+
links += link_to "Edit", send("edit_simple_admin_#{@interface.member}_path", object), :class => "member_link edit_link"
|
35
|
+
links += link_to "Delete", send("simple_admin_#{@interface.member}_path", object), :method => :delete, :confirm => "Are you sure you want to delete this?", :class => "member_link delete_link"
|
36
|
+
links
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module SimpleAdmin
|
2
|
+
module TitleHelper
|
3
|
+
def title
|
4
|
+
"#{page_title} | #{site_title}"
|
5
|
+
end
|
6
|
+
|
7
|
+
def site_title
|
8
|
+
SimpleAdmin::site_title
|
9
|
+
end
|
10
|
+
|
11
|
+
def page_title
|
12
|
+
options = @interface.options_for(params[:action].to_sym)
|
13
|
+
case options[:title]
|
14
|
+
when Proc
|
15
|
+
options[:title].call(@resource)
|
16
|
+
when Symbol
|
17
|
+
if @resource
|
18
|
+
@resource.send(optons[:title])
|
19
|
+
else
|
20
|
+
options[:title].to_s
|
21
|
+
end
|
22
|
+
when String
|
23
|
+
options[:title]
|
24
|
+
else
|
25
|
+
if @resource && @resource.new_record?
|
26
|
+
"New #{@interface.member.titleize}"
|
27
|
+
elsif @resource
|
28
|
+
"#{@interface.member.titleize}#{@resource.to_param.match(/\d+/) ? ' #' : ': '}#{@resource.to_param}"
|
29
|
+
else
|
30
|
+
@interface.collection.titlecase
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|