typus 0.9.17

Sign up to get free protection for your applications and to get access to all the features.
Files changed (154) hide show
  1. data/.gitignore +8 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +86 -0
  4. data/Rakefile +61 -0
  5. data/VERSION +1 -0
  6. data/app/controllers/admin/master_controller.rb +354 -0
  7. data/app/controllers/typus_controller.rb +128 -0
  8. data/app/helpers/admin/form_helper.rb +386 -0
  9. data/app/helpers/admin/master_helper.rb +104 -0
  10. data/app/helpers/admin/public_helper.rb +27 -0
  11. data/app/helpers/admin/sidebar_helper.rb +236 -0
  12. data/app/helpers/admin/table_helper.rb +227 -0
  13. data/app/helpers/typus_helper.rb +194 -0
  14. data/app/models/typus_mailer.rb +14 -0
  15. data/app/models/typus_user.rb +5 -0
  16. data/app/views/admin/dashboard/_sidebar.html.erb +9 -0
  17. data/app/views/admin/resources/edit.html.erb +24 -0
  18. data/app/views/admin/resources/index.html.erb +23 -0
  19. data/app/views/admin/resources/new.html.erb +22 -0
  20. data/app/views/admin/resources/show.html.erb +18 -0
  21. data/app/views/admin/shared/_footer.html.erb +1 -0
  22. data/app/views/admin/shared/_pagination.html.erb +28 -0
  23. data/app/views/layouts/admin.html.erb +73 -0
  24. data/app/views/layouts/typus.html.erb +29 -0
  25. data/app/views/typus/dashboard.html.erb +9 -0
  26. data/app/views/typus/recover_password.html.erb +7 -0
  27. data/app/views/typus/reset_password.html.erb +15 -0
  28. data/app/views/typus/sign_in.html.erb +9 -0
  29. data/app/views/typus/sign_up.html.erb +7 -0
  30. data/app/views/typus_mailer/reset_password_link.erb +11 -0
  31. data/config/locales/typus/de.yml +109 -0
  32. data/config/locales/typus/es.yml +109 -0
  33. data/config/locales/typus/language.yml.template +113 -0
  34. data/config/locales/typus/pt-BR.yml +111 -0
  35. data/config/locales/typus/ru.yml +111 -0
  36. data/generators/typus/templates/config/initializers/typus.rb +33 -0
  37. data/generators/typus/templates/config/typus/README +51 -0
  38. data/generators/typus/templates/config/typus/application.yml +6 -0
  39. data/generators/typus/templates/config/typus/application_roles.yml +23 -0
  40. data/generators/typus/templates/config/typus/typus.yml +14 -0
  41. data/generators/typus/templates/config/typus/typus_roles.yml +2 -0
  42. data/generators/typus/templates/db/create_typus_users.rb +21 -0
  43. data/generators/typus/templates/public/images/admin/arrow_down.gif +0 -0
  44. data/generators/typus/templates/public/images/admin/arrow_up.gif +0 -0
  45. data/generators/typus/templates/public/images/admin/spinner.gif +0 -0
  46. data/generators/typus/templates/public/images/admin/status_false.gif +0 -0
  47. data/generators/typus/templates/public/images/admin/status_true.gif +0 -0
  48. data/generators/typus/templates/public/images/admin/trash.gif +0 -0
  49. data/generators/typus/templates/public/javascripts/admin/application.js +14 -0
  50. data/generators/typus/templates/public/stylesheets/admin/reset.css +68 -0
  51. data/generators/typus/templates/public/stylesheets/admin/screen.css +729 -0
  52. data/generators/typus/typus_generator.rb +122 -0
  53. data/generators/typus_update_schema_to_01/templates/config/typus.yml +14 -0
  54. data/generators/typus_update_schema_to_01/templates/migration.rb +11 -0
  55. data/generators/typus_update_schema_to_01/typus_update_schema_to_01_generator.rb +19 -0
  56. data/lib/typus.rb +122 -0
  57. data/lib/typus/active_record.rb +307 -0
  58. data/lib/typus/authentication.rb +142 -0
  59. data/lib/typus/configuration.rb +85 -0
  60. data/lib/typus/extensions/routes.rb +15 -0
  61. data/lib/typus/format.rb +55 -0
  62. data/lib/typus/generator.rb +81 -0
  63. data/lib/typus/hash.rb +8 -0
  64. data/lib/typus/locale.rb +17 -0
  65. data/lib/typus/object.rb +21 -0
  66. data/lib/typus/quick_edit.rb +40 -0
  67. data/lib/typus/reloader.rb +15 -0
  68. data/lib/typus/string.rb +11 -0
  69. data/lib/typus/templates/index.html.erb +11 -0
  70. data/lib/typus/templates/resource_controller.rb.erb +15 -0
  71. data/lib/typus/templates/resource_controller_test.rb.erb +10 -0
  72. data/lib/typus/templates/resources_controller.rb.erb +37 -0
  73. data/lib/typus/user.rb +134 -0
  74. data/lib/vendor/active_record.rb +15 -0
  75. data/lib/vendor/paginator.rb +143 -0
  76. data/rails/init.rb +3 -0
  77. data/tasks/typus_tasks.rake +32 -0
  78. data/test/config/broken/application.yml +68 -0
  79. data/test/config/broken/application_roles.yml +20 -0
  80. data/test/config/broken/empty.yml +0 -0
  81. data/test/config/broken/empty_roles.yml +0 -0
  82. data/test/config/broken/undefined.yml +3 -0
  83. data/test/config/broken/undefined_roles.yml +6 -0
  84. data/test/config/default/typus.yml +14 -0
  85. data/test/config/default/typus_roles.yml +2 -0
  86. data/test/config/empty/empty_01.yml +0 -0
  87. data/test/config/empty/empty_01_roles.yml +0 -0
  88. data/test/config/empty/empty_02.yml +0 -0
  89. data/test/config/empty/empty_02_roles.yml +0 -0
  90. data/test/config/locales/es.yml +10 -0
  91. data/test/config/ordered/001_roles.yml +2 -0
  92. data/test/config/ordered/002_roles.yml +2 -0
  93. data/test/config/unordered/app_one_roles.yml +2 -0
  94. data/test/config/unordered/app_two_roles.yml +2 -0
  95. data/test/config/working/application.yml +68 -0
  96. data/test/config/working/application_roles.yml +22 -0
  97. data/test/config/working/typus.yml +14 -0
  98. data/test/config/working/typus_roles.yml +2 -0
  99. data/test/fixtures/app/controllers/admin/assets_controller.rb +2 -0
  100. data/test/fixtures/app/controllers/admin/categories_controller.rb +2 -0
  101. data/test/fixtures/app/controllers/admin/comments_controller.rb +2 -0
  102. data/test/fixtures/app/controllers/admin/pages_controller.rb +2 -0
  103. data/test/fixtures/app/controllers/admin/posts_controller.rb +2 -0
  104. data/test/fixtures/app/controllers/admin/status_controller.rb +6 -0
  105. data/test/fixtures/app/controllers/admin/typus_users_controller.rb +2 -0
  106. data/test/fixtures/app/controllers/admin/watch_dog_controller.rb +6 -0
  107. data/test/fixtures/app/views/admin/comments/_edit.html.erb +1 -0
  108. data/test/fixtures/app/views/admin/comments/_index.html.erb +1 -0
  109. data/test/fixtures/app/views/admin/comments/_new.html.erb +1 -0
  110. data/test/fixtures/app/views/admin/comments/_show.html.erb +1 -0
  111. data/test/fixtures/app/views/admin/comments/_sidebar.html.erb +1 -0
  112. data/test/fixtures/app/views/admin/dashboard/_content.html.erb +1 -0
  113. data/test/fixtures/app/views/admin/dashboard/_sidebar.html.erb +1 -0
  114. data/test/fixtures/app/views/admin/resources/_sidebar.html.erb +1 -0
  115. data/test/fixtures/app/views/admin/shared/_footer.html.erb +1 -0
  116. data/test/fixtures/app/views/admin/status/index.html.erb +1 -0
  117. data/test/fixtures/app/views/admin/templates/_datepicker.html.erb +1 -0
  118. data/test/fixtures/assets.yml +11 -0
  119. data/test/fixtures/categories.yml +14 -0
  120. data/test/fixtures/comments.yml +27 -0
  121. data/test/fixtures/pages.yml +41 -0
  122. data/test/fixtures/posts.yml +37 -0
  123. data/test/fixtures/typus_users.yml +54 -0
  124. data/test/functional/admin/assets_controller_test.rb +57 -0
  125. data/test/functional/admin/categories_controller_test.rb +106 -0
  126. data/test/functional/admin/comments_controller_test.rb +120 -0
  127. data/test/functional/admin/master_controller_test.rb +5 -0
  128. data/test/functional/admin/posts_controller_test.rb +261 -0
  129. data/test/functional/admin/status_controller_test.rb +43 -0
  130. data/test/functional/admin/typus_users_controller_test.rb +239 -0
  131. data/test/functional/typus_controller_test.rb +321 -0
  132. data/test/helper.rb +51 -0
  133. data/test/helpers/admin/form_helper_test.rb +337 -0
  134. data/test/helpers/admin/master_helper_test.rb +69 -0
  135. data/test/helpers/admin/public_helper_test.rb +26 -0
  136. data/test/helpers/admin/sidebar_helper_test.rb +335 -0
  137. data/test/helpers/admin/table_helper_test.rb +239 -0
  138. data/test/helpers/typus_helper_test.rb +117 -0
  139. data/test/lib/active_record_test.rb +382 -0
  140. data/test/lib/configuration_test.rb +94 -0
  141. data/test/lib/hash_test.rb +11 -0
  142. data/test/lib/routes_test.rb +71 -0
  143. data/test/lib/string_test.rb +25 -0
  144. data/test/lib/typus_test.rb +85 -0
  145. data/test/models.rb +51 -0
  146. data/test/schema.rb +64 -0
  147. data/test/unit/typus_mailer_test.rb +33 -0
  148. data/test/unit/typus_test.rb +17 -0
  149. data/test/unit/typus_user_roles_test.rb +90 -0
  150. data/test/unit/typus_user_test.rb +177 -0
  151. data/test/vendor/active_record_test.rb +18 -0
  152. data/test/vendor/paginator_test.rb +136 -0
  153. data/typus.gemspec +228 -0
  154. metadata +241 -0
