incline 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (303) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/Gemfile +17 -0
  4. data/Gemfile.lock +186 -0
  5. data/MIT-LICENSE +20 -0
  6. data/README.rdoc +208 -0
  7. data/Rakefile +37 -0
  8. data/app/assets/fonts/incline/.keep +0 -0
  9. data/app/assets/images/incline/.keep +0 -0
  10. data/app/assets/images/incline/barcode-B.svg +181 -0
  11. data/app/assets/javascripts/incline/activate_classed_items.js +11 -0
  12. data/app/assets/javascripts/incline/application.js +30 -0
  13. data/app/assets/javascripts/incline/bootstrap-datepicker.js +1800 -0
  14. data/app/assets/javascripts/incline/datatables.js +22193 -0
  15. data/app/assets/javascripts/incline/escapeHtml.js +10 -0
  16. data/app/assets/javascripts/incline/inline_actions.js +479 -0
  17. data/app/assets/javascripts/incline/jquery.doubleScroll.js +112 -0
  18. data/app/assets/javascripts/incline/jquery.number.js +764 -0
  19. data/app/assets/javascripts/incline/regexMask.js +27 -0
  20. data/app/assets/javascripts/incline/select2/i18n/en.js +3 -0
  21. data/app/assets/javascripts/incline/select2/select2.full.js +6436 -0
  22. data/app/assets/stylesheets/incline/application.css +18 -0
  23. data/app/assets/stylesheets/incline/bootstrap-theme.min.css +5 -0
  24. data/app/assets/stylesheets/incline/custom.scss +279 -0
  25. data/app/assets/stylesheets/incline/datatables.css +494 -0
  26. data/app/assets/stylesheets/incline/datepicker3.css +790 -0
  27. data/app/assets/stylesheets/incline/select2.css +484 -0
  28. data/app/controllers/incline/access_groups_controller.rb +127 -0
  29. data/app/controllers/incline/access_test_controller.rb +30 -0
  30. data/app/controllers/incline/account_activations_controller.rb +28 -0
  31. data/app/controllers/incline/application_controller.rb +11 -0
  32. data/app/controllers/incline/contact_controller.rb +34 -0
  33. data/app/controllers/incline/password_resets_controller.rb +113 -0
  34. data/app/controllers/incline/security_controller.rb +100 -0
  35. data/app/controllers/incline/sessions_controller.rb +50 -0
  36. data/app/controllers/incline/users_controller.rb +304 -0
  37. data/app/controllers/incline/welcome_controller.rb +19 -0
  38. data/app/helpers/incline/.keep +0 -0
  39. data/app/mailers/incline/application_mailer_base.rb +11 -0
  40. data/app/mailers/incline/contact_form.rb +19 -0
  41. data/app/mailers/incline/user_mailer.rb +45 -0
  42. data/app/models/incline/access_group.rb +121 -0
  43. data/app/models/incline/access_group_group_member.rb +12 -0
  44. data/app/models/incline/access_group_user_member.rb +10 -0
  45. data/app/models/incline/action_group.rb +12 -0
  46. data/app/models/incline/action_security.rb +222 -0
  47. data/app/models/incline/contact_message.rb +37 -0
  48. data/app/models/incline/disable_info.rb +20 -0
  49. data/app/models/incline/password_reset.rb +14 -0
  50. data/app/models/incline/password_reset_request.rb +14 -0
  51. data/app/models/incline/user.rb +437 -0
  52. data/app/models/incline/user_login_history.rb +30 -0
  53. data/app/views/incline/access_groups/_details.json.jbuilder +10 -0
  54. data/app/views/incline/access_groups/_form.html.erb +19 -0
  55. data/app/views/incline/access_groups/_list.html.erb +60 -0
  56. data/app/views/incline/access_groups/_messages.json.jbuilder +6 -0
  57. data/app/views/incline/access_groups/edit.html.erb +2 -0
  58. data/app/views/incline/access_groups/index.html.erb +6 -0
  59. data/app/views/incline/access_groups/index.json.jbuilder +16 -0
  60. data/app/views/incline/access_groups/new.html.erb +2 -0
  61. data/app/views/incline/access_groups/show.html.erb +9 -0
  62. data/app/views/incline/access_groups/show.json.jbuilder +11 -0
  63. data/app/views/incline/contact/new.html.erb +22 -0
  64. data/app/views/incline/contact_form/contact.html.erb +16 -0
  65. data/app/views/incline/contact_form/contact.text.erb +13 -0
  66. data/app/views/incline/password_resets/edit.html.erb +16 -0
  67. data/app/views/incline/password_resets/new.html.erb +12 -0
  68. data/app/views/incline/security/_details.json.jbuilder +7 -0
  69. data/app/views/incline/security/_form.html.erb +20 -0
  70. data/app/views/incline/security/_list.html.erb +89 -0
  71. data/app/views/incline/security/_messages.json.jbuilder +6 -0
  72. data/app/views/incline/security/edit.html.erb +2 -0
  73. data/app/views/incline/security/index.html.erb +6 -0
  74. data/app/views/incline/security/index.json.jbuilder +16 -0
  75. data/app/views/incline/security/show.html.erb +31 -0
  76. data/app/views/incline/security/show.json.jbuilder +11 -0
  77. data/app/views/incline/sessions/new.html.erb +26 -0
  78. data/app/views/incline/user_mailer/account_activation.html.erb +7 -0
  79. data/app/views/incline/user_mailer/account_activation.text.erb +6 -0
  80. data/app/views/incline/user_mailer/invalid_password_reset.html.erb +3 -0
  81. data/app/views/incline/user_mailer/invalid_password_reset.text.erb +5 -0
  82. data/app/views/incline/user_mailer/password_reset.html.erb +8 -0
  83. data/app/views/incline/user_mailer/password_reset.text.erb +7 -0
  84. data/app/views/incline/users/_details.json.jbuilder +32 -0
  85. data/app/views/incline/users/_form.html.erb +21 -0
  86. data/app/views/incline/users/_list.html.erb +102 -0
  87. data/app/views/incline/users/_messages.json.jbuilder +6 -0
  88. data/app/views/incline/users/disable_confirm.html.erb +19 -0
  89. data/app/views/incline/users/edit.html.erb +5 -0
  90. data/app/views/incline/users/index.html.erb +6 -0
  91. data/app/views/incline/users/index.json.jbuilder +16 -0
  92. data/app/views/incline/users/new.html.erb +5 -0
  93. data/app/views/incline/users/show.html.erb +12 -0
  94. data/app/views/incline/users/show.json.jbuilder +11 -0
  95. data/app/views/incline/welcome/home.html.erb +5 -0
  96. data/app/views/layouts/application.html.erb +1 -0
  97. data/app/views/layouts/incline/_account_menu.html.erb +18 -0
  98. data/app/views/layouts/incline/_app_menu_anon.html.erb +1 -0
  99. data/app/views/layouts/incline/_app_menu_authenticated.html.erb +1 -0
  100. data/app/views/layouts/incline/_footer.html.erb +13 -0
  101. data/app/views/layouts/incline/_header.html.erb +21 -0
  102. data/app/views/layouts/incline/_html_mailer.html.erb +5 -0
  103. data/app/views/layouts/incline/_incline_app.html.erb +25 -0
  104. data/app/views/layouts/incline/_messages.html.erb +3 -0
  105. data/app/views/layouts/incline/_shim.html.erb +3 -0
  106. data/app/views/layouts/incline/_text_mailer.text.erb +1 -0
  107. data/app/views/layouts/incline/application.html.erb +1 -0
  108. data/app/views/layouts/mailer.html.erb +2 -0
  109. data/app/views/layouts/mailer.text.erb +2 -0
  110. data/bin/rails +12 -0
  111. data/bin/test_scaffold.sh +10 -0
  112. data/config/routes.rb +61 -0
  113. data/db/migrate/20170511230126_create_incline_users.rb +26 -0
  114. data/db/migrate/20170515003052_create_incline_access_groups.rb +10 -0
  115. data/db/migrate/20170515003221_create_incline_user_login_histories.rb +12 -0
  116. data/db/migrate/20170515150908_create_incline_access_group_user_members.rb +11 -0
  117. data/db/migrate/20170515151058_create_incline_access_group_group_members.rb +11 -0
  118. data/db/migrate/20170517193432_add_comments_to_incline_user.rb +5 -0
  119. data/db/migrate/20170622132700_create_incline_action_securities.rb +16 -0
  120. data/db/migrate/20170622172712_create_incline_action_groups.rb +11 -0
  121. data/db/migrate/20170622195742_add_non_standard_to_action_security.rb +5 -0
  122. data/db/migrate/20170622230422_add_visible_to_action_security.rb +5 -0
  123. data/db/seeds.rb +81 -0
  124. data/exe/new_incline_app +42 -0
  125. data/lib/generators/incline/install_generator.rb +259 -0
  126. data/lib/generators/incline/templates/_app_menu_anon.html.erb +1 -0
  127. data/lib/generators/incline/templates/_app_menu_authenticated.html.erb +1 -0
  128. data/lib/generators/incline/templates/incline_application.css +17 -0
  129. data/lib/generators/incline/templates/incline_application.html.erb +1 -0
  130. data/lib/generators/incline/templates/incline_application.js +12 -0
  131. data/lib/generators/incline/templates/incline_database.yml +25 -0
  132. data/lib/generators/incline/templates/incline_email.yml +20 -0
  133. data/lib/generators/incline/templates/incline_mailer.html.erb +2 -0
  134. data/lib/generators/incline/templates/incline_mailer.text.erb +2 -0
  135. data/lib/generators/incline/templates/incline_users.yml +64 -0
  136. data/lib/generators/incline/templates/incline_version.rb +3 -0
  137. data/lib/incline/auth_engine_base.rb +52 -0
  138. data/lib/incline/data_tables_request.rb +336 -0
  139. data/lib/incline/date_time_formats.rb +6 -0
  140. data/lib/incline/engine.rb +212 -0
  141. data/lib/incline/errors.rb +15 -0
  142. data/lib/incline/extensions/action_controller_base.rb +526 -0
  143. data/lib/incline/extensions/action_mailer_base.rb +66 -0
  144. data/lib/incline/extensions/action_view_base.rb +489 -0
  145. data/lib/incline/extensions/active_record_base.rb +308 -0
  146. data/lib/incline/extensions/application.rb +137 -0
  147. data/lib/incline/extensions/application_configuration.rb +50 -0
  148. data/lib/incline/extensions/connection_adapter.rb +55 -0
  149. data/lib/incline/extensions/date_time_value.rb +123 -0
  150. data/lib/incline/extensions/date_value.rb +77 -0
  151. data/lib/incline/extensions/decimal_value.rb +55 -0
  152. data/lib/incline/extensions/erb_scaffold_generator.rb +31 -0
  153. data/lib/incline/extensions/float_value.rb +59 -0
  154. data/lib/incline/extensions/form_builder.rb +617 -0
  155. data/lib/incline/extensions/integer_value.rb +54 -0
  156. data/lib/incline/extensions/jbuilder_generator.rb +38 -0
  157. data/lib/incline/extensions/jbuilder_template.rb +39 -0
  158. data/lib/incline/extensions/main_app.rb +40 -0
  159. data/lib/incline/extensions/numeric.rb +63 -0
  160. data/lib/incline/extensions/object.rb +31 -0
  161. data/lib/incline/extensions/resource_route_generator.rb +53 -0
  162. data/lib/incline/extensions/session.rb +113 -0
  163. data/lib/incline/extensions/string.rb +50 -0
  164. data/lib/incline/extensions/test_case.rb +764 -0
  165. data/lib/incline/extensions/time_zone_converter.rb +40 -0
  166. data/lib/incline/global_status.rb +236 -0
  167. data/lib/incline/helpers/route_hash_formatter.rb +46 -0
  168. data/lib/incline/json_log_formatter.rb +96 -0
  169. data/lib/incline/json_logger.rb +17 -0
  170. data/lib/incline/log.rb +153 -0
  171. data/lib/incline/number_formats.rb +17 -0
  172. data/lib/incline/recaptcha.rb +346 -0
  173. data/lib/incline/user_manager.rb +212 -0
  174. data/lib/incline/validators/email_validator.rb +45 -0
  175. data/lib/incline/validators/ip_address_validator.rb +32 -0
  176. data/lib/incline/validators/recaptcha_validator.rb +37 -0
  177. data/lib/incline/validators/safe_name_validator.rb +31 -0
  178. data/lib/incline/version.rb +3 -0
  179. data/lib/incline/work_path.rb +75 -0
  180. data/lib/incline.rb +197 -0
  181. data/lib/tasks/incline_tasks.rake +4 -0
  182. data/lib/templates/erb/scaffold/_form.html.erb +43 -0
  183. data/lib/templates/erb/scaffold/_list.html.erb +81 -0
  184. data/lib/templates/erb/scaffold/edit.html.erb +1 -0
  185. data/lib/templates/erb/scaffold/index.html.erb +6 -0
  186. data/lib/templates/erb/scaffold/new.html.erb +1 -0
  187. data/lib/templates/erb/scaffold/show.html.erb +34 -0
  188. data/lib/templates/jbuilder/scaffold/_details.json.jbuilder +20 -0
  189. data/lib/templates/jbuilder/scaffold/index.json.jbuilder +16 -0
  190. data/lib/templates/jbuilder/scaffold/show.json.jbuilder +16 -0
  191. data/lib/templates/rails/scaffold_controller/controller.rb +128 -0
  192. data/test/controllers/incline/access_groups_controller_test.rb +65 -0
  193. data/test/controllers/incline/access_test_controller_test.rb +53 -0
  194. data/test/controllers/incline/contact_controller_test.rb +32 -0
  195. data/test/controllers/incline/security_controller_test.rb +39 -0
  196. data/test/controllers/incline/welcome_controller_test.rb +16 -0
  197. data/test/dummy/README.rdoc +28 -0
  198. data/test/dummy/Rakefile +6 -0
  199. data/test/dummy/app/assets/images/.keep +0 -0
  200. data/test/dummy/app/assets/javascripts/application.js +12 -0
  201. data/test/dummy/app/assets/stylesheets/application.css +17 -0
  202. data/test/dummy/app/controllers/application_controller.rb +5 -0
  203. data/test/dummy/app/controllers/concerns/.keep +0 -0
  204. data/test/dummy/app/helpers/application_helper.rb +2 -0
  205. data/test/dummy/app/mailers/.keep +0 -0
  206. data/test/dummy/app/models/.keep +0 -0
  207. data/test/dummy/app/models/concerns/.keep +0 -0
  208. data/test/dummy/app/views/layouts/application.html.erb +1 -0
  209. data/test/dummy/app/views/layouts/incline/_app_menu_anon.html.erb +1 -0
  210. data/test/dummy/app/views/layouts/incline/_app_menu_authenticated.html.erb +1 -0
  211. data/test/dummy/app/views/layouts/mailer.html.erb +2 -0
  212. data/test/dummy/app/views/layouts/mailer.text.erb +2 -0
  213. data/test/dummy/bin/bundle +3 -0
  214. data/test/dummy/bin/rails +4 -0
  215. data/test/dummy/bin/rake +4 -0
  216. data/test/dummy/bin/setup +29 -0
  217. data/test/dummy/config/application.rb +38 -0
  218. data/test/dummy/config/boot.rb +5 -0
  219. data/test/dummy/config/database.yml +34 -0
  220. data/test/dummy/config/email.yml +24 -0
  221. data/test/dummy/config/environment.rb +5 -0
  222. data/test/dummy/config/environments/development.rb +45 -0
  223. data/test/dummy/config/environments/production.rb +85 -0
  224. data/test/dummy/config/environments/test.rb +44 -0
  225. data/test/dummy/config/initializers/assets.rb +11 -0
  226. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  227. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  228. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  229. data/test/dummy/config/initializers/inflections.rb +16 -0
  230. data/test/dummy/config/initializers/mime_types.rb +4 -0
  231. data/test/dummy/config/initializers/session_store.rb +3 -0
  232. data/test/dummy/config/initializers/to_time_preserves_timezone.rb +10 -0
  233. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  234. data/test/dummy/config/locales/en.yml +23 -0
  235. data/test/dummy/config/routes.rb +6 -0
  236. data/test/dummy/config.ru +4 -0
  237. data/test/dummy/db/schema.rb +108 -0
  238. data/test/dummy/lib/assets/.keep +0 -0
  239. data/test/dummy/log/.keep +0 -0
  240. data/test/dummy/public/404.html +67 -0
  241. data/test/dummy/public/422.html +67 -0
  242. data/test/dummy/public/500.html +66 -0
  243. data/test/dummy/public/favicon.ico +0 -0
  244. data/test/extensions/action_controller_base_extensions_test.rb +21 -0
  245. data/test/extensions/action_mailer_base_extensions_test.rb +20 -0
  246. data/test/extensions/action_view_base_extensions_test.rb +267 -0
  247. data/test/extensions/active_record_extensions_test.rb +173 -0
  248. data/test/extensions/application_configuration_extensions_test.rb +46 -0
  249. data/test/extensions/application_extensions_test.rb +23 -0
  250. data/test/extensions/connection_adapter_extensions_test.rb +54 -0
  251. data/test/extensions/date_time_value_extensions_test.rb +104 -0
  252. data/test/extensions/date_value_extensions_test.rb +102 -0
  253. data/test/extensions/decimal_value_extensions_test.rb +85 -0
  254. data/test/extensions/erb_scaffold_generator_extensions_test.rb +17 -0
  255. data/test/extensions/float_value_extensions_test.rb +78 -0
  256. data/test/extensions/form_builder_extensions_test.rb +28 -0
  257. data/test/extensions/integer_value_extensions_test.rb +78 -0
  258. data/test/extensions/jbuilder_generator_extensions_test.rb +21 -0
  259. data/test/extensions/jbuilder_template_extensions_test.rb +47 -0
  260. data/test/extensions/main_app_extensions_test.rb +55 -0
  261. data/test/extensions/numeric_extensions_test.rb +76 -0
  262. data/test/extensions/object_extensions_test.rb +104 -0
  263. data/test/extensions/session_extensions_test.rb +69 -0
  264. data/test/extensions/string_extensions_test.rb +32 -0
  265. data/test/extensions/test_case_extensions_test.rb +538 -0
  266. data/test/extensions/time_zone_converter_extensions_test.rb +10 -0
  267. data/test/fixtures/incline/access_group_group_members.yml +1 -0
  268. data/test/fixtures/incline/access_group_user_members.yml +1 -0
  269. data/test/fixtures/incline/access_groups.yml +13 -0
  270. data/test/fixtures/incline/action_groups.yml +6 -0
  271. data/test/fixtures/incline/action_securities.yml +18 -0
  272. data/test/fixtures/incline/user_login_histories.yml +1 -0
  273. data/test/fixtures/incline/users.yml +64 -0
  274. data/test/incline_test.rb +63 -0
  275. data/test/integration/incline/users_edit_test.rb +180 -0
  276. data/test/integration/incline/users_login_test.rb +105 -0
  277. data/test/integration/incline/users_signup_test.rb +147 -0
  278. data/test/integration/navigation_test.rb +11 -0
  279. data/test/lib/data_tables_request_test.rb +245 -0
  280. data/test/lib/date_time_formats_test.rb +111 -0
  281. data/test/lib/global_status_test.rb +89 -0
  282. data/test/lib/json_log_formatter_test.rb +43 -0
  283. data/test/lib/log_test.rb +36 -0
  284. data/test/lib/recaptcha_test.rb +75 -0
  285. data/test/lib/user_manager_test.rb +47 -0
  286. data/test/lib/work_path_test.rb +18 -0
  287. data/test/models/incline/access_group_group_member_test.rb +30 -0
  288. data/test/models/incline/access_group_test.rb +60 -0
  289. data/test/models/incline/access_group_user_member_test.rb +29 -0
  290. data/test/models/incline/action_group_test.rb +27 -0
  291. data/test/models/incline/action_security_test.rb +176 -0
  292. data/test/models/incline/contact_message_test.rb +66 -0
  293. data/test/models/incline/disable_info_test.rb +29 -0
  294. data/test/models/incline/password_reset_request_test.rb +35 -0
  295. data/test/models/incline/password_reset_test.rb +51 -0
  296. data/test/models/incline/user_login_history_test.rb +31 -0
  297. data/test/models/incline/user_test.rb +91 -0
  298. data/test/test_helper.rb +42 -0
  299. data/test/validators/email_validator_test.rb +102 -0
  300. data/test/validators/ip_address_validator_test.rb +107 -0
  301. data/test/validators/recaptcha_validator_test.rb +57 -0
  302. data/test/validators/safe_name_validator_test.rb +101 -0
  303. metadata +584 -0
