fesplugas-typus 0.9.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.
- data/.gitignore +7 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +80 -0
- data/Rakefile +61 -0
- data/VERSION +1 -0
- data/app/controllers/admin/master_controller.rb +324 -0
- data/app/controllers/typus_controller.rb +127 -0
- data/app/helpers/admin/form_helper.rb +351 -0
- data/app/helpers/admin/master_helper.rb +99 -0
- data/app/helpers/admin/public_helper.rb +24 -0
- data/app/helpers/admin/sidebar_helper.rb +259 -0
- data/app/helpers/admin/table_helper.rb +227 -0
- data/app/helpers/typus_helper.rb +169 -0
- data/app/models/typus_mailer.rb +14 -0
- data/app/models/typus_user.rb +5 -0
- data/app/views/admin/dashboard/_sidebar.html.erb +9 -0
- data/app/views/admin/resources/edit.html.erb +29 -0
- data/app/views/admin/resources/index.html.erb +28 -0
- data/app/views/admin/resources/new.html.erb +27 -0
- data/app/views/admin/resources/show.html.erb +21 -0
- data/app/views/admin/shared/_footer.html.erb +1 -0
- data/app/views/admin/shared/_pagination.html.erb +28 -0
- data/app/views/layouts/admin.html.erb +72 -0
- data/app/views/layouts/typus.html.erb +29 -0
- data/app/views/typus/dashboard.html.erb +13 -0
- data/app/views/typus/recover_password.html.erb +7 -0
- data/app/views/typus/reset_password.html.erb +13 -0
- data/app/views/typus/sign_in.html.erb +9 -0
- data/app/views/typus/sign_up.html.erb +7 -0
- data/app/views/typus_mailer/reset_password_link.erb +11 -0
- data/config/locales/es.yml +106 -0
- data/config/locales/pt-BR.yml +108 -0
- data/config/locales/typus_hacks.yml +14 -0
- data/config/routes.rb +14 -0
- data/generators/typus/templates/config/initializers/typus.rb +27 -0
- data/generators/typus/templates/config/typus/application.yml +45 -0
- data/generators/typus/templates/config/typus/application_roles.yml +23 -0
- data/generators/typus/templates/config/typus/typus.yml +14 -0
- data/generators/typus/templates/config/typus/typus_roles.yml +2 -0
- data/generators/typus/templates/db/create_typus_users.rb +21 -0
- data/generators/typus/templates/public/images/admin/arrow_down.gif +0 -0
- data/generators/typus/templates/public/images/admin/arrow_up.gif +0 -0
- data/generators/typus/templates/public/images/admin/spinner.gif +0 -0
- data/generators/typus/templates/public/images/admin/status_false.gif +0 -0
- data/generators/typus/templates/public/images/admin/status_true.gif +0 -0
- data/generators/typus/templates/public/images/admin/trash.gif +0 -0
- data/generators/typus/templates/public/javascripts/admin/application.js +14 -0
- data/generators/typus/templates/public/stylesheets/admin/reset.css +68 -0
- data/generators/typus/templates/public/stylesheets/admin/screen.css +709 -0
- data/generators/typus/typus_generator.rb +141 -0
- data/generators/typus_update_schema_to_01/templates/config/typus.yml +14 -0
- data/generators/typus_update_schema_to_01/templates/migration.rb +11 -0
- data/generators/typus_update_schema_to_01/typus_update_schema_to_01_generator.rb +19 -0
- data/init.rb +19 -0
- data/lib/typus/active_record.rb +298 -0
- data/lib/typus/authentication.rb +155 -0
- data/lib/typus/configuration.rb +92 -0
- data/lib/typus/format.rb +56 -0
- data/lib/typus/generator.rb +173 -0
- data/lib/typus/hash.rb +10 -0
- data/lib/typus/locale.rb +17 -0
- data/lib/typus/object.rb +22 -0
- data/lib/typus/quick_edit.rb +33 -0
- data/lib/typus/reloader.rb +17 -0
- data/lib/typus/string.rb +11 -0
- data/lib/typus/user.rb +137 -0
- data/lib/typus.rb +133 -0
- data/lib/vendor/active_record.rb +15 -0
- data/lib/vendor/paginator.rb +143 -0
- data/tasks/typus_tasks.rake +26 -0
- data/test/config/broken/application.yml +68 -0
- data/test/config/broken/application_roles.yml +20 -0
- data/test/config/broken/empty.yml +0 -0
- data/test/config/broken/empty_roles.yml +0 -0
- data/test/config/broken/undefined.yml +3 -0
- data/test/config/broken/undefined_roles.yml +6 -0
- data/test/config/default/typus.yml +14 -0
- data/test/config/default/typus_roles.yml +2 -0
- data/test/config/empty/empty_01.yml +0 -0
- data/test/config/empty/empty_01_roles.yml +0 -0
- data/test/config/empty/empty_02.yml +0 -0
- data/test/config/empty/empty_02_roles.yml +0 -0
- data/test/config/locales/es.yml +10 -0
- data/test/config/ordered/001_roles.yml +2 -0
- data/test/config/ordered/002_roles.yml +2 -0
- data/test/config/unordered/app_one_roles.yml +2 -0
- data/test/config/unordered/app_two_roles.yml +2 -0
- data/test/config/working/application.yml +67 -0
- data/test/config/working/application_roles.yml +22 -0
- data/test/config/working/typus.yml +14 -0
- data/test/config/working/typus_roles.yml +2 -0
- data/test/fixtures/app/controllers/admin/assets_controller.rb +2 -0
- data/test/fixtures/app/controllers/admin/categories_controller.rb +2 -0
- data/test/fixtures/app/controllers/admin/comments_controller.rb +2 -0
- data/test/fixtures/app/controllers/admin/pages_controller.rb +2 -0
- data/test/fixtures/app/controllers/admin/posts_controller.rb +2 -0
- data/test/fixtures/app/controllers/admin/status_controller.rb +6 -0
- data/test/fixtures/app/controllers/admin/typus_users_controller.rb +2 -0
- data/test/fixtures/app/controllers/admin/watch_dog_controller.rb +6 -0
- data/test/fixtures/app/views/admin/comments/_edit_bottom.html.erb +1 -0
- data/test/fixtures/app/views/admin/comments/_edit_sidebar.html.erb +1 -0
- data/test/fixtures/app/views/admin/comments/_edit_top.html.erb +1 -0
- data/test/fixtures/app/views/admin/comments/_index_bottom.html.erb +1 -0
- data/test/fixtures/app/views/admin/comments/_index_sidebar.html.erb +1 -0
- data/test/fixtures/app/views/admin/comments/_index_top.html.erb +1 -0
- data/test/fixtures/app/views/admin/comments/_new_bottom.html.erb +1 -0
- data/test/fixtures/app/views/admin/comments/_new_sidebar.html.erb +1 -0
- data/test/fixtures/app/views/admin/comments/_new_top.html.erb +1 -0
- data/test/fixtures/app/views/admin/comments/_show_bottom.html.erb +1 -0
- data/test/fixtures/app/views/admin/comments/_show_sidebar.html.erb +1 -0
- data/test/fixtures/app/views/admin/comments/_show_top.html.erb +1 -0
- data/test/fixtures/app/views/admin/dashboard/_bottom.html.erb +1 -0
- data/test/fixtures/app/views/admin/dashboard/_sidebar.html.erb +1 -0
- data/test/fixtures/app/views/admin/dashboard/_top.html.erb +1 -0
- data/test/fixtures/app/views/admin/shared/_footer.html.erb +1 -0
- data/test/fixtures/app/views/admin/status/index.html.erb +1 -0
- data/test/fixtures/app/views/admin/templates/_datepicker.html.erb +1 -0
- data/test/fixtures/assets.yml +11 -0
- data/test/fixtures/categories.yml +14 -0
- data/test/fixtures/comments.yml +27 -0
- data/test/fixtures/pages.yml +41 -0
- data/test/fixtures/posts.yml +37 -0
- data/test/fixtures/typus_users.yml +54 -0
- data/test/functional/admin/assets_controller_test.rb +57 -0
- data/test/functional/admin/categories_controller_test.rb +106 -0
- data/test/functional/admin/comments_controller_test.rb +121 -0
- data/test/functional/admin/master_controller_test.rb +5 -0
- data/test/functional/admin/posts_controller_test.rb +278 -0
- data/test/functional/admin/status_controller_test.rb +43 -0
- data/test/functional/admin/typus_users_controller_test.rb +239 -0
- data/test/functional/typus_controller_test.rb +315 -0
- data/test/helper.rb +51 -0
- data/test/helpers/admin/form_helper_test.rb +316 -0
- data/test/helpers/admin/master_helper_test.rb +65 -0
- data/test/helpers/admin/public_helper_test.rb +22 -0
- data/test/helpers/admin/sidebar_helper_test.rb +351 -0
- data/test/helpers/admin/table_helper_test.rb +255 -0
- data/test/helpers/typus_helper_test.rb +106 -0
- data/test/lib/active_record_test.rb +372 -0
- data/test/lib/configuration_test.rb +91 -0
- data/test/lib/hash_test.rb +11 -0
- data/test/lib/routes_test.rb +82 -0
- data/test/lib/string_test.rb +25 -0
- data/test/lib/typus_test.rb +105 -0
- data/test/models.rb +51 -0
- data/test/schema.rb +64 -0
- data/test/unit/typus_mailer_test.rb +33 -0
- data/test/unit/typus_test.rb +17 -0
- data/test/unit/typus_user_roles_test.rb +90 -0
- data/test/unit/typus_user_test.rb +177 -0
- data/test/vendor/active_record_test.rb +18 -0
- data/test/vendor/paginator_test.rb +138 -0
- data/typus.gemspec +225 -0
- metadata +241 -0
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
module Admin::SidebarHelper
|
|
2
|
+
|
|
3
|
+
def actions
|
|
4
|
+
|
|
5
|
+
returning(String.new) do |html|
|
|
6
|
+
|
|
7
|
+
html << <<-HTML
|
|
8
|
+
#{build_typus_list(default_actions, :header => 'actions')}
|
|
9
|
+
#{build_typus_list(previous_and_next, :header => 'go_to')}
|
|
10
|
+
HTML
|
|
11
|
+
|
|
12
|
+
html << <<-HTML
|
|
13
|
+
#{build_typus_list(export, :header => 'export')}
|
|
14
|
+
HTML
|
|
15
|
+
|
|
16
|
+
%w( parent_module submodules ).each do |block|
|
|
17
|
+
html << <<-HTML
|
|
18
|
+
#{build_typus_list(modules(block), :header => block)}
|
|
19
|
+
HTML
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def default_actions
|
|
27
|
+
|
|
28
|
+
items = []
|
|
29
|
+
|
|
30
|
+
case params[:action]
|
|
31
|
+
when 'index', 'edit', 'show', 'update'
|
|
32
|
+
if @current_user.can_perform?(@resource[:class], 'create')
|
|
33
|
+
items << (link_to _('Add entry'), :action => 'new')
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
case params[:action]
|
|
38
|
+
when 'show'
|
|
39
|
+
if @current_user.can_perform?(@resource[:class], 'update')
|
|
40
|
+
items << (link_to _('Edit entry'), :action => 'edit', :id => @item.id)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
@resource[:class].typus_actions_for(params[:action]).each do |action|
|
|
45
|
+
if @current_user.can_perform?(@resource[:class], action)
|
|
46
|
+
items << (link_to action.humanize, params.merge(:action => action))
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
case params[:action]
|
|
51
|
+
when 'new', 'create', 'edit', 'show', 'update'
|
|
52
|
+
items << (link_to _('Back to list'), :action => 'index')
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
return items
|
|
56
|
+
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def export
|
|
60
|
+
return [] unless params[:action] == 'index'
|
|
61
|
+
returning(Array.new) do |format|
|
|
62
|
+
@resource[:class].typus_export_formats.each do |f|
|
|
63
|
+
format << (link_to f.upcase, params.merge(:format => f))
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def build_typus_list(items, *args)
|
|
69
|
+
|
|
70
|
+
options = args.extract_options!
|
|
71
|
+
|
|
72
|
+
header = if options[:header]
|
|
73
|
+
_(options[:header].humanize)
|
|
74
|
+
elsif options[:attribute]
|
|
75
|
+
@resource[:class].human_attribute_name(options[:attribute])
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
return String.new if items.empty?
|
|
79
|
+
returning(String.new) do |html|
|
|
80
|
+
html << "<h2>#{header}</h2>\n" unless header.nil?
|
|
81
|
+
next unless options[:selector].nil?
|
|
82
|
+
html << "<ul>\n"
|
|
83
|
+
items.each do |item|
|
|
84
|
+
html << "<li>#{item}</li>\n"
|
|
85
|
+
end
|
|
86
|
+
html << "</ul>\n"
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def modules(name)
|
|
92
|
+
|
|
93
|
+
models = case name
|
|
94
|
+
when 'parent_module': Typus.parent(@resource[:class], 'module')
|
|
95
|
+
when 'submodules': Typus.module(@resource[:class])
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
return [] if models.empty?
|
|
99
|
+
|
|
100
|
+
returning(Array.new) do |items|
|
|
101
|
+
models.each do |model|
|
|
102
|
+
items << (link_to model.humanize, :controller => model.tableize)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def previous_and_next
|
|
109
|
+
return [] unless %w( edit show update ).include?(params[:action])
|
|
110
|
+
returning(Array.new) do |items|
|
|
111
|
+
items << (link_to _('Next'), params.merge(:id => @next.id)) if @next
|
|
112
|
+
items << (link_to _('Previous'), params.merge(:id => @previous.id)) if @previous
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def search
|
|
117
|
+
|
|
118
|
+
typus_search = @resource[:class].typus_defaults_for(:search)
|
|
119
|
+
return if typus_search.empty?
|
|
120
|
+
|
|
121
|
+
search_by = typus_search.collect { |x| @resource[:class].human_attribute_name(x) }.to_sentence
|
|
122
|
+
|
|
123
|
+
search_params = params.dup
|
|
124
|
+
%w( action controller search page ).each { |p| search_params.delete(p) }
|
|
125
|
+
|
|
126
|
+
hidden_params = search_params.map { |key, value| hidden_field_tag(key, value) }
|
|
127
|
+
|
|
128
|
+
<<-HTML
|
|
129
|
+
<h2>#{_('Search')}</h2>
|
|
130
|
+
<form action="" method="get">
|
|
131
|
+
<p><input id="search" name="search" type="text" value="#{params[:search]}"/></p>
|
|
132
|
+
#{hidden_params.sort.join("\n")}
|
|
133
|
+
</form>
|
|
134
|
+
<p class="tip">#{_('Search by')} #{search_by.downcase}.</p>
|
|
135
|
+
HTML
|
|
136
|
+
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def filters
|
|
140
|
+
|
|
141
|
+
typus_filters = @resource[:class].typus_filters
|
|
142
|
+
return if typus_filters.empty?
|
|
143
|
+
|
|
144
|
+
current_request = request.env['QUERY_STRING'] || []
|
|
145
|
+
|
|
146
|
+
returning(String.new) do |html|
|
|
147
|
+
typus_filters.each do |key, value|
|
|
148
|
+
case value
|
|
149
|
+
when :boolean: html << boolean_filter(current_request, key)
|
|
150
|
+
when :string: html << string_filter(current_request, key)
|
|
151
|
+
when :datetime: html << datetime_filter(current_request, key)
|
|
152
|
+
when :belongs_to: html << relationship_filter(current_request, key)
|
|
153
|
+
when :has_and_belongs_to_many:
|
|
154
|
+
html << relationship_filter(current_request, key, true)
|
|
155
|
+
else
|
|
156
|
+
html << "<p>#{_('Unknown')}</p>"
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def relationship_filter(request, filter, habtm = false)
|
|
164
|
+
|
|
165
|
+
model = (habtm) ? filter.classify.constantize : filter.capitalize.camelize.constantize
|
|
166
|
+
related_fk = (habtm) ? filter : @resource[:class].reflect_on_association(filter.to_sym).primary_key_name
|
|
167
|
+
|
|
168
|
+
params_without_filter = params.dup
|
|
169
|
+
%w( controller action page ).each { |p| params_without_filter.delete(p) }
|
|
170
|
+
params_without_filter.delete(related_fk)
|
|
171
|
+
|
|
172
|
+
items = []
|
|
173
|
+
|
|
174
|
+
returning(String.new) do |html|
|
|
175
|
+
related_items = model.find(:all, :order => model.typus_order_by)
|
|
176
|
+
if related_items.size > model.typus_options_for(:sidebar_selector)
|
|
177
|
+
related_items.each do |item|
|
|
178
|
+
switch = request.include?("#{related_fk}=#{item.id}") ? 'selected' : ''
|
|
179
|
+
items << <<-HTML
|
|
180
|
+
<option #{switch} value="#{url_for params.merge(related_fk => item.id, :page => nil)}">#{item.typus_name}</option>
|
|
181
|
+
HTML
|
|
182
|
+
end
|
|
183
|
+
model_pluralized = model.name.downcase.pluralize
|
|
184
|
+
form = <<-HTML
|
|
185
|
+
<!-- Embedded JS -->
|
|
186
|
+
<script>
|
|
187
|
+
function surfto_#{model_pluralized}(form) {
|
|
188
|
+
var myindex = form.#{model_pluralized}.selectedIndex
|
|
189
|
+
if (form.#{model_pluralized}.options[myindex].value != "0") {
|
|
190
|
+
top.location.href = form.#{model_pluralized}.options[myindex].value;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
</script>
|
|
194
|
+
<!-- /Embedded JS -->
|
|
195
|
+
<p><form class="form" action="#">
|
|
196
|
+
<select name="#{model_pluralized}" onChange="surfto_#{model_pluralized}(this.form)">
|
|
197
|
+
<option value="#{url_for params_without_filter}">#{_('filter by')} #{_(model.human_name)}</option>
|
|
198
|
+
#{items.join("\n")}
|
|
199
|
+
</select>
|
|
200
|
+
</form></p>
|
|
201
|
+
HTML
|
|
202
|
+
else
|
|
203
|
+
related_items.each do |item|
|
|
204
|
+
switch = request.include?("#{related_fk}=#{item.id}") ? 'on' : 'off'
|
|
205
|
+
items << (link_to item.typus_name, params.merge(related_fk => item.id, :page => nil), :class => switch)
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
if form
|
|
210
|
+
html << build_typus_list(items, :attribute => filter, :selector => true)
|
|
211
|
+
html << form
|
|
212
|
+
else
|
|
213
|
+
html << build_typus_list(items, :attribute => filter)
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
##
|
|
221
|
+
# Thinking in update datetime_filters to ...
|
|
222
|
+
#
|
|
223
|
+
# %w( today last_few_days last_7_days last_30_days )
|
|
224
|
+
#
|
|
225
|
+
# ... which are the ones used by 'exception_logger'.
|
|
226
|
+
#
|
|
227
|
+
def datetime_filter(request, filter)
|
|
228
|
+
items = []
|
|
229
|
+
%w( today past_7_days this_month this_year ).each do |timeline|
|
|
230
|
+
switch = request.include?("#{filter}=#{timeline}") ? 'on' : 'off'
|
|
231
|
+
options = { filter.to_sym => timeline, :page => nil }
|
|
232
|
+
items << (link_to _(timeline.humanize), params.merge(options), :class => switch)
|
|
233
|
+
end
|
|
234
|
+
build_typus_list(items, :attribute => filter)
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def boolean_filter(request, filter)
|
|
238
|
+
items = []
|
|
239
|
+
@resource[:class].typus_boolean(filter).each do |key, value|
|
|
240
|
+
switch = request.include?("#{filter}=#{key}") ? 'on' : 'off'
|
|
241
|
+
options = { filter.to_sym => key, :page => nil }
|
|
242
|
+
items << (link_to _(value), params.merge(options), :class => switch)
|
|
243
|
+
end
|
|
244
|
+
build_typus_list(items, :attribute => filter)
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
def string_filter(request, filter)
|
|
248
|
+
values = @resource[:class].send(filter)
|
|
249
|
+
items = []
|
|
250
|
+
values.each do |item|
|
|
251
|
+
link_name, link_filter = (values.first.kind_of?(Array)) ? [ item.first, item.last ] : [ item, item ]
|
|
252
|
+
switch = request.include?("#{filter}=#{link_filter}") ? 'on' : 'off'
|
|
253
|
+
options = { filter.to_sym => link_filter, :page => nil }
|
|
254
|
+
items << (link_to link_name.capitalize, params.merge(options), :class => switch)
|
|
255
|
+
end
|
|
256
|
+
build_typus_list(items, :attribute => filter)
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
end
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
module Admin::TableHelper
|
|
2
|
+
|
|
3
|
+
def build_typus_table(model, fields, items, link_options = {}, association = nil)
|
|
4
|
+
|
|
5
|
+
returning(String.new) do |html|
|
|
6
|
+
|
|
7
|
+
html << <<-HTML
|
|
8
|
+
<table>
|
|
9
|
+
HTML
|
|
10
|
+
|
|
11
|
+
html << typus_table_header(model, fields)
|
|
12
|
+
|
|
13
|
+
items.each do |item|
|
|
14
|
+
|
|
15
|
+
html << <<-HTML
|
|
16
|
+
<tr class="#{cycle('even', 'odd')}" id="item_#{item.id}">
|
|
17
|
+
HTML
|
|
18
|
+
|
|
19
|
+
fields.each do |key, value|
|
|
20
|
+
case value
|
|
21
|
+
when :boolean: html << typus_table_boolean_field(key, item)
|
|
22
|
+
when :datetime: html << typus_table_datetime_field(key, item, fields.keys.first, link_options)
|
|
23
|
+
when :date: html << typus_table_datetime_field(key, item, fields.keys.first, link_options)
|
|
24
|
+
when :time: html << typus_table_datetime_field(key, item, fields.keys.first, link_options)
|
|
25
|
+
when :belongs_to: html << typus_table_belongs_to_field(key, item)
|
|
26
|
+
when :tree: html << typus_table_tree_field(key, item)
|
|
27
|
+
when :position: html << typus_table_position_field(key, item)
|
|
28
|
+
when :has_and_belongs_to_many:
|
|
29
|
+
html << typus_table_has_and_belongs_to_many_field(key, item)
|
|
30
|
+
else
|
|
31
|
+
html << typus_table_string_field(key, item, fields.keys.first, link_options)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
##
|
|
36
|
+
# This controls the action to perform. If we are on a model list we
|
|
37
|
+
# will remove the entry, but if we inside a model we will remove the
|
|
38
|
+
# relationship between the models.
|
|
39
|
+
#
|
|
40
|
+
# Only shown is the user can destroy items.
|
|
41
|
+
#
|
|
42
|
+
|
|
43
|
+
if @current_user.can_perform?(model, 'delete')
|
|
44
|
+
|
|
45
|
+
case params[:action]
|
|
46
|
+
when 'index'
|
|
47
|
+
perform = link_to image_tag('admin/trash.gif'), { :action => 'destroy',
|
|
48
|
+
:id => item.id },
|
|
49
|
+
:confirm => _('Remove entry?'),
|
|
50
|
+
:method => :delete
|
|
51
|
+
else
|
|
52
|
+
perform = link_to image_tag('admin/trash.gif'), { :action => 'unrelate',
|
|
53
|
+
:id => params[:id],
|
|
54
|
+
:association => association,
|
|
55
|
+
:resource => model,
|
|
56
|
+
:resource_id => item.id },
|
|
57
|
+
:confirm => _("Unrelate {{unrelate_model}} from {{unrelate_model_from}}?",
|
|
58
|
+
:unrelate_model => model.human_name,
|
|
59
|
+
:unrelate_model_from => @resource[:class].human_name)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
html << <<-HTML
|
|
63
|
+
<td width="10px">#{perform}</td>
|
|
64
|
+
HTML
|
|
65
|
+
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
html << <<-HTML
|
|
69
|
+
</tr>
|
|
70
|
+
HTML
|
|
71
|
+
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
html << "</table>"
|
|
75
|
+
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
##
|
|
81
|
+
# Header of the table
|
|
82
|
+
#
|
|
83
|
+
def typus_table_header(model, fields)
|
|
84
|
+
returning(String.new) do |html|
|
|
85
|
+
headers = []
|
|
86
|
+
fields.each do |key, value|
|
|
87
|
+
|
|
88
|
+
content = model.human_attribute_name(key)
|
|
89
|
+
content += " (#{key})" if key.include?('_id')
|
|
90
|
+
|
|
91
|
+
if (model.model_fields.map(&:first).collect { |i| i.to_s }.include?(key) || model.reflect_on_all_associations(:belongs_to).map(&:name).include?(key.to_sym)) && params[:action] == 'index'
|
|
92
|
+
sort_order = case params[:sort_order]
|
|
93
|
+
when 'asc': 'desc'
|
|
94
|
+
when 'desc': 'asc'
|
|
95
|
+
end
|
|
96
|
+
order_by = model.reflect_on_association(key.to_sym).primary_key_name rescue key
|
|
97
|
+
switch = (params[:order_by] == key) ? sort_order : ''
|
|
98
|
+
options = { :order_by => order_by, :sort_order => sort_order }
|
|
99
|
+
content = (link_to "<div class=\"#{switch}\">#{content}</div>", params.merge(options))
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
headers << "<th>#{content}</th>"
|
|
103
|
+
|
|
104
|
+
end
|
|
105
|
+
headers << "<th> </th>" if @current_user.can_perform?(model, 'delete')
|
|
106
|
+
html << <<-HTML
|
|
107
|
+
<tr>
|
|
108
|
+
#{headers.join("\n")}
|
|
109
|
+
</tr>
|
|
110
|
+
HTML
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def typus_table_belongs_to_field(attribute, item)
|
|
115
|
+
|
|
116
|
+
action = item.send(attribute).class.typus_options_for(:default_action_on_item) rescue 'edit'
|
|
117
|
+
|
|
118
|
+
content = if !item.send(attribute).kind_of?(NilClass)
|
|
119
|
+
link_to item.send(attribute).typus_name, :controller => "admin/#{attribute.pluralize}", :action => action, :id => item.send(attribute).id
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
<<-HTML
|
|
123
|
+
<td>#{content}</td>
|
|
124
|
+
HTML
|
|
125
|
+
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def typus_table_has_and_belongs_to_many_field(attribute, item)
|
|
129
|
+
<<-HTML
|
|
130
|
+
<td>#{item.send(attribute).map { |i| i.typus_name }.join('<br />')}</td>
|
|
131
|
+
HTML
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
##
|
|
135
|
+
# When detection of the attributes is made a default attribute
|
|
136
|
+
# type is set. From the string_field we display other content
|
|
137
|
+
# types.
|
|
138
|
+
#
|
|
139
|
+
def typus_table_string_field(attribute, item, first_field, link_options = {})
|
|
140
|
+
|
|
141
|
+
action = item.class.typus_options_for(:default_action_on_item)
|
|
142
|
+
|
|
143
|
+
content = if first_field == attribute
|
|
144
|
+
link_to item.send(attribute) || item.class.typus_options_for(:nil), link_options.merge(:controller => "admin/#{item.class.name.tableize}", :action => action, :id => item.id)
|
|
145
|
+
else
|
|
146
|
+
item.send(attribute)
|
|
147
|
+
end
|
|
148
|
+
<<-HTML
|
|
149
|
+
<td>#{content}</td>
|
|
150
|
+
HTML
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def typus_table_tree_field(attribute, item)
|
|
154
|
+
<<-HTML
|
|
155
|
+
<td>#{item.parent.typus_name if item.parent}</td>
|
|
156
|
+
HTML
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def typus_table_position_field(attribute, item)
|
|
160
|
+
|
|
161
|
+
html_position = []
|
|
162
|
+
|
|
163
|
+
[['Up', 'move_higher'], ['Down', 'move_lower']].each do |position|
|
|
164
|
+
|
|
165
|
+
options = { :controller => item.class.name.tableize,
|
|
166
|
+
:action => 'position',
|
|
167
|
+
:id => item.id,
|
|
168
|
+
:go => position.last }
|
|
169
|
+
|
|
170
|
+
html_position << <<-HTML
|
|
171
|
+
#{link_to _(position.first), params.merge(options)}
|
|
172
|
+
HTML
|
|
173
|
+
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
<<-HTML
|
|
177
|
+
<td>#{html_position.join('/ ')}</td>
|
|
178
|
+
HTML
|
|
179
|
+
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def typus_table_datetime_field(attribute, item, first_field = nil, link_options = {} )
|
|
183
|
+
|
|
184
|
+
action = item.class.typus_options_for(:default_action_on_item)
|
|
185
|
+
|
|
186
|
+
date_format = item.class.typus_date_format(attribute)
|
|
187
|
+
value = !item.send(attribute).nil? ? item.send(attribute).to_s(date_format) : item.class.typus_options_for(:nil)
|
|
188
|
+
content = if first_field == attribute
|
|
189
|
+
link_to value, link_options.merge(:controller => "admin/#{item.class.name.tableize}", :action => action, :id => item.id )
|
|
190
|
+
else
|
|
191
|
+
value
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
<<-HTML
|
|
195
|
+
<td>#{content}</td>
|
|
196
|
+
HTML
|
|
197
|
+
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def typus_table_boolean_field(attribute, item)
|
|
201
|
+
|
|
202
|
+
boolean_icon = item.class.typus_options_for(:icon_on_boolean)
|
|
203
|
+
boolean_hash = item.class.typus_boolean(attribute)
|
|
204
|
+
|
|
205
|
+
status = item.send(attribute)
|
|
206
|
+
|
|
207
|
+
link_text = unless item.send(attribute).nil?
|
|
208
|
+
(boolean_icon) ? image_tag("admin/status_#{status}.gif") : boolean_hash["#{status}".to_sym]
|
|
209
|
+
else
|
|
210
|
+
item.class.typus_options_for(:nil) # Content is nil, so we show nil.
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
options = { :controller => item.class.name.tableize, :action => 'toggle', :field => attribute, :id => item.id }
|
|
214
|
+
|
|
215
|
+
content = if item.class.typus_options_for(:toggle) && !item.send(attribute).nil?
|
|
216
|
+
link_to link_text, params.merge(options), :confirm => _("Change {{attribute}}?", :attribute => item.class.human_attribute_name(attribute).downcase)
|
|
217
|
+
else
|
|
218
|
+
link_text
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
<<-HTML
|
|
222
|
+
<td align="center">#{content}</td>
|
|
223
|
+
HTML
|
|
224
|
+
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
end
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
module TypusHelper
|
|
2
|
+
|
|
3
|
+
##
|
|
4
|
+
# Applications list on the dashboard
|
|
5
|
+
#
|
|
6
|
+
def applications
|
|
7
|
+
|
|
8
|
+
returning(String.new) do |html|
|
|
9
|
+
|
|
10
|
+
Typus.applications.each do |app|
|
|
11
|
+
|
|
12
|
+
available = Typus.application(app).map do |resource|
|
|
13
|
+
resource if @current_user.resources.include?(resource)
|
|
14
|
+
end
|
|
15
|
+
next if available.compact.empty?
|
|
16
|
+
|
|
17
|
+
html << <<-HTML
|
|
18
|
+
<table>
|
|
19
|
+
<tr>
|
|
20
|
+
<th colspan="2">#{app}</th>
|
|
21
|
+
</tr>
|
|
22
|
+
HTML
|
|
23
|
+
|
|
24
|
+
available.compact.each do |model|
|
|
25
|
+
description = Typus.module_description(model)
|
|
26
|
+
admin_items_path = { :controller => "admin/#{model.tableize}" }
|
|
27
|
+
new_admin_item_path = { :controller => "admin/#{model.tableize}", :action => 'new'}
|
|
28
|
+
html << <<-HTML
|
|
29
|
+
<tr class="#{cycle('even', 'odd')}">
|
|
30
|
+
<td>#{link_to _(model.constantize.human_name.pluralize), admin_items_path}<br /><small>#{description}</small></td>
|
|
31
|
+
<td class="right"><small>
|
|
32
|
+
#{link_to _('Add'), new_admin_item_path if @current_user.can_perform?(model, 'create')}
|
|
33
|
+
</small></td>
|
|
34
|
+
</tr>
|
|
35
|
+
HTML
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
html << <<-HTML
|
|
39
|
+
</table>
|
|
40
|
+
HTML
|
|
41
|
+
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
##
|
|
49
|
+
# Resources (wich are not models) on the dashboard.
|
|
50
|
+
#
|
|
51
|
+
def resources
|
|
52
|
+
|
|
53
|
+
available = Typus.resources.map do |resource|
|
|
54
|
+
resource if @current_user.resources.include?(resource)
|
|
55
|
+
end
|
|
56
|
+
return if available.compact.empty?
|
|
57
|
+
|
|
58
|
+
returning(String.new) do |html|
|
|
59
|
+
|
|
60
|
+
html << <<-HTML
|
|
61
|
+
<table>
|
|
62
|
+
<tr>
|
|
63
|
+
<th colspan="2">#{_("Resources")}</th>
|
|
64
|
+
</tr>
|
|
65
|
+
HTML
|
|
66
|
+
|
|
67
|
+
available.compact.each do |resource|
|
|
68
|
+
|
|
69
|
+
resource_path = { :controller => "admin/#{resource.underscore}" }
|
|
70
|
+
|
|
71
|
+
html << <<-HTML
|
|
72
|
+
<tr class="#{cycle('even', 'odd')}">
|
|
73
|
+
<td>#{link_to _(resource.humanize), resource_path}</td>
|
|
74
|
+
<td align="right" style="vertical-align: bottom;"></td>
|
|
75
|
+
</tr>
|
|
76
|
+
HTML
|
|
77
|
+
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
html << <<-HTML
|
|
81
|
+
</table>
|
|
82
|
+
HTML
|
|
83
|
+
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def typus_block(*args)
|
|
89
|
+
|
|
90
|
+
options = args.extract_options!
|
|
91
|
+
template = [ 'admin', options[:resource], options[:location], "_#{options[:partial]}.html.erb" ].compact.join('/')
|
|
92
|
+
|
|
93
|
+
exists = ActionController::Base.view_paths.map { |vp| File.exists?("#{vp}/#{template}") }
|
|
94
|
+
|
|
95
|
+
return unless exists.include?(true)
|
|
96
|
+
render :partial => template.gsub('/_', '/')
|
|
97
|
+
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def page_title(action = params[:action])
|
|
101
|
+
crumbs = [ Typus::Configuration.options[:app_name] ]
|
|
102
|
+
crumbs << @resource[:class].human_name.pluralize if @resource
|
|
103
|
+
crumbs << _(action.humanize) unless %w( index ).include?(action)
|
|
104
|
+
return crumbs.compact.map { |x| x }.join(' › ')
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def header
|
|
108
|
+
|
|
109
|
+
if ActionController::Routing::Routes.named_routes.routes.keys.include?(:root)
|
|
110
|
+
link_to_site = <<-HTML
|
|
111
|
+
<small>#{link_to _('View site'), root_path, :target => 'blank'}</small>
|
|
112
|
+
HTML
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
<<-HTML
|
|
116
|
+
<h1>#{Typus::Configuration.options[:app_name]} #{link_to_site}</h1>
|
|
117
|
+
HTML
|
|
118
|
+
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def login_info(user = @current_user)
|
|
122
|
+
|
|
123
|
+
admin_edit_typus_user_path = { :controller => "admin/#{Typus::Configuration.options[:user_class_name].tableize}",
|
|
124
|
+
:action => 'edit',
|
|
125
|
+
:id => user.id }
|
|
126
|
+
|
|
127
|
+
<<-HTML
|
|
128
|
+
<ul>
|
|
129
|
+
<li>#{_('Logged as')} #{link_to user.full_name(:display_role => true), admin_edit_typus_user_path}</li>
|
|
130
|
+
<li>#{link_to _('Sign out'), admin_sign_out_path }</li>
|
|
131
|
+
</ul>
|
|
132
|
+
HTML
|
|
133
|
+
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def display_flash_message(message = flash)
|
|
137
|
+
|
|
138
|
+
return if message.empty?
|
|
139
|
+
flash_type = message.keys.first
|
|
140
|
+
|
|
141
|
+
<<-HTML
|
|
142
|
+
<div id="flash" class="#{flash_type}">
|
|
143
|
+
<p>#{message[flash_type]}</p>
|
|
144
|
+
</div>
|
|
145
|
+
HTML
|
|
146
|
+
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def typus_message(message, html_class = 'notice')
|
|
150
|
+
<<-HTML
|
|
151
|
+
<div id="flash" class="#{html_class}">
|
|
152
|
+
<p>#{message}</p>
|
|
153
|
+
</div>
|
|
154
|
+
HTML
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def locales(uri = admin_set_locale_path)
|
|
158
|
+
|
|
159
|
+
return unless Typus.locales.many?
|
|
160
|
+
|
|
161
|
+
locale_links = Typus.locales.map { |l| "<a href=\"#{uri}?locale=#{l.last}\">#{l.first.downcase}</a>" }
|
|
162
|
+
|
|
163
|
+
<<-HTML
|
|
164
|
+
<p>#{_('Set language to')} #{locale_links.join(', ')}.</p>
|
|
165
|
+
HTML
|
|
166
|
+
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
class TypusMailer < ActionMailer::Base
|
|
2
|
+
|
|
3
|
+
self.template_root = "#{File.dirname(__FILE__)}/../views"
|
|
4
|
+
|
|
5
|
+
def reset_password_link(user)
|
|
6
|
+
@subject = "[#{Typus::Configuration.options[:app_name]}] #{_('Reset password')}"
|
|
7
|
+
@body = { :user => user }
|
|
8
|
+
@recipients = user.email
|
|
9
|
+
@from = Typus::Configuration.options[:email]
|
|
10
|
+
@sent_on = Time.now
|
|
11
|
+
@headers = {}
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
end
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<h2>Welcome to Typus!</h2>
|
|
2
|
+
|
|
3
|
+
<p>Documentation is available <a href="http://intraducibles.com/projects/typus">here</a>.</p>
|
|
4
|
+
|
|
5
|
+
<p>If you need help don't hesitate in joining the <a href="http://groups.google.com/group/typus" rel="external">Typus</a> mailing list.</p>
|
|
6
|
+
|
|
7
|
+
<p>Replace this message adding a <code>_sidebar.html.erb</code> file on the <code>app/views/admin/dashboard</code> folder.</p>
|
|
8
|
+
|
|
9
|
+
<p>Have a nice day!</p>
|