@@ -0,0 +1,128 @@
1
+ class TypusController < ApplicationController
2
+
3
+ unloadable
4
+
5
+ layout :select_layout
6
+
7
+ include Typus::Authentication
8
+ include Typus::Locale
9
+ include Typus::QuickEdit
10
+ include Typus::Reloader
11
+
12
+ if Typus::Configuration.options[:ssl]
13
+ include SslRequirement
14
+ ssl_required :sign_in, :sign_out,
15
+ :dashboard,
16
+ :recover_password, :reset_password
17
+ end
18
+
19
+ filter_parameter_logging :password
20
+
21
+ before_filter :set_locale
22
+
23
+ before_filter :reload_config_et_roles
24
+ before_filter :require_login,
25
+ :except => [ :sign_up, :sign_in, :sign_out,
26
+ :recover_password, :reset_password,
27
+ :quick_edit ]
28
+
29
+ before_filter :check_if_user_can_perform_action_on_resource_without_model,
30
+ :except => [ :sign_up, :sign_in, :sign_out,
31
+ :dashboard,
32
+ :recover_password, :reset_password,
33
+ :quick_edit, :set_locale ]
34
+
35
+ before_filter :recover_password_disabled?,
36
+ :only => [ :recover_password, :reset_password ]
37
+
38
+ def dashboard
39
+ flash[:notice] = _("There are not defined applications in config/typus/*.yml.") if Typus.applications.empty?
40
+ end
41
+
42
+ def sign_in
43
+
44
+ redirect_to admin_sign_up_path and return if Typus.user_class.count.zero?
45
+
46
+ if request.post?
47
+ if user = Typus.user_class.authenticate(params[:user][:email], params[:user][:password])
48
+ session[:typus_user_id] = user.id
49
+ redirect_to params[:back_to] || admin_dashboard_path
50
+ else
51
+ flash[:error] = _("The email and/or password you entered is invalid.")
52
+ redirect_to admin_sign_in_path
53
+ end
54
+ end
55
+
56
+ end
57
+
58
+ def sign_out
59
+ session[:typus_user_id] = nil
60
+ redirect_to admin_sign_in_path
61
+ end
62
+
63
+ def recover_password
64
+ if request.post?
65
+ if user = Typus.user_class.find_by_email(params[:user][:email])
66
+ ActionMailer::Base.default_url_options[:host] = request.host_with_port
67
+ TypusMailer.deliver_reset_password_link(user)
68
+ flash[:success] = _("Password recovery link sent to your email.")
69
+ redirect_to admin_sign_in_path
70
+ else
71
+ redirect_to admin_recover_password_path
72
+ end
73
+ end
74
+ end
75
+
76
+ ##
77
+ # Available if Typus::Configuration.options[:recover_password] is enabled.
78
+ #
79
+ def reset_password
80
+ @user = Typus.user_class.find_by_token!(params[:token])
81
+ if request.post?
82
+ @user.password = params[:user][:password]
83
+ @user.password_confirmation = params[:user][:password_confirmation]
84
+ if @user.save
85
+ session[:typus_user_id] = @user.id
86
+ redirect_to admin_dashboard_path
87
+ else
88
+ render :action => 'reset_password'
89
+ end
90
+ end
91
+ end
92
+
93
+ def sign_up
94
+
95
+ redirect_to admin_sign_in_path and return unless Typus.user_class.count.zero?
96
+
97
+ if request.post?
98
+
99
+ email, password = params[:user][:email], 'columbia'
100
+ user = Typus.user_class.generate(email, password)
101
+
102
+ if user.save
103
+ session[:typus_user_id] = user.id
104
+ flash[:notice] = _("Password set to \"{{password}}\".", :password => password)
105
+ redirect_to admin_dashboard_path
106
+ else
107
+ flash[:error] = _("That doesn't seem like a valid email address.")
108
+ end
109
+
110
+ else
111
+
112
+ flash[:notice] = _("Enter your email below to create the first user.")
113
+
114
+ end
115
+
116
+ end
117
+
118
+ private
119
+
120
+ def recover_password_disabled?
121
+ redirect_to admin_sign_in_path unless Typus::Configuration.options[:recover_password]
122
+ end
123
+
124
+ def select_layout
125
+ %w( sign_up sign_in sign_out recover_password reset_password ).include?(action_name) ? 'typus' : 'admin'
126
+ end
127
+
128
+ end
@@ -0,0 +1,386 @@
1
+ module Admin::FormHelper
2
+
3
+ def build_form(fields)
4
+
5
+ options = { :start_year => @resource[:class].typus_options_for(:start_year),
6
+ :end_year => @resource[:class].typus_options_for(:end_year),
7
+ :minute_step => @resource[:class].typus_options_for(:minute_step) }
8
+
9
+ returning(String.new) do |html|
10
+ html << (error_messages_for :item, :header_tag => 'h3')
11
+ html << '<ul>'
12
+
13
+ fields.each do |key, value|
14
+ if template = @resource[:class].typus_template(key)
15
+ html << typus_template_field(key, template, options)
16
+ next
17
+ end
18
+ case value
19
+ when :belongs_to then html << typus_belongs_to_field(key)
20
+ when :boolean then html << typus_boolean_field(key)
21
+ when :date then html << typus_date_field(key, options)
22
+ when :datetime then html << typus_datetime_field(key, options)
23
+ when :file then html << typus_file_field(key)
24
+ when :password then html << typus_password_field(key)
25
+ when :selector then html << typus_selector_field(key)
26
+ when :text then html << typus_text_field(key)
27
+ when :tiny_mce then html << typus_tiny_mce_field(key)
28
+ when :time then html << typus_time_field(key, options)
29
+ when :tree then html << typus_tree_field(key)
30
+ else
31
+ html << typus_string_field(key)
32
+ end
33
+ end
34
+ html << '</ul>'
35
+ end
36
+ end
37
+
38
+ def typus_belongs_to_field(attribute)
39
+
40
+ ##
41
+ # We only can pass parameters to 'new' and 'edit', so this hack makes
42
+ # the work to replace the current action.
43
+ #
44
+ params[:action] = (params[:action] == 'create') ? 'new' : params[:action]
45
+
46
+ back_to = '/' + [ params[:controller], params[:action], params[:id] ].compact.join('/')
47
+
48
+ related = @resource[:class].reflect_on_association(attribute.to_sym).class_name.constantize
49
+ related_fk = @resource[:class].reflect_on_association(attribute.to_sym).primary_key_name
50
+
51
+ message = [ _("Are you sure you want to leave this page?"),
52
+ _("If you have made any changes to the fields without clicking the Save/Update entry button, your changes will be lost."),
53
+ _("Click OK to continue, or click Cancel to stay on this page.") ]
54
+
55
+ returning(String.new) do |html|
56
+
57
+ if related.respond_to?(:roots)
58
+ html << typus_tree_field(related_fk, related.roots, related_fk)
59
+ else
60
+ html << <<-HTML
61
+ <li><label for="item_#{attribute}">#{_(related_fk.humanize)}
62
+ <small>#{link_to _("Add"), { :controller => "admin/#{related.class_name.tableize}", :action => 'new', :back_to => back_to, :selected => related_fk }, :confirm => message.join("\n\n") if @current_user.can_perform?(related, 'create')}</small>
63
+ </label>
64
+ #{select :item, related_fk, related.find(:all, :order => related.typus_order_by).collect { |p| [p.typus_name, p.id] }, { :include_blank => true }, { :disabled => attribute_disabled?(attribute) } }</li>
65
+ HTML
66
+ end
67
+
68
+ end
69
+
70
+ end
71
+
72
+ def typus_boolean_field(attribute)
73
+ attribute_name = attribute.gsub(/\?$/,'')
74
+ custom_true = @resource[:class].typus_boolean(attribute)[:true]
75
+ custom_true = custom_true != 'True' ? custom_true : "Checked if active"
76
+ <<-HTML
77
+ <li><label>#{@resource[:class].human_attribute_name(attribute)}</label>
78
+ #{check_box :item, attribute_name} <label class="inline_label" for="item_#{attribute_name}">#{_(custom_true)}</label></li>
79
+ HTML
80
+ end
81
+
82
+ def typus_date_field(attribute, options)
83
+ <<-HTML
84
+ <li><label for="item_#{attribute}">#{@resource[:class].human_attribute_name(attribute)}</label>
85
+ #{date_select :item, attribute, options, { :disabled => attribute_disabled?(attribute)} }</li>
86
+ HTML
87
+ end
88
+
89
+ def typus_datetime_field(attribute, options)
90
+ <<-HTML
91
+ <li><label for="item_#{attribute}">#{@resource[:class].human_attribute_name(attribute)}</label>
92
+ #{datetime_select :item, attribute, options, {:disabled => attribute_disabled?(attribute)}}</li>
93
+ HTML
94
+ end
95
+
96
+ def typus_file_field(attribute)
97
+
98
+ attribute_display = attribute.split('_file_name').first
99
+
100
+ <<-HTML
101
+ <li><label for="item_#{attribute}">#{_(attribute_display.humanize)}</label>
102
+ #{file_field :item, attribute.split("_file_name").first, :disabled => attribute_disabled?(attribute)}</li>
103
+ HTML
104
+
105
+ end
106
+
107
+ def typus_password_field(attribute)
108
+ <<-HTML
109
+ <li><label for="item_#{attribute}">#{@resource[:class].human_attribute_name(attribute)}</label>
110
+ #{password_field :item, attribute, :class => 'text', :disabled => attribute_disabled?(attribute)}</li>
111
+ HTML
112
+ end
113
+
114
+ def typus_selector_field(attribute)
115
+ returning(String.new) do |html|
116
+ options = []
117
+ @resource[:class].send(attribute).each do |option|
118
+ case option.kind_of?(Array)
119
+ when true
120
+ selected = (@item.send(attribute).to_s == option.last.to_s) ? 'selected' : ''
121
+ options << "<option #{selected} value=\"#{option.last}\">#{option.first}</option>"
122
+ else
123
+ selected = (@item.send(attribute).to_s == option.to_s) ? 'selected' : ''
124
+ options << "<option #{selected} value=\"#{option}\">#{option}</option>"
125
+ end
126
+ end
127
+ html << <<-HTML
128
+ <li><label for="item_#{attribute}">#{@resource[:class].human_attribute_name(attribute)}</label>
129
+ <select id="item_#{attribute}" #{attribute_disabled?(attribute) ? 'disabled="disabled"' : ''} name="item[#{attribute}]">
130
+ <option value=""></option>
131
+ #{options.join("\n")}
132
+ </select></li>
133
+ HTML
134
+ end
135
+ end
136
+
137
+ def typus_text_field(attribute)
138
+ <<-HTML
139
+ <li><label for="item_#{attribute}">#{@resource[:class].human_attribute_name(attribute)}</label>
140
+ #{text_area :item, attribute, :class => 'text', :rows => @resource[:class].typus_options_for(:form_rows), :disabled => attribute_disabled?(attribute)}</li>
141
+ HTML
142
+ end
143
+
144
+ def typus_tiny_mce_field(attribute)
145
+ <<-HTML
146
+ <li><label for="item_#{attribute}">#{@resource[:class].human_attribute_name(attribute)}</label>
147
+ #{text_area :item, attribute, :class => 'mceEditor', :disabled => attribute_disabled?(attribute)}</li>
148
+ HTML
149
+ end
150
+
151
+ def typus_time_field(attribute, options)
152
+ <<-HTML
153
+ <li><label for="item_#{attribute}">#{@resource[:class].human_attribute_name(attribute)}</label>
154
+ #{time_select :item, attribute, options, {:disabled => attribute_disabled?(attribute)}}</li>
155
+ HTML
156
+ end
157
+
158
+ def typus_tree_field(attribute, items = @resource[:class].roots, attribute_virtual = 'parent_id')
159
+ <<-HTML
160
+ <li><label for="item_#{attribute}">#{@resource[:class].human_attribute_name(attribute)}</label>
161
+ <select id="item_#{attribute}" #{attribute_disabled?(attribute) ? 'disabled="disabled"' : ''} name="item[#{attribute}]">
162
+ <option value=""></option>
163
+ #{expand_tree_into_select_field(items, attribute_virtual)}
164
+ </select></li>
165
+ HTML
166
+ end
167
+
168
+ def typus_string_field(attribute)
169
+
170
+ # Read only fields.
171
+ if @resource[:class].typus_field_options_for(:read_only).include?(attribute)
172
+ value = 'read_only' if %w( edit ).include?(params[:action])
173
+ end
174
+
175
+ # Auto generated fields.
176
+ if @resource[:class].typus_field_options_for(:auto_generated).include?(attribute)
177
+ value = 'auto_generated' if %w( new edit ).include?(params[:action])
178
+ end
179
+
180
+ comment = %w( read_only auto_generated ).include?(value) ? "<small>#{value} field</small>".humanize : ''
181
+
182
+ attribute_humanized = @resource[:class].human_attribute_name(attribute)
183
+ attribute_humanized += " (#{attribute})" if attribute.include?('_id')
184
+
185
+ <<-HTML
186
+ <li><label for="item_#{attribute}">#{attribute_humanized}#{comment}</label>
187
+ #{text_field :item, attribute, :class => 'text', :disabled => attribute_disabled?(attribute) }</li>
188
+ HTML
189
+
190
+ end
191
+
192
+ def typus_relationships
193
+
194
+ # OPTIMIZE
195
+ @back_to = '/' + [ params[:controller], params[:action], params[:id] ].compact.join('/')
196
+
197
+ returning(String.new) do |html|
198
+ @resource[:class].typus_defaults_for(:relationships).each do |relationship|
199
+
200
+ association = @resource[:class].reflect_on_association(relationship.to_sym)
201
+
202
+ next if !@current_user.can_perform?(association.class_name.constantize, 'read')
203
+
204
+ case association.macro
205
+ when :has_and_belongs_to_many
206
+ html << typus_form_has_and_belongs_to_many(relationship)
207
+ when :has_many
208
+ html << typus_form_has_many(relationship)
209
+ when :has_one
210
+ html << typus_form_has_one(relationship)
211
+ end
212
+
213
+ end
214
+ end
215
+
216
+ end
217
+
218
+ def typus_form_has_many(field)
219
+ returning(String.new) do |html|
220
+
221
+ model_to_relate = @resource[:class].reflect_on_association(field.to_sym).class_name.constantize
222
+ model_to_relate_as_resource = model_to_relate.name.tableize
223
+
224
+ reflection = @resource[:class].reflect_on_association(field.to_sym)
225
+ association = reflection.macro
226
+ foreign_key = reflection.through_reflection ? reflection.primary_key_name.pluralize : reflection.primary_key_name
227
+
228
+ link_options = { :controller => "admin/#{field}",
229
+ :action => 'new',
230
+ :back_to => "#{@back_to}##{field}",
231
+ :resource => @resource[:self].singularize,
232
+ :resource_id => @item.id,
233
+ foreign_key => @item.id }
234
+
235
+ html << <<-HTML
236
+ <a name="#{field}"></a>
237
+ <div class="box_relationships">
238
+ <h2>
239
+ #{link_to model_to_relate.typus_human_name.pluralize, { :controller => "admin/#{model_to_relate_as_resource}", foreign_key => @item.id }, :title => _("{{model}} filtered by {{filtered_by}}", :model => model_to_relate.typus_human_name.pluralize, :filtered_by => @item.typus_name)}
240
+ <small>#{link_to _("Add new"), link_options if @current_user.can_perform?(model_to_relate, 'create')}</small>
241
+ </h2>
242
+ HTML
243
+
244
+ conditions = if model_to_relate.typus_options_for(:only_user_items) && !@current_user.is_root?
245
+ { Typus.user_fk => @current_user }
246
+ end
247
+
248
+ options = { :order => model_to_relate.typus_order_by, :conditions => conditions }
249
+ items_count = @resource[:class].find(params[:id]).send(field).count(:conditions => conditions)
250
+ items_per_page = model_to_relate.typus_options_for(:per_page).to_i
251
+
252
+ @pager = ::Paginator.new(items_count, items_per_page) do |offset, per_page|
253
+ options.merge!({:limit => per_page, :offset => offset})
254
+ items = @resource[:class].find(params[:id]).send(field).find(:all, options)
255
+ end
256
+
257
+ @items = @pager.page(params[:page])
258
+
259
+ unless @items.empty?
260
+ options = { :back_to => "#{@back_to}##{field}", :resource => @resource[:self], :resource_id => @item.id }
261
+ html << build_list(model_to_relate,
262
+ model_to_relate.typus_fields_for(:relationship),
263
+ @items,
264
+ model_to_relate_as_resource,
265
+ options,
266
+ association)
267
+ html << pagination(:anchor => model_to_relate.name.tableize) unless pagination.nil?
268
+ else
269
+ html << <<-HTML
270
+ <div id="flash" class="notice"><p>#{_("There are no {{records}}.", :records => model_to_relate.typus_human_name.pluralize.downcase)}</p></div>
271
+ HTML
272
+ end
273
+ html << <<-HTML
274
+ </div>
275
+ HTML
276
+ end
277
+ end
278
+
279
+ def typus_form_has_and_belongs_to_many(field)
280
+ returning(String.new) do |html|
281
+
282
+ model_to_relate = @resource[:class].reflect_on_association(field.to_sym).class_name.constantize
283
+ model_to_relate_as_resource = model_to_relate.name.tableize
284
+
285
+ reflection = @resource[:class].reflect_on_association(field.to_sym)
286
+ association = reflection.macro
287
+
288
+ html << <<-HTML
289
+ <a name="#{field}"></a>
290
+ <div class="box_relationships">
291
+ <h2>
292
+ #{link_to model_to_relate.typus_human_name.pluralize, :controller => "admin/#{model_to_relate_as_resource}"}
293
+ <small>#{link_to _("Add new"), :controller => field, :action => 'new', :back_to => @back_to, :resource => @resource[:self], :resource_id => @item.id if @current_user.can_perform?(model_to_relate, 'create')}</small>
294
+ </h2>
295
+ HTML
296
+ items_to_relate = (model_to_relate.find(:all) - @item.send(field))
297
+ unless items_to_relate.empty?
298
+ html << <<-HTML
299
+ #{form_tag :action => 'relate', :id => @item.id}
300
+ #{hidden_field :related, :model, :value => model_to_relate}
301
+ <p>#{ select :related, :id, items_to_relate.collect { |f| [f.typus_name, f.id] }.sort_by { |e| e.first } } &nbsp; #{submit_tag _("Add"), :class => 'button'}</p>
302
+ </form>
303
+ HTML
304
+ end
305
+ items = @resource[:class].find(params[:id]).send(field)
306
+ unless items.empty?
307
+ html << build_list(model_to_relate,
308
+ model_to_relate.typus_fields_for(:relationship),
309
+ items,
310
+ model_to_relate_as_resource,
311
+ {},
312
+ association)
313
+ else
314
+ html << <<-HTML
315
+ <div id="flash" class="notice"><p>#{_("There are no {{records}}.", :records => model_to_relate.typus_human_name.pluralize.downcase)}</p></div>
316
+ HTML
317
+ end
318
+ html << <<-HTML
319
+ </div>
320
+ HTML
321
+ end
322
+ end
323
+
324
+ def typus_form_has_one(field)
325
+ returning(String.new) do |html|
326
+
327
+ model_to_relate = @resource[:class].reflect_on_association(field.to_sym).class_name.constantize
328
+ model_to_relate_as_resource = model_to_relate.name.tableize
329
+
330
+ reflection = @resource[:class].reflect_on_association(field.to_sym)
331
+ association = reflection.macro
332
+
333
+ html << <<-HTML
334
+ <a name="#{field}"></a>
335
+ <div class="box_relationships">
336
+ <h2>
337
+ #{link_to model_to_relate.typus_human_name, :controller => "admin/#{model_to_relate_as_resource}"}
338
+ </h2>
339
+ HTML
340
+ items = Array.new
341
+ items << @resource[:class].find(params[:id]).send(field) unless @resource[:class].find(params[:id]).send(field).nil?
342
+ unless items.empty?
343
+ options = { :back_to => @back_to, :resource => @resource[:self], :resource_id => @item.id }
344
+ html << build_list(model_to_relate,
345
+ model_to_relate.typus_fields_for(:relationship),
346
+ items,
347
+ model_to_relate_as_resource,
348
+ options,
349
+ association)
350
+ else
351
+ html << <<-HTML
352
+ <div id="flash" class="notice"><p>#{_("There is no {{records}}.", :records => model_to_relate.typus_human_name.downcase)}</p></div>
353
+ HTML
354
+ end
355
+ html << <<-HTML
356
+ </div>
357
+ HTML
358
+ end
359
+ end
360
+
361
+ def typus_template_field(attribute, template, options = {})
362
+ folder = Typus::Configuration.options[:templates_folder]
363
+ template_name = File.join(folder, template)
364
+
365
+ output = render(:partial => template_name, :locals => { :resource => @resource, :attribute => attribute, :options => options } )
366
+ output || "#{attribute}: Can not find the template '#{template}'"
367
+ end
368
+
369
+ def attribute_disabled?(attribute)
370
+ accessible = @resource[:class].accessible_attributes
371
+ return accessible.nil? ? false : !accessible.include?(attribute)
372
+ end
373
+
374
+ ##
375
+ # Tree builder when model +acts_as_tree+
376
+ #
377
+ def expand_tree_into_select_field(items, attribute)
378
+ returning(String.new) do |html|
379
+ items.each do |item|
380
+ html << %{<option #{"selected" if @item.send(attribute) == item.id} value="#{item.id}">#{"&nbsp;" * item.ancestors.size * 8} &#92;_ #{item.typus_name}</option>\n}
381
+ html << expand_tree_into_select_field(item.children, attribute) unless item.children.empty?
382
+ end
383
+ end
384
+ end
385
+
386
+ end