@@ -0,0 +1,617 @@
1
+ require 'cgi/util'
2
+ require 'action_view'
3
+
4
+ module Incline::Extensions
5
+ ##
6
+ # Adds additional helper methods to form builders.
7
+ module FormBuilder
8
+
9
+ ##
10
+ # Creates a date picker selection field using a bootstrap input group.
11
+ #
12
+ # *Valid options:*
13
+ #
14
+ # input_group_size::
15
+ # Valid optional sizes are 'small' or 'large'.
16
+ # readonly::
17
+ # Set to true to make the input field read only.
18
+ # pre_calendar::
19
+ # Set to true to put a calendar icon before the input field.
20
+ # post_calendar::
21
+ # Set to true to put a calendar icon after the input field. This is the default setting if no other pre/post
22
+ # is selected.
23
+ # pre_label::
24
+ # Set to a text value to put a label before the input field. Replaces +pre_calendar+ if specified.
25
+ # post_label::
26
+ # Set to a text value to put a label after the input field. Replaces +post_calendar+ if specified.
27
+ #
28
+ # f.date_picker :end_date, :pre_label => 'End'
29
+ #
30
+ def date_picker(method, options = {})
31
+ options = {
32
+ class: 'form-control',
33
+ read_only: false,
34
+ pre_calendar: false,
35
+ pre_label: nil,
36
+ post_calendar: false,
37
+ post_label: false,
38
+ attrib_val: { },
39
+ style: { },
40
+ input_group_size: ''
41
+ }.merge(options)
42
+
43
+ style = ''
44
+ options[:style].each { |k,v| style += "#{k}: #{v};" }
45
+
46
+ attrib = options[:attrib_val]
47
+ attrib[:class] = options[:class]
48
+ attrib[:style] = style
49
+ attrib[:readonly] = 'readonly' if options[:read_only]
50
+
51
+ if %w(sm small input-group-sm).include?(options[:input_group_size])
52
+ options[:input_group_size] = 'input-group-sm'
53
+ elsif %w(lg large input-group-lg).include?(options[:input_group_size])
54
+ options[:input_group_size] = 'input-group-lg'
55
+ else
56
+ options[:input_group_size] = ''
57
+ end
58
+
59
+ attrib[:value] = object.send(method).strftime('%m/%d/%Y') if object.send(method)
60
+ fld = text_field(method, attrib)
61
+
62
+ # must have at least one attachment, default to post-calendar.
63
+ options[:post_calendar] = true unless options[:pre_calendar] || options[:pre_label] || options[:post_label]
64
+
65
+ # labels override calendars.
66
+ options[:pre_calendar] = false if options[:pre_label]
67
+ options[:post_calendar] = false if options[:post_label]
68
+
69
+ # construct the prefix
70
+ if options[:pre_calendar]
71
+ pre = '<span class="input-group-addon"><i class="glyphicon glyphicon-calendar"></i></span>'
72
+ elsif options[:pre_label]
73
+ pre = "<span class=\"input-group-addon\">#{CGI::escape_html options[:pre_label]}</span>"
74
+ else
75
+ pre = ''
76
+ end
77
+
78
+ # construct the postfix
79
+ if options[:post_calendar]
80
+ post = '<span class="input-group-addon"><i class="glyphicon glyphicon-calendar"></i></span>'
81
+ elsif options[:post_label]
82
+ post = "<span class=\"input-group-addon\">#{CGI::escape_html options[:post_label]}</span>"
83
+ else
84
+ post = ''
85
+ end
86
+
87
+ # and then the return value.
88
+ "<div class=\"input-group date #{options[:input_group_size]}\">#{pre}#{fld}#{post}</div>".html_safe
89
+ end
90
+
91
+ ##
92
+ # Creates a multiple input field control for the provided form.
93
+ #
94
+ # The +methods+ parameter can be either an array of method names, or a hash with method names as the
95
+ # keys and labels as the values.
96
+ #
97
+ # For instance:
98
+ # [ :alpha, :bravo, :charlie ]
99
+ # { :alpha => 'The first item', :bravo => 'The second item', :charlie => 'The third item' }
100
+ #
101
+ # *Valid options:*
102
+ #
103
+ # class::
104
+ # The CSS class to apply. Defaults to 'form-control'.
105
+ #
106
+ # read_only::
107
+ # Should the control be read-only? Defaults to false.
108
+ #
109
+ # style::
110
+ # A hash containing CSS styling attributes to apply to the input fields.
111
+ # Width is generated automatically or specified individually using the "field_n" option.
112
+ #
113
+ # input_group_size::
114
+ # You can specific *small* or *large* to change the control's overall size.
115
+ #
116
+ # attrib::
117
+ # Any additional attributes you want to apply to the input fields.
118
+ #
119
+ # field_n::
120
+ # Sets specific attributes for field "n". These values will override the "attrib" and "style" options.
121
+ #
122
+ # f.multi_input [ :city, :state, :zip ],
123
+ # :field_1 => { :maxlength => 30, :style => { :width => '65%' } },
124
+ # :field_2 => { :maxlength => 2 },
125
+ # :field_3 => { :maxlength => 10, :style => { :width => '25%' } }
126
+ #
127
+ def multi_input(methods, options = {})
128
+ raise ArgumentError.new('methods must be either a Hash or an Array') unless methods.is_a?(::Hash) || methods.is_a?(::Array)
129
+ options = options.dup
130
+
131
+ # add some defaults.
132
+ options = {
133
+ class: 'form-control',
134
+ read_only: false,
135
+ attrib: { },
136
+ style: { },
137
+ input_group_size: ''
138
+ }.merge(options)
139
+
140
+ # build the style attribute.
141
+ options[:attrib][:style] ||= ''
142
+ options[:style].each do |k,v|
143
+ if k.to_s == 'width'
144
+ options[:input_group_width] = "width: #{v};"
145
+ else
146
+ options[:attrib][:style] += "#{k}: #{v};"
147
+ end
148
+ end
149
+
150
+ # Standardize the "methods" list to be an array of arrays.
151
+ if methods.is_a?(::Hash)
152
+ methods = methods.to_a
153
+ elsif methods.is_a?(::Array)
154
+ methods = methods.map{|v| v.is_a?(::Array) ? v : [ v, v.to_s.humanize ] }
155
+ end
156
+
157
+ # Extract field attributes.
158
+ fields = { }
159
+ index = 1
160
+ methods.each do |(meth,label)|
161
+ fields[meth] = options[:attrib].merge(options.delete(:"field_#{index}") || {})
162
+ fields[meth][:readonly] = 'readonly' if options[:read_only]
163
+ fields[meth][:class] ||= options[:class]
164
+ if fields[meth][:style].is_a?(::Hash)
165
+ fields[meth][:style] = fields[meth][:style].to_a.map{|v| v.map(&:to_s).join(':') + ';'}.join(' ')
166
+ end
167
+ fields[meth][:placeholder] ||= label
168
+ end
169
+
170
+ if %w(sm small input-group-sm).include?(options[:input_group_size])
171
+ options[:input_group_size] = 'input-group-sm'
172
+ elsif %w(lg large input-group-lg).include?(options[:input_group_size])
173
+ options[:input_group_size] = 'input-group-lg'
174
+ else
175
+ options[:input_group_size] = ''
176
+ end
177
+
178
+ # We want each field to have a width specified.
179
+ remaining_width = 100.0
180
+ remaining_fields = fields.count
181
+ width_match_1 = /^width:([^;]);/
182
+ width_match_2 = /;\s*width:([^;]);/
183
+
184
+ # pass 1, compute remaining width.
185
+ fields.each do |meth, attr|
186
+ width = width_match_1.match(attr[:style]) || width_match_2.match(attr[:style])
187
+ if width
188
+ if width[-1] == '%'
189
+ width = width[0...-1].strip.to_f
190
+ if width > remaining_width
191
+ Incline::Log::warn "Field width adds up to more than 100% in multi_input affecting field \"#{meth}\"."
192
+ width = remaining_width
193
+ attr[:style] = attr[:style].gsub(width_match_1, '').gsub(width_match_2, '') + "width: #{width}%;"
194
+ end
195
+ remaining_width -= width
196
+ remaining_width = 0 if remaining_width < 0
197
+ remaining_fields -= 1
198
+ else
199
+ # we do not support pixel, em, etc, so dump the unsupported width.
200
+ Incline::Log::warn "Unsupported width style in multi_input affecting field \"#{meth}\": #{width}"
201
+ attr[:style] = attr[:style].gsub(width_match_1, '').gsub(width_match_2, '')
202
+ end
203
+ end
204
+ end
205
+
206
+ # pass 2, fill in missing widths.
207
+ fields.each do |meth, attr|
208
+ width = width_match_1.match(attr[:style]) || width_match_2.match(attr[:style])
209
+ unless width
210
+ width =
211
+ if remaining_fields > 1
212
+ (remaining_width / remaining_fields).to_i
213
+ else
214
+ remaining_width
215
+ end
216
+
217
+ Incline::Log::warn "Computed field width of 0% in multi_input affecting field \"#{meth}\"." if width == 0
218
+
219
+ attr[:style] += "width: #{width}%;"
220
+ remaining_width -= width
221
+ remaining_fields -= 1
222
+ remaining_width = 0 if remaining_width < 0
223
+ end
224
+ end
225
+
226
+ fld = []
227
+ fields.each do |meth, attr|
228
+ attr[:value] = object.send(meth)
229
+ fld << text_field(meth, attr)
230
+ end
231
+
232
+ "<div class=\"input-group #{options[:input_group_size]}\" style=\"#{options[:input_group_width]}\">#{fld.join}</div>".html_safe
233
+ end
234
+
235
+ ##
236
+ # Creates a currency entry field.
237
+ #
238
+ # *Valid options:*
239
+ #
240
+ # currency_symbol::
241
+ # A string used to prefix the input field. Defaults to '$'.
242
+ #
243
+ # All other options will be passed through to the {FormHelper#text_field}[http://apidock.com/rails/ActionView/Helpers/FormHelper/text_field] method.
244
+ #
245
+ # The value will be formatted with comma delimiters and two decimal places.
246
+ #
247
+ # f.currency :pay_rate
248
+ #
249
+ def currency_field(method, options = {})
250
+ # get the symbol for the field.
251
+ sym = options.delete(:currency_symbol) || '$'
252
+
253
+ # get the value
254
+ if (val = object.send(method))
255
+ options[:value] = number_with_precision val, precision: 2, delimiter: ','
256
+ end
257
+
258
+ # build the field
259
+ fld = text_field(method, options)
260
+
261
+ # return the value.
262
+ "<div class=\"input-symbol\"><span>#{CGI::escape_html sym}</span>#{fld}</div>".html_safe
263
+ end
264
+
265
+ ##
266
+ # Creates a label followed by an optional small text description.
267
+ # For instance, <label>Hello</label> <small>(World)</small>
268
+ #
269
+ # Valid options:
270
+ #
271
+ # text::
272
+ # The text for the label. If not set, the method name is humanized and that value will be used.
273
+ #
274
+ # small_text::
275
+ # The small text to follow the label. If not set, then no small text will be included.
276
+ # This is useful for flagging fields as optional.
277
+ #
278
+ # For additional options, see {FormHelper#label}[http://apidock.com/rails/ActionView/Helpers/FormHelper/label].
279
+ def label_w_small(method, options = {})
280
+ text = options.delete(:text) || method.to_s.humanize
281
+ small_text = options.delete(:small_text)
282
+ label(method, text, options) +
283
+ (small_text ? " <small>(#{CGI::escape_html small_text})</small>" : '').html_safe
284
+ end
285
+
286
+ ##
287
+ # Creates a standard form group with a label and text field.
288
+ #
289
+ # The +options+ is a hash containing label, field, and group options.
290
+ # Prefix label options with +label_+ and field options with +field_+.
291
+ # All other options will apply to the group itself.
292
+ #
293
+ # Group options:
294
+ #
295
+ # class::
296
+ # The CSS class for the form group. Defaults to 'form-group'.
297
+ #
298
+ # style::
299
+ # Any styles to apply to the form group.
300
+ #
301
+ # For label options, see #label_w_small.
302
+ # For field options, see {FormHelper#text_field}[http://apidock.com/rails/ActionView/Helpers/FormHelper/text_field].
303
+ #
304
+ def text_form_group(method, options = {})
305
+ gopt, lopt, fopt = split_form_group_options(options)
306
+ lbl = label_w_small(method, lopt)
307
+ fld = gopt[:wrap].call(text_field(method, fopt))
308
+ form_group lbl, fld, gopt
309
+ end
310
+
311
+ ##
312
+ # Creates a standard form group with a label and password field.
313
+ #
314
+ # The +options+ is a hash containing label, field, and group options.
315
+ # Prefix label options with +label_+ and field options with +field_+.
316
+ # All other options will apply to the group itself.
317
+ #
318
+ # Group options:
319
+ #
320
+ # class::
321
+ # The CSS class for the form group. Defaults to 'form-group'.
322
+ #
323
+ # style::
324
+ # Any styles to apply to the form group.
325
+ #
326
+ # For label options, see #label_w_small.
327
+ # For field options, see {FormHelper#password_field}[http://apidock.com/rails/ActionView/Helpers/FormHelper/password_field].
328
+ #
329
+ def password_form_group(method, options = {})
330
+ gopt, lopt, fopt = split_form_group_options(options)
331
+ lbl = label_w_small(method, lopt)
332
+ fld = gopt[:wrap].call(password_field(method, fopt))
333
+ form_group lbl, fld, gopt
334
+ end
335
+
336
+
337
+ ##
338
+ # Creates a form group including a label and a text area.
339
+ #
340
+ # The +options+ is a hash containing label, field, and group options.
341
+ # Prefix label options with +label_+ and field options with +field_+.
342
+ # All other options will apply to the group itself.
343
+ #
344
+ # Group options:
345
+ #
346
+ # class::
347
+ # The CSS class for the form group. Defaults to 'form-group'.
348
+ #
349
+ # style::
350
+ # Any styles to apply to the form group.
351
+ #
352
+ # For label options, see #label_w_small.
353
+ # For field options, see {FormHelper#text_area}[http://apidock.com/rails/ActionView/Helpers/FormHelper/text_area].
354
+ def textarea_form_group(method, options = {})
355
+ gopt, lopt, fopt = split_form_group_options(options)
356
+ lbl = label_w_small method, lopt
357
+ fld = gopt[:wrap].call(text_area(method, fopt))
358
+ form_group lbl, fld, gopt
359
+ end
360
+
361
+ ##
362
+ # Creates a standard form group with a label and currency field.
363
+ #
364
+ # The +options+ is a hash containing label, field, and group options.
365
+ # Prefix label options with +label_+ and field options with +field_+.
366
+ # All other options will apply to the group itself.
367
+ #
368
+ # Group options:
369
+ #
370
+ # class::
371
+ # The CSS class for the form group. Defaults to 'form-group'.
372
+ #
373
+ # style::
374
+ # Any styles to apply to the form group.
375
+ #
376
+ # For label options, see #label_w_small.
377
+ # For field options, see #currency_field.
378
+ #
379
+ def currency_form_group(method, options = {})
380
+ gopt, lopt, fopt = split_form_group_options(options)
381
+ lbl = label_w_small(method, lopt)
382
+ fld = gopt[:wrap].call(currency_field(method, fopt))
383
+ form_group lbl, fld, gopt
384
+ end
385
+
386
+ ##
387
+ # Creates a standard form group with a label and a static text field.
388
+ #
389
+ # The +options+ is a hash containing label, field, and group options.
390
+ # Prefix label options with +label_+ and field options with +field_+.
391
+ # All other options will apply to the group itself.
392
+ #
393
+ # Group options:
394
+ #
395
+ # class::
396
+ # The CSS class for the form group. Defaults to 'form-group'.
397
+ #
398
+ # style::
399
+ # Any styles to apply to the form group.
400
+ #
401
+ # For label options, see #label_w_small.
402
+ #
403
+ # Field options:
404
+ #
405
+ # value::
406
+ # Allows you to specify a value for the static field, otherwise the value from +method+ will be used.
407
+ #
408
+ def static_form_group(method, options = {})
409
+ gopt, lopt, fopt = split_form_group_options(options)
410
+ lbl = label_w_small(method, lopt)
411
+ fld = gopt[:wrap].call("<input type=\"text\" class=\"form-control disabled\" readonly=\"readonly\" value=\"#{CGI::escape_html(fopt[:value] || object.send(method))}\">")
412
+ form_group lbl, fld, gopt
413
+ end
414
+
415
+ ##
416
+ # Creates a standard form group with a datepicker field.
417
+ #
418
+ # The +options+ is a hash containing label, field, and group options.
419
+ # Prefix label options with +label_+ and field options with +field_+.
420
+ # All other options will apply to the group itself.
421
+ #
422
+ # Group options:
423
+ #
424
+ # class::
425
+ # The CSS class for the form group. Defaults to 'form-group'.
426
+ #
427
+ # style::
428
+ # Any styles to apply to the form group.
429
+ #
430
+ # For label options, see #label_w_small.
431
+ # For field options, see #date_picker.
432
+ #
433
+ def datepicker_form_group(method, options = {})
434
+ gopt, lopt, fopt = split_form_group_options(options)
435
+ lbl = label_w_small(method, lopt)
436
+ fld = gopt[:wrap].call(date_picker(method, fopt))
437
+ form_group lbl, fld, gopt
438
+ end
439
+
440
+ ##
441
+ # Creates a standard form group with a multiple input control.
442
+ #
443
+ # The +options+ is a hash containing label, field, and group options.
444
+ # Prefix label options with +label_+ and field options with +field_+.
445
+ # All other options will apply to the group itself.
446
+ #
447
+ # Group options:
448
+ #
449
+ # class::
450
+ # The CSS class for the form group. Defaults to 'form-group'.
451
+ #
452
+ # style::
453
+ # Any styles to apply to the form group.
454
+ #
455
+ # For label options, see #label_w_small.
456
+ # For field options, see #multi_input_field.
457
+ #
458
+ def multi_input_form_group(methods, options = {})
459
+ gopt, lopt, fopt = split_form_group_options(options)
460
+ lopt[:text] ||= gopt[:label]
461
+ if lopt[:text].blank?
462
+ lopt[:text] = methods.map {|k,_| k.to_s.humanize }.join(', ')
463
+ end
464
+ lbl = label_w_small(methods.map{|k,_| k}.first, lopt)
465
+ fld = gopt[:wrap].call(multi_input(methods, fopt))
466
+ form_group lbl, fld, gopt
467
+ end
468
+
469
+ ##
470
+ # Creates a standard form group with a checkbox field.
471
+ #
472
+ # The +options+ is a hash containing label, field, and group options.
473
+ # Prefix label options with +label_+ and field options with +field_+.
474
+ # All other options will apply to the group itself.
475
+ #
476
+ # Group options:
477
+ #
478
+ # class::
479
+ # The CSS class for the form group.
480
+ #
481
+ # h_align::
482
+ # Create a checkbox aligned to a certain column (1-12) if set.
483
+ # If not set, then a regular form group is generated.
484
+ #
485
+ # For label options, see #label_w_small.
486
+ # For field options, see {FormHelper#check_box}[http://apidock.com/rails/ActionView/Helpers/FormHelper/check_box].
487
+ #
488
+ def check_box_form_group(method, options = {})
489
+ gopt, lopt, fopt = split_form_group_options({ class: 'checkbox', field_class: ''}.merge(options))
490
+
491
+ if gopt[:h_align]
492
+ gopt[:class] = gopt[:class].blank? ?
493
+ "col-sm-#{12-gopt[:h_align]} col-sm-offset-#{gopt[:h_align]}" :
494
+ "#{gopt[:class]} col-sm-#{12-gopt[:h_align]} col-sm-offset-#{gopt[:h_align]}"
495
+ end
496
+
497
+ lbl = label method do
498
+ check_box(method, fopt) +
499
+ CGI::escape_html(lopt[:text] || method.to_s.humanize) +
500
+ (lopt[:small_text] ? " <small>(#{CGI::escape_html lopt[:small_text]})</small>" : '').html_safe
501
+ end
502
+
503
+ "<div class=\"#{gopt[:h_align] ? 'row' : 'form-group'}\"><div class=\"#{gopt[:class]}\">#{lbl}</div></div>".html_safe
504
+ end
505
+
506
+ ##
507
+ # Creates a standard form group with a collection select field.
508
+ #
509
+ # The +collection+ should be an enumerable object (responds to 'each').
510
+ #
511
+ # The +value_method+ would be the method to call on the objects in the collection to get the value.
512
+ # This default to 'to_s' and is appropriate for any array of strings.
513
+ #
514
+ # The +text_method+ would be the method to call on the objects in the collection to get the display text.
515
+ # This defaults to 'to_s' as well, and should be appropriate for most objects.
516
+ #
517
+ # The +options+ is a hash containing label, field, and group options.
518
+ # Prefix label options with +label_+ and field options with +field_+.
519
+ # All other options will apply to the group itself.
520
+ #
521
+ # Group options:
522
+ #
523
+ # class::
524
+ # The CSS class for the form group. Defaults to 'form-group'.
525
+ #
526
+ # style::
527
+ # Any styles to apply to the form group.
528
+ #
529
+ # For label options, see #label_w_small.
530
+ # For field options, see {FormOptionsHelper#collection_select}[http://apidock.com/rails/ActionView/Helpers/FormOptionsHelper/collection_select].
531
+ #
532
+ def select_form_group(method, collection, value_method = :to_s, text_method = :to_s, options = {})
533
+ gopt, lopt, fopt = split_form_group_options({ field_include_blank: true }.merge(options))
534
+ lbl = label_w_small(method, lopt)
535
+ opt = {}
536
+ [:include_blank, :prompt, :include_hidden].each do |attr|
537
+ if fopt[attr] != nil
538
+ opt[attr] = fopt[attr]
539
+ fopt.except! attr
540
+ end
541
+ end
542
+ fld = gopt[:wrap].call(collection_select(method, collection, value_method, text_method, opt, fopt))
543
+ form_group lbl, fld, gopt
544
+ end
545
+
546
+ ##
547
+ # Adds a recaptcha challenge to the form configured to set the specified attribute to the recaptcha response.
548
+ #
549
+ # Valid options:
550
+ # theme::
551
+ # Can be :dark or :light, defaults to :light.
552
+ # type::
553
+ # Can be :image or :audio, defaults to :image.
554
+ # size::
555
+ # Can be :compact or :normal, defaults to :normal.
556
+ # tab_index::
557
+ # Can be any valid integer if you want a specific tab order, defaults to 0.
558
+ #
559
+ def recaptcha(method, options = {})
560
+ Incline::Recaptcha::Tag.new(@object_name, method, @template, options).render
561
+ end
562
+
563
+
564
+ private
565
+
566
+ def form_group(lbl, fld, opt)
567
+ ret = '<div'
568
+ ret += " class=\"#{CGI::escape_html opt[:class]}" unless opt[:class].blank?
569
+ ret += '"'
570
+ ret += " style=\"#{CGI::escape_html opt[:style]}\"" unless opt[:style].blank?
571
+ ret += ">#{lbl}#{fld}</div>"
572
+ ret.html_safe
573
+ end
574
+
575
+ def split_form_group_options(options)
576
+ options = {class: 'form-group', field_class: 'form-control'}.merge(options || {})
577
+ group = {}
578
+ label = {}
579
+ field = {}
580
+
581
+ options.keys.each do |k|
582
+ sk = k.to_s
583
+ if sk.index('label_') == 0
584
+ label[sk[6..-1].to_sym] = options[k]
585
+ elsif sk.index('field_') == 0
586
+ field[sk[6..-1].to_sym] = options[k]
587
+ else
588
+ group[k.to_sym] = options[k]
589
+ end
590
+ end
591
+
592
+ group[:wrap] = Proc.new do |fld|
593
+ fld
594
+ end
595
+ if group[:h_align]
596
+ if group[:h_align].is_a?(::TrueClass)
597
+ l = 3
598
+ else
599
+ l = group[:h_align].to_i
600
+ end
601
+ l = 1 if l < 1
602
+ l = 6 if l > 6
603
+ f = 12 - l
604
+ group[:h_align] = l
605
+ label[:class] = label[:class].blank? ? "col-sm-#{l} control-label" : "#{label[:class]} col-sm-#{l} control-label"
606
+ group[:wrap] = Proc.new do |fld|
607
+ "<div class=\"col-sm-#{f}\">#{fld}</div>"
608
+ end
609
+ end
610
+
611
+ [group, label, field]
612
+ end
613
+
614
+ end
615
+ end
616
+
617
+ ActionView::Helpers::FormBuilder.include Incline::Extensions::FormBuilder
@@ -0,0 +1,54 @@
1
+ require 'incline/number_formats'
2
+ require 'active_record'
3
+
4
+ module Incline::Extensions
5
+ ##
6
+ # Patches the ActiveRecord Integer type to be able to accept more numbers.
7
+ #
8
+ # Specifically this will allow comma delimited numbers to be provided to active record models.
9
+ module IntegerValue
10
+
11
+ ##
12
+ # Patches the ActiveRecord Integer type.
13
+ def self.included(base) #:nodoc:
14
+ base.class_eval do
15
+
16
+ private
17
+
18
+ undef cast_value
19
+
20
+ def cast_value(value)
21
+ begin
22
+ case value
23
+ when true then 1
24
+ when false then 0
25
+ when ::String
26
+ # 1,234.56789
27
+ if value =~ Incline::NumberFormats::WITH_DELIMITERS
28
+ value = value.gsub(',', '')
29
+ end
30
+ if value =~ Incline::NumberFormats::WITHOUT_DELIMITERS
31
+ value.to_i
32
+ else
33
+ nil
34
+ end
35
+ else
36
+ if value.respond_to?(:to_i)
37
+ value.to_i
38
+ else
39
+ nil
40
+ end
41
+ end
42
+ rescue
43
+ Incline::Log::warn "Failed to parse #{value.inspect}: #{$!.message}"
44
+ nil
45
+ end
46
+ end
47
+
48
+ end
49
+ end
50
+
51
+ end
52
+ end
53
+
54
+ ActiveRecord::Type::Integer.include Incline::Extensions::IntegerValue
@@ -0,0 +1,38 @@
1
+ require 'rails/generators'
2
+ require 'generators/rails/jbuilder_generator'
3
+
4
+ module Incline::Extensions
5
+ ##
6
+ # Adds _details view to jbuilder.
7
+ module JbuilderGenerator
8
+
9
+ ##
10
+ # Overrides the copy_view_files method to include the _details view.
11
+ def self.included(base)
12
+ base.class_eval do
13
+
14
+ source_root File.expand_path('../../../templates/jbuilder/scaffold', __FILE__)
15
+
16
+ undef copy_view_files
17
+
18
+ def copy_view_files
19
+ available_views.each do |view|
20
+ filename = filename_with_extensions(view)
21
+ template filename, File.join('app/views', controller_file_path, filename)
22
+ end
23
+ end
24
+
25
+ protected
26
+
27
+ def available_views
28
+ %w(index show _details)
29
+ end
30
+
31
+ end
32
+ end
33
+
34
+ end
35
+ end
36
+
37
+ Rails::Generators::JbuilderGenerator.include Incline::Extensions::JbuilderGenerator
38
+