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,10 @@
1
+
2
+ function escapeHTML(unsafe)
3
+ {
4
+ return unsafe
5
+ .replace(/&/g,'&')
6
+ .replace(/</g, '&lt;')
7
+ .replace(/>/g, '&gt;')
8
+ .replace(/"/g, '&quot;')
9
+ .replace(/'/g, '&#039;');
10
+ }
@@ -0,0 +1,479 @@
1
+ // Data Tables Helper Methods
2
+ // (C) 2017 Beau Barker (beau@barkerest.com)
3
+
4
+ /*
5
+ * JSON format:
6
+ * {
7
+ * // (optional) set to true to indicate an invalid request to the server, default is false.
8
+ * "invalidRequest": false,
9
+ * // (optional) an array of messages to display to the user.
10
+ * "messages": [
11
+ * {
12
+ * // (required) "info", "warning", "danger", "success"
13
+ * "type": "info",
14
+ * // (required) the message to display.
15
+ * "text": "The action was successful."
16
+ * }
17
+ * ],
18
+ * // (optional) an array of data to update the data table with.
19
+ * "data": [
20
+ * {
21
+ * // (required) the unique ID for this row.
22
+ * "DT_RowId": "my_model_1",
23
+ * // (required) the "show" path for the model.
24
+ * "DT_Path": "/incline/my_model/1",
25
+ * // (optional) "update" or "remove", default is "update".
26
+ * "DT_RowAction": "update",
27
+ * // (optional) "info", "warning", "danger", "success"
28
+ * "DT_RowClass": "info",
29
+ *
30
+ * // then model details such as:
31
+ * "name": "John Doe",
32
+ * "age": 35,
33
+ * "email": "jdoe@example.com",
34
+ * "occupation": "Mechanic"
35
+ * }
36
+ * ]
37
+ * }
38
+ */
39
+
40
+
41
+ var inclineInline = {
42
+ action: function(path, method) {
43
+ if (!(method)) method = 'get';
44
+ if (path.indexOf('?') >= 0) {
45
+ path += '&inline=1';
46
+ } else {
47
+ path += '?inline=1';
48
+ }
49
+ $.ajax({
50
+ method: method.toUpperCase(),
51
+ url: path,
52
+ dataType: 'json',
53
+ success: function (data, status, xhr) {
54
+ inclineInline._handle_json_result(data);
55
+ },
56
+ error: function (xhr, status, error) {
57
+ inclineInline._handle_error(status, error);
58
+ }
59
+ });
60
+ },
61
+
62
+ form: function(req_path, req_method) {
63
+ if (!(req_method)) req_method = 'get';
64
+ if (req_path.indexOf('?') >= 0) {
65
+ req_path += '&inline=1';
66
+ } else {
67
+ req_path += '?inline=1';
68
+ }
69
+
70
+ // first request should return HTML.
71
+ $.ajax({
72
+ method: req_method.toUpperCase(),
73
+ url: req_path,
74
+ dataType: 'html',
75
+ success: function (data, status, xhr) {
76
+ inclineInline._handle_form_response(data, status, xhr);
77
+ },
78
+ error: function (xhr, status, error) {
79
+ inclineInline._handle_error(status, error);
80
+ }
81
+ });
82
+ },
83
+
84
+ _handle_json_result: function(data) {
85
+ var ts = Math.round((new Date().getTime() / 100) % 864000, 0);
86
+ var i;
87
+ if (data.invalidRequest) {
88
+ // Should probably come up with a more informative alert.
89
+ this._handle_error('invalid request', 'invalid request');
90
+ } else {
91
+ // build alerts that clear after 5 seconds.
92
+ if (data.messages) {
93
+ var messageCount = data.messages.length;
94
+ var alertDiv = $('#incline_dynamic_alerts');
95
+ for (i = 0; i < messageCount; i++) {
96
+ var message = data.messages[i];
97
+ var html = '<div id="alert-' + ts.toString() + '" class="alert alert-' + escapeHTML(message.type) + ' alert-dismissible fade in" role="alert">' +
98
+ '<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>' +
99
+ escapeHTML(message.text) +
100
+ '</div>';
101
+ var close = '$(\'#alert-' + ts.toString() + '\').alert(\'close\');';
102
+ alertDiv.prepend(html);
103
+ window.setTimeout(close, 5000);
104
+ ts++;
105
+ }
106
+ }
107
+ // update rows in the data table.
108
+ if (data.data) {
109
+ var dataCount = data.data.length;
110
+ for (i = 0; i < dataCount; i++) {
111
+ var item = data.data[i];
112
+ var row = $('#' + item.DT_RowId);
113
+ if (row.length > 0) {
114
+ var table = row.parents('table');
115
+ if ($.fn.dataTable.isDataTable(table))
116
+ {
117
+ var table_id = table.attr('id');
118
+ table = table.dataTable().api();
119
+ if (item.DT_RowAction === 'remove') {
120
+ table.row('#' + item.DT_RowId).remove(); // remove the row from the DT.
121
+ table.draw('page'); // refresh the current page.
122
+ } else {
123
+ table.row('#' + item.DT_RowId).data(item); // refresh the row in the DT.
124
+ inclineInline._go_to_record(item); // find and hilight the record.
125
+ }
126
+ }
127
+ } else if (dataCount == 1) {
128
+ // no row found and there is only one record returned, focus on that record.
129
+ inclineInline._go_to_record(item);
130
+ }
131
+ }
132
+ }
133
+ }
134
+ },
135
+
136
+ _handle_form_response: function (data, status, xhr) {
137
+ var type = xhr.getResponseHeader('Content-Type').toLowerCase().trim();
138
+ if (type.indexOf(';') >= 0)
139
+ type = type.substring(0, type.indexOf(';')).trim();
140
+
141
+ if (type === 'application/json') {
142
+ // json response
143
+ this._destroy_dialog();
144
+ this._handle_json_result(data);
145
+ } else if (type === 'text/html') {
146
+ // html response
147
+ this._set_dialog(data);
148
+ } else {
149
+ // unsupported response
150
+ this._destroy_dialog();
151
+ this._handle_error('invalid response', 'invalid response');
152
+ }
153
+ },
154
+
155
+ _handle_error: function (status, error) {
156
+ this._destroy_dialog(); // no matter what, the dialog should be destroyed.
157
+
158
+ // Should probably come up with more informative error alerts.
159
+ if (status === 'error') {
160
+ alert(error);
161
+ } else {
162
+ alert(status);
163
+ }
164
+ },
165
+
166
+ _dialog: false,
167
+
168
+ _create_dialog: function () {
169
+ if (!(this._dialog))
170
+ {
171
+ var body = $('body');
172
+ var modal = $('<div class="modal fade" id="incline_inline_form" tabindex="-1" role="dialog" aria-labelledby="incline_inline_form_title" style="display: none;">' +
173
+ '<div class="modal-dialog" role="document">' +
174
+ '<div class="modal-content">' +
175
+ '<div class="modal-header">' +
176
+ '<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>' +
177
+ '<h4 class="modal-title" id="incline_inline_form_title"></h4>' +
178
+ '</div>' +
179
+ '<div class="modal-body" id="incline_inline_form_body"></div>' +
180
+ '<div class="modal-footer" id="incline_inline_form_footer"></div>' +
181
+ '</div></div></div>');
182
+
183
+ body.prepend(modal);
184
+ modal = $('#incline_inline_form');
185
+ modal.on('hidden.bs.modal', function (e) {
186
+ modal.remove();
187
+ inclineInline._dialog = false;
188
+ });
189
+ this._dialog = true;
190
+ }
191
+ },
192
+
193
+ _set_dialog: function (html) {
194
+ var title;
195
+ var body;
196
+ var footer;
197
+ var tmp;
198
+ var dup;
199
+ var panel;
200
+ var panel_parent;
201
+ var align_regex = /^(.*\s)?(row(\s.*)?|col-(xs|sm|md|lg)-.*)$/;
202
+ var panel_regex = /^(.*\s)?panel(\s.*)?$/;
203
+
204
+ // add html to DOM under a hidden div for processing.
205
+ tmp = $('<div></div>').css('display','none');
206
+ $('body').append(tmp);
207
+ tmp.html(html);
208
+ html = tmp;
209
+
210
+ this._create_dialog();
211
+
212
+ // get the parts of the modal to update.
213
+ title = $('#incline_inline_form_title');
214
+ body = $('#incline_inline_form_body');
215
+ footer = $('#incline_inline_form_footer');
216
+
217
+ // reset
218
+ title.text('');
219
+ body.empty();
220
+ footer.empty();
221
+
222
+ tmp = html.find('form');
223
+ if (tmp.length == 1) { // support one and only one form in the resulting HTML.
224
+ // we have a form in the html that needs to be modified accordingly.
225
+ var form_method = tmp.attr('method');
226
+ var form_url = tmp.attr('action');
227
+ var form_id = tmp.attr('id');
228
+
229
+ // make sure the inline parameter is set.
230
+ tmp.append('<input type="hidden" name="inline" value="1" />');
231
+
232
+ // override submit to make sure the submission occurs via ajax.
233
+ tmp.submit(function (e) {
234
+ var form_data = $('#' + form_id).serialize();
235
+ e.preventDefault();
236
+
237
+ // prevent double submission.
238
+ tmp.find('input,button,select,textarea').prop('disabled', true);
239
+
240
+ $.ajax({
241
+ type: form_method.toUpperCase(),
242
+ url: form_url,
243
+ data: form_data,
244
+ success: function(data, status, xhr) {
245
+ inclineInline._handle_form_response(data, status, xhr);
246
+ },
247
+ error: function(xhr, status, error) {
248
+ inclineInline._handle_error(status, error);
249
+ }
250
+ });
251
+ });
252
+ }
253
+
254
+ // cancel links and buttons
255
+ tmp = html.find('a,button,input[type=button]').filter(function() { return $(this).text().toLowerCase() === 'cancel'; });
256
+ if (tmp.length > 0) {
257
+ tmp.click(function (e) {
258
+ e.preventDefault();
259
+ inclineInline._destroy_dialog();
260
+ });
261
+ }
262
+
263
+ // global title recognition, first H1 or H2 element.
264
+ tmp = html.find('h1');
265
+ if (tmp.length < 1) tmp = html.find('h2');
266
+ if (tmp.length > 0) {
267
+ tmp = tmp.first();
268
+ title.text(tmp.text());
269
+ // only remove if there is no additional HTML markup.
270
+ if (tmp.html() === tmp.text())
271
+ {
272
+ tmp.remove();
273
+ }
274
+ }
275
+
276
+ // put the error messages in place.
277
+ tmp = html.find('#error_explanation');
278
+ if (tmp.length > 0) {
279
+ tmp.detach();
280
+ body.prepend(tmp);
281
+ }
282
+
283
+ // put the alert messages in place.
284
+ tmp = html.find('.alert');
285
+ if (tmp.length > 0) {
286
+ tmp.detach();
287
+ body.prepend(tmp);
288
+ }
289
+
290
+ // remove outside alignment DIVs.
291
+ while ((tmp = html.children()) && tmp.length == 1 && align_regex.test(tmp.attr('class'))) {
292
+ tmp.detach();
293
+ html.append(tmp.children());
294
+ }
295
+
296
+ // If the html has one child and that child is a form, then look inside the form.
297
+ panel_parent = html;
298
+ panel = panel_parent.children();
299
+ if (panel.length == 1 && panel[0].tagName.toUpperCase() === 'FORM') {
300
+ panel_parent = panel;
301
+ panel = panel_parent.children(':not(input[type=hidden])'); // ignore hidden inputs
302
+ }
303
+
304
+ // now if there is only one child and that child is a panel, we can rip it apart.
305
+ if (panel.length == 1 && panel[0].tagName.toUpperCase() === 'DIV' && panel_regex.test(panel.attr('class'))) {
306
+ panel.detach();
307
+
308
+ if ((tmp = panel.children('.panel-heading')) && tmp.length > 0) {
309
+ title.text(tmp.text());
310
+ }
311
+
312
+ tmp = panel.children('table,.panel-body');
313
+ if (tmp.length > 0) {
314
+ tmp.removeClass('panel-body');
315
+ tmp.detach();
316
+ panel_parent.append(tmp);
317
+ }
318
+
319
+ tmp = panel.children('.panel-footer');
320
+ if (tmp.length > 0) {
321
+ tmp.removeClass('panel-footer');
322
+ tmp.detach();
323
+ // now we have a conundrum.
324
+ if (panel_parent[0].tagName.toUpperCase() === 'FORM') {
325
+ // since the footer might contain controls for the form, we need it to be in the form.
326
+ panel_parent.append(tmp);
327
+ } else {
328
+ // or the form doesn't wrap the footer, so we can just use the footer.
329
+ footer.append(tmp.children());
330
+ }
331
+ }
332
+ }
333
+
334
+ // we are done modifying the HTML and we can add it.
335
+ html.detach();
336
+ body.append(html.contents());
337
+
338
+ // footer should only be visible if it has contents.
339
+ if (footer.children().length > 0 || footer.text() !== '') {
340
+ footer.show();
341
+ } else {
342
+ footer.hide();
343
+ }
344
+
345
+ // make sure the dialog is visible.
346
+ tmp = $('#incline_inline_form');
347
+ if (tmp.is(':hidden')) {
348
+ tmp.modal('show');
349
+ tmp.on('shown.bs.modal', function () {
350
+ activateClassedItems(tmp);
351
+ });
352
+ } else {
353
+ // make sure the classed items are activated.
354
+ activateClassedItems(tmp);
355
+ }
356
+ },
357
+
358
+ _destroy_dialog: function () {
359
+ if (this._dialog) {
360
+ var dlg = $('#incline_inline_form');
361
+ if (dlg.length > 0) {
362
+ if (dlg.is(':hidden')) {
363
+ dlg.remove();
364
+ } else {
365
+ dlg.modal('hide');
366
+ }
367
+ }
368
+ this._dialog = false;
369
+ }
370
+ },
371
+
372
+ _go_to_record: function (data) {
373
+ var table = $('table.dataTable');
374
+ var params;
375
+ var i;
376
+ var row_id = '#' + data.DT_RowId;
377
+
378
+ if (table.length < 1) return;
379
+
380
+ table = table.dataTable().api();
381
+
382
+ i = data.DT_RowId.lastIndexOf('_');
383
+
384
+ params = table.ajax.params();
385
+ params.draw = -1;
386
+ params.locate_id = data.DT_RowId.substring(i + 1);
387
+
388
+ $.ajax({
389
+ url: data.DT_Path + '/locate',
390
+ method: 'POST',
391
+ dataType: 'json',
392
+ data: params,
393
+ success: function(data) {
394
+ var recNum = data.record;
395
+ if (recNum > -1) {
396
+ var pageLen = table.page.len();
397
+ var pageNum;
398
+
399
+ if (pageLen < 1) return;
400
+
401
+ // avoid division by zero.
402
+ if (recNum === 0) {
403
+ pageNum = 0;
404
+ } else {
405
+ pageNum = Math.floor(recNum / pageLen);
406
+ }
407
+
408
+ // set the page number and refresh the datatable only if we are on a different page or the row isn't visible.
409
+ if (table.page() != pageNum || $(row_id).length < 1) {
410
+ table.page(pageNum).draw('page');
411
+ }
412
+
413
+ // hilite the row (give DOM a quick chance to update).
414
+ window.setTimeout(function() { inclineInline._hilite_fade(row_id); }, 250 );
415
+ }
416
+ }
417
+ });
418
+
419
+ },
420
+
421
+ _hilite_fade: function (selector) {
422
+ // 2s hilite pulse from any bg color to yellow and then back.
423
+ $(selector).addClass('cell-fade').addClass('cell-hilite');
424
+ window.setTimeout(function() {
425
+ $(selector).removeClass('cell-hilite');
426
+ window.setTimeout(function() {
427
+ $(selector).removeClass('cell-fade');
428
+ }, 1000);
429
+ }, 1000);
430
+ },
431
+ };
432
+
433
+ /*
434
+ * Generates an AJAX request to load an HTML fragment from the server.
435
+ * When the HTML fragment is returned, it is displayed in a modal dialog over the current page.
436
+ * If a form is present in the returned HTML, the 'submit' event is hooked to submit inline via AJAX.
437
+ * If the form submission returns HTML, the returned HTML overwrites the previous HTML.
438
+ * If the form submission returns JSON, the JSON is is used to update the page.
439
+ */
440
+ function inlineForm(req_path,req_method) {
441
+ inclineInline.form(req_path, req_method);
442
+ }
443
+
444
+ /*
445
+ * Generates an AJAX request to the server and expects a JSON result.
446
+ * The JSON is used to update the page.
447
+ */
448
+ function inlineAction(path, method) {
449
+ inclineInline.action(path, method);
450
+ }
451
+
452
+ (function ($){
453
+ // inlineAction should return JSON data.
454
+ // If "invalidRequest" is set in the response then an alert is generated.
455
+ // Otherwise, if "messages" are set in the response then we display them.
456
+ $.fn.inlineAction = function () {
457
+ var item = $(this);
458
+ var path = item.attr('href');
459
+ var method = item.attr('data-method');
460
+ if (!(method)) method = 'get';
461
+
462
+ item.click(function (e) {
463
+ e.preventDefault();
464
+ inclineInline.action(path, method);
465
+ });
466
+ };
467
+ $.fn.inlineForm = function () {
468
+ var item =$(this);
469
+ var path = item.attr('href');
470
+ var method = item.attr('data-method');
471
+ if (!(method)) method = 'get';
472
+
473
+ item.click(function (e) {
474
+ e.preventDefault();
475
+ inclineInline.form(path, method);
476
+ });
477
+ };
478
+ })(jQuery);
479
+
@@ -0,0 +1,112 @@
1
+ /*
2
+ * @name DoubleScroll
3
+ * @desc displays scroll bar on top and on the bottom of the div
4
+ * @requires jQuery
5
+ *
6
+ * @author Pawel Suwala - http://suwala.eu/
7
+ * @author Antoine Vianey - http://www.astek.fr/
8
+ * @version 0.4 (18-06-2014)
9
+ *
10
+ * Dual licensed under the MIT and GPL licenses:
11
+ * http://www.opensource.org/licenses/mit-license.php
12
+ * http://www.gnu.org/licenses/gpl.html
13
+ *
14
+ * Usage:
15
+ * https://github.com/avianey/jqDoubleScroll
16
+ */
17
+
18
+ jQuery.fn.doubleScroll = function(userOptions) {
19
+ var $ = jQuery;
20
+ // Default options
21
+ var options = {
22
+ contentElement: undefined, // Widest element, if not specified first child element will be used
23
+ scrollCss: {
24
+ 'overflow-x': 'auto',
25
+ 'overflow-y': 'hidden'
26
+ },
27
+ contentCss: {
28
+ 'overflow-x': 'auto',
29
+ 'overflow-y': 'hidden'
30
+ },
31
+ onlyIfScroll: true, // top scrollbar is not shown if the bottom one is not present
32
+ resetOnWindowResize: false, // recompute the top ScrollBar requirements when the window is resized
33
+ timeToWaitForResize: 30 // wait for the last update event (usefull when browser fire resize event constantly during ressing)
34
+ };
35
+ $.extend(true, options, userOptions);
36
+ // do not modify
37
+ // internal stuff
38
+ $.extend(options, {
39
+ topScrollBarMarkup: '<div class="doubleScroll-scroll-wrapper" style="height: 20px;"><div class="doubleScroll-scroll" style="height: 20px;"></div></div>',
40
+ topScrollBarWrapperSelector: '.doubleScroll-scroll-wrapper',
41
+ topScrollBarInnerSelector: '.doubleScroll-scroll'
42
+ });
43
+
44
+ var _showScrollBar = function($self, options) {
45
+
46
+ if (options.onlyIfScroll && $self.get(0).scrollWidth <= $self.width()) {
47
+ // content doesn't scroll
48
+ // remove any existing occurrence...
49
+ $self.prev(options.topScrollBarWrapperSelector).remove();
50
+ return;
51
+ }
52
+
53
+ // add div that will act as an upper scroll only if not already added to the DOM
54
+ var $topScrollBar = $self.prev(options.topScrollBarWrapperSelector);
55
+ if ($topScrollBar.length == 0) {
56
+
57
+ // creating the scrollbar
58
+ // added before in the DOM
59
+ $topScrollBar = $(options.topScrollBarMarkup);
60
+ $self.before($topScrollBar);
61
+
62
+ // apply the css
63
+ $topScrollBar.css(options.scrollCss);
64
+ $self.css(options.contentCss);
65
+
66
+ // bind upper scroll to bottom scroll
67
+ $topScrollBar.bind('scroll.doubleScroll', function() {
68
+ $self.scrollLeft($topScrollBar.scrollLeft());
69
+ });
70
+
71
+ // bind bottom scroll to upper scroll
72
+ var selfScrollHandler = function() {
73
+ $topScrollBar.scrollLeft($self.scrollLeft());
74
+ };
75
+ $self.bind('scroll.doubleScroll', selfScrollHandler);
76
+ }
77
+
78
+ // find the content element (should be the widest one)
79
+ var $contentElement;
80
+ if (options.contentElement !== undefined && $self.find(options.contentElement).length !== 0) {
81
+ $contentElement = $self.find(options.contentElement);
82
+ } else {
83
+ $contentElement = $self.find('>:first-child');
84
+ }
85
+
86
+ // set the width of the wrappers
87
+ $(options.topScrollBarInnerSelector, $topScrollBar).width($contentElement.outerWidth());
88
+ $topScrollBar.width($self.width());
89
+ $topScrollBar.scrollLeft($self.scrollLeft());
90
+
91
+ };
92
+
93
+ return this.each(function() {
94
+ var $self = $(this);
95
+ _showScrollBar($self, options);
96
+
97
+ // bind the resize handler
98
+ // do it once
99
+ if (options.resetOnWindowResize) {
100
+ var id;
101
+ var handler = function(e) {
102
+ _showScrollBar($self, options);
103
+ };
104
+ $(window).bind('resize.doubleScroll', function() {
105
+ // adding/removing/replacing the scrollbar might resize the window
106
+ // so the resizing flag will avoid the infinite loop here...
107
+ clearTimeout(id);
108
+ id = setTimeout(handler, options.timeToWaitForResize);
109
+ });
110
+ }
111
+ });
112
+ };