fae-railsz 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (328) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +5 -0
  3. data/Rakefile +37 -0
  4. data/app/assets/fonts/fae/icons.eot +0 -0
  5. data/app/assets/fonts/fae/icons.svg +56 -0
  6. data/app/assets/fonts/fae/icons.ttf +0 -0
  7. data/app/assets/fonts/fae/icons.woff +0 -0
  8. data/app/assets/fonts/fae/lato-bold-webfont.eot +0 -0
  9. data/app/assets/fonts/fae/lato-bold-webfont.svg +4551 -0
  10. data/app/assets/fonts/fae/lato-bold-webfont.ttf +0 -0
  11. data/app/assets/fonts/fae/lato-bold-webfont.woff +0 -0
  12. data/app/assets/fonts/fae/lato-light-webfont.eot +0 -0
  13. data/app/assets/fonts/fae/lato-light-webfont.svg +4241 -0
  14. data/app/assets/fonts/fae/lato-light-webfont.ttf +0 -0
  15. data/app/assets/fonts/fae/lato-light-webfont.woff +0 -0
  16. data/app/assets/fonts/fae/lato-regular-webfont.eot +0 -0
  17. data/app/assets/fonts/fae/lato-regular-webfont.svg +4241 -0
  18. data/app/assets/fonts/fae/lato-regular-webfont.ttf +0 -0
  19. data/app/assets/fonts/fae/lato-regular-webfont.woff +0 -0
  20. data/app/assets/fonts/fae/selection.json +1334 -0
  21. data/app/assets/images/fae/error_bg.jpg +0 -0
  22. data/app/assets/images/fae/error_sad_face.png +0 -0
  23. data/app/assets/images/fae/icons/alert.svg +9 -0
  24. data/app/assets/images/fae/icons/arrow_down.svg +8 -0
  25. data/app/assets/images/fae/icons/arrow_left.svg +9 -0
  26. data/app/assets/images/fae/icons/arrow_right.svg +9 -0
  27. data/app/assets/images/fae/icons/arrow_stacked.svg +8 -0
  28. data/app/assets/images/fae/icons/arrow_up.svg +8 -0
  29. data/app/assets/images/fae/icons/calendar.svg +17 -0
  30. data/app/assets/images/fae/icons/check.svg +7 -0
  31. data/app/assets/images/fae/icons/checkmark.svg +8 -0
  32. data/app/assets/images/fae/icons/chevron_down.svg +7 -0
  33. data/app/assets/images/fae/icons/chevron_left.svg +10 -0
  34. data/app/assets/images/fae/icons/chevron_right.svg +10 -0
  35. data/app/assets/images/fae/icons/chevron_up.svg +7 -0
  36. data/app/assets/images/fae/icons/delete.svg +8 -0
  37. data/app/assets/images/fae/icons/delete_x.svg +8 -0
  38. data/app/assets/images/fae/icons/edit.svg +11 -0
  39. data/app/assets/images/fae/icons/handle.svg +13 -0
  40. data/app/assets/images/fae/icons/home.svg +10 -0
  41. data/app/assets/images/fae/icons/logout.svg +12 -0
  42. data/app/assets/images/fae/icons/magnifying_glass.svg +10 -0
  43. data/app/assets/images/fae/icons/menu.svg +11 -0
  44. data/app/assets/images/fae/icons/offlink.svg +25 -0
  45. data/app/assets/images/fae/icons/plus.svg +8 -0
  46. data/app/assets/images/fae/icons/pulldown.svg +11 -0
  47. data/app/assets/images/fae/icons/search.svg +11 -0
  48. data/app/assets/images/fae/icons/settings.svg +12 -0
  49. data/app/assets/images/fae/icons/sort.svg +11 -0
  50. data/app/assets/images/fae/icons/support.svg +15 -0
  51. data/app/assets/images/fae/icons/trash.svg +10 -0
  52. data/app/assets/images/fae/icons/trumbowyg.svg +1 -0
  53. data/app/assets/images/fae/icons/user.svg +13 -0
  54. data/app/assets/images/fae/icons/users.svg +19 -0
  55. data/app/assets/images/fae/icons/zoom.svg +12 -0
  56. data/app/assets/images/fae/tutorial_model_location.png +0 -0
  57. data/app/assets/images/fae/youtube_helper.jpg +0 -0
  58. data/app/assets/javascripts/fae/_modals.js +60 -0
  59. data/app/assets/javascripts/fae/_tables.js +403 -0
  60. data/app/assets/javascripts/fae/admin.js.erb +11 -0
  61. data/app/assets/javascripts/fae/application.js +63 -0
  62. data/app/assets/javascripts/fae/fae_init.js +8 -0
  63. data/app/assets/javascripts/fae/form/_ajax.js +380 -0
  64. data/app/assets/javascripts/fae/form/_cancel.js +38 -0
  65. data/app/assets/javascripts/fae/form/_filtering.js +276 -0
  66. data/app/assets/javascripts/fae/form/_form.js +60 -0
  67. data/app/assets/javascripts/fae/form/_slugger.js.erb +100 -0
  68. data/app/assets/javascripts/fae/form/_validator.js +459 -0
  69. data/app/assets/javascripts/fae/form/fae_chosen.js +44 -0
  70. data/app/assets/javascripts/fae/form/fileinputer.js +178 -0
  71. data/app/assets/javascripts/fae/form/hinter.js +111 -0
  72. data/app/assets/javascripts/fae/form/inputs/_checkbox.js +27 -0
  73. data/app/assets/javascripts/fae/form/inputs/_color.js +42 -0
  74. data/app/assets/javascripts/fae/form/inputs/_dates.js +78 -0
  75. data/app/assets/javascripts/fae/form/inputs/_select.js +162 -0
  76. data/app/assets/javascripts/fae/form/inputs/_text.js +118 -0
  77. data/app/assets/javascripts/fae/navigation/_global_search.js +184 -0
  78. data/app/assets/javascripts/fae/navigation/_language.js +89 -0
  79. data/app/assets/javascripts/fae/navigation/_navigation.js +206 -0
  80. data/app/assets/javascripts/fae/navigation/_subnav_highlighter.js +81 -0
  81. data/app/assets/javascripts/fae/navigation/sticky.js +186 -0
  82. data/app/assets/javascripts/fae/vendor/chosen.jquery.min.js +2 -0
  83. data/app/assets/javascripts/fae/vendor/frob_core_helpers.js +587 -0
  84. data/app/assets/javascripts/fae/vendor/fryr.js +437 -0
  85. data/app/assets/javascripts/fae/vendor/jqColorPicker.min.js +4 -0
  86. data/app/assets/javascripts/fae/vendor/jquery.daterangepicker.js +1292 -0
  87. data/app/assets/javascripts/fae/vendor/jquery.multi-select.js +534 -0
  88. data/app/assets/javascripts/fae/vendor/jquery.simplemodal.1.4.4.js +719 -0
  89. data/app/assets/javascripts/fae/vendor/jquery.tablesorter.js +1901 -0
  90. data/app/assets/javascripts/fae/vendor/js.cookie.js +139 -0
  91. data/app/assets/javascripts/fae/vendor/moment.min.js +7 -0
  92. data/app/assets/javascripts/fae/vendor/simplemde.min.js +13 -0
  93. data/app/assets/javascripts/fae/vendor/touch_punch.js +11 -0
  94. data/app/assets/javascripts/fae/vendor/trumbowyg.js.erb +4 -0
  95. data/app/assets/javascripts/fae/vendor/trumbowyg/plugins/upload/trumbowyg.upload.js +223 -0
  96. data/app/assets/javascripts/fae/vendor/trumbowyg/trumbowyg.js +1603 -0
  97. data/app/assets/stylesheets/fae/application.css +8 -0
  98. data/app/assets/stylesheets/fae/base.scss +82 -0
  99. data/app/assets/stylesheets/fae/globals/_fonts.scss +43 -0
  100. data/app/assets/stylesheets/fae/globals/_icons.scss +15 -0
  101. data/app/assets/stylesheets/fae/globals/_plugins.scss +51 -0
  102. data/app/assets/stylesheets/fae/globals/_tags.scss +68 -0
  103. data/app/assets/stylesheets/fae/globals/imports/_extends.scss +53 -0
  104. data/app/assets/stylesheets/fae/globals/imports/_mixins.scss +58 -0
  105. data/app/assets/stylesheets/fae/globals/imports/_variables.scss +165 -0
  106. data/app/assets/stylesheets/fae/globals/imports/finescss/_fine.scss +7 -0
  107. data/app/assets/stylesheets/fae/globals/imports/finescss/_fine_functions.scss +88 -0
  108. data/app/assets/stylesheets/fae/globals/imports/finescss/_fine_mixins.scss +280 -0
  109. data/app/assets/stylesheets/fae/globals/imports/finescss/_fine_variables.scss +30 -0
  110. data/app/assets/stylesheets/fae/globals/layout/_base.scss +48 -0
  111. data/app/assets/stylesheets/fae/globals/layout/_breadcrumbs.scss +45 -0
  112. data/app/assets/stylesheets/fae/globals/layout/_content-header.scss +99 -0
  113. data/app/assets/stylesheets/fae/globals/legacy/_pre-1.3.scss +659 -0
  114. data/app/assets/stylesheets/fae/globals/navigation/_base.scss +22 -0
  115. data/app/assets/stylesheets/fae/globals/navigation/_footer.scss +50 -0
  116. data/app/assets/stylesheets/fae/globals/navigation/_header.scss +149 -0
  117. data/app/assets/stylesheets/fae/globals/navigation/_mobilenav.scss +149 -0
  118. data/app/assets/stylesheets/fae/globals/navigation/_search.scss +76 -0
  119. data/app/assets/stylesheets/fae/globals/navigation/_sidenav.scss +142 -0
  120. data/app/assets/stylesheets/fae/globals/navigation/_utility.scss +95 -0
  121. data/app/assets/stylesheets/fae/modules/_alerts.scss +50 -0
  122. data/app/assets/stylesheets/fae/modules/_buttons.scss +62 -0
  123. data/app/assets/stylesheets/fae/modules/_modal.scss +78 -0
  124. data/app/assets/stylesheets/fae/modules/_toggles.scss +48 -0
  125. data/app/assets/stylesheets/fae/modules/forms/_asset-actions.scss +83 -0
  126. data/app/assets/stylesheets/fae/modules/forms/_base.scss +100 -0
  127. data/app/assets/stylesheets/fae/modules/forms/_checkbox.scss +87 -0
  128. data/app/assets/stylesheets/fae/modules/forms/_colorpicker.scss +57 -0
  129. data/app/assets/stylesheets/fae/modules/forms/_date.scss +335 -0
  130. data/app/assets/stylesheets/fae/modules/forms/_hints.scss +40 -0
  131. data/app/assets/stylesheets/fae/modules/forms/_label.scss +57 -0
  132. data/app/assets/stylesheets/fae/modules/forms/_radio.scss +69 -0
  133. data/app/assets/stylesheets/fae/modules/forms/_select.scss +317 -0
  134. data/app/assets/stylesheets/fae/modules/forms/_simple-mde.scss +29 -0
  135. data/app/assets/stylesheets/fae/modules/forms/_text.scss +62 -0
  136. data/app/assets/stylesheets/fae/modules/forms/_textarea.scss +16 -0
  137. data/app/assets/stylesheets/fae/modules/forms/_validation.scss +63 -0
  138. data/app/assets/stylesheets/fae/modules/tables/_actions.scss +41 -0
  139. data/app/assets/stylesheets/fae/modules/tables/_base.scss +63 -0
  140. data/app/assets/stylesheets/fae/modules/tables/_collapsible.scss +76 -0
  141. data/app/assets/stylesheets/fae/modules/tables/_filters.scss +61 -0
  142. data/app/assets/stylesheets/fae/modules/tables/_image.scss +21 -0
  143. data/app/assets/stylesheets/fae/modules/tables/_pagination.scss +34 -0
  144. data/app/assets/stylesheets/fae/modules/tables/_sorting.scss +58 -0
  145. data/app/assets/stylesheets/fae/modules/tables/_sticky.scss +9 -0
  146. data/app/assets/stylesheets/fae/modules/tables/_tooltips.scss +24 -0
  147. data/app/assets/stylesheets/fae/pages/_error.scss +35 -0
  148. data/app/assets/stylesheets/fae/pages/_help.scss +28 -0
  149. data/app/assets/stylesheets/fae/pages/_home.scss +18 -0
  150. data/app/assets/stylesheets/fae/pages/_login.scss +137 -0
  151. data/app/assets/stylesheets/fae/vendor/chosen.css +377 -0
  152. data/app/assets/stylesheets/fae/vendor/daterangepicker.css +227 -0
  153. data/app/assets/stylesheets/fae/vendor/reset.css +48 -0
  154. data/app/assets/stylesheets/fae/vendor/simplemde.min.css +7 -0
  155. data/app/assets/stylesheets/fae/vendor/trumbowyg.css +584 -0
  156. data/app/controllers/concerns/fae/application_controller_concern.rb +1 -0
  157. data/app/controllers/concerns/fae/asset_cloner.rb +46 -0
  158. data/app/controllers/concerns/fae/cloneable.rb +136 -0
  159. data/app/controllers/fae/application_controller.rb +123 -0
  160. data/app/controllers/fae/base_controller.rb +117 -0
  161. data/app/controllers/fae/files_controller.rb +26 -0
  162. data/app/controllers/fae/images_controller.rb +37 -0
  163. data/app/controllers/fae/nested_base_controller.rb +100 -0
  164. data/app/controllers/fae/options_controller.rb +29 -0
  165. data/app/controllers/fae/pages_controller.rb +44 -0
  166. data/app/controllers/fae/setup_controller.rb +54 -0
  167. data/app/controllers/fae/static_pages_controller.rb +54 -0
  168. data/app/controllers/fae/users_controller.rb +71 -0
  169. data/app/controllers/fae/utilities_controller.rb +61 -0
  170. data/app/helpers/fae/application_helper.rb +114 -0
  171. data/app/helpers/fae/fae_helper.rb +6 -0
  172. data/app/helpers/fae/form_helper.rb +240 -0
  173. data/app/helpers/fae/nested_form_helper.rb +39 -0
  174. data/app/helpers/fae/view_helper.rb +175 -0
  175. data/app/inputs/date_range_input.rb +17 -0
  176. data/app/inputs/radio_collection_input.rb +17 -0
  177. data/app/inputs/symbol_input.rb +5 -0
  178. data/app/models/concerns/fae/assets_validatable.rb +12 -0
  179. data/app/models/concerns/fae/authorization_concern.rb +12 -0
  180. data/app/models/concerns/fae/base_model_concern.rb +105 -0
  181. data/app/models/concerns/fae/change_concern.rb +1 -0
  182. data/app/models/concerns/fae/file_concern.rb +1 -0
  183. data/app/models/concerns/fae/image_concern.rb +1 -0
  184. data/app/models/concerns/fae/navigation_concern.rb +10 -0
  185. data/app/models/concerns/fae/option_concern.rb +1 -0
  186. data/app/models/concerns/fae/page_validatable.rb +26 -0
  187. data/app/models/concerns/fae/paper_trailer.rb +8 -0
  188. data/app/models/concerns/fae/role_concern.rb +1 -0
  189. data/app/models/concerns/fae/sortable.rb +51 -0
  190. data/app/models/concerns/fae/static_page_concern.rb +1 -0
  191. data/app/models/concerns/fae/text_area_concern.rb +1 -0
  192. data/app/models/concerns/fae/text_field_concern.rb +1 -0
  193. data/app/models/concerns/fae/trackable.rb +124 -0
  194. data/app/models/concerns/fae/user_concern.rb +7 -0
  195. data/app/models/fae/authorization.rb +8 -0
  196. data/app/models/fae/change.rb +53 -0
  197. data/app/models/fae/file.rb +24 -0
  198. data/app/models/fae/image.rb +33 -0
  199. data/app/models/fae/navigation.rb +132 -0
  200. data/app/models/fae/option.rb +38 -0
  201. data/app/models/fae/role.rb +18 -0
  202. data/app/models/fae/static_page.rb +109 -0
  203. data/app/models/fae/text_area.rb +14 -0
  204. data/app/models/fae/text_field.rb +14 -0
  205. data/app/models/fae/user.rb +67 -0
  206. data/app/uploaders/fae/file_uploader.rb +26 -0
  207. data/app/uploaders/fae/image_uploader.rb +28 -0
  208. data/app/validators/fae/cross_model_uniqueness_validator.rb +14 -0
  209. data/app/views/devise/confirmations/new.html.slim +13 -0
  210. data/app/views/devise/mailer/confirmation_instructions.html.slim +3 -0
  211. data/app/views/devise/mailer/reset_password_instructions.html.slim +5 -0
  212. data/app/views/devise/mailer/unlock_instructions.html.slim +4 -0
  213. data/app/views/devise/passwords/edit.html.slim +10 -0
  214. data/app/views/devise/passwords/new.html.slim +10 -0
  215. data/app/views/devise/registrations/edit.html.slim +22 -0
  216. data/app/views/devise/registrations/new.html.slim +15 -0
  217. data/app/views/devise/sessions/new.html.slim +7 -0
  218. data/app/views/devise/shared/_links.slim +25 -0
  219. data/app/views/devise/unlocks/new.html.slim +13 -0
  220. data/app/views/fae/application/_breadcrumb.html.slim +19 -0
  221. data/app/views/fae/application/_content_form.html.slim +55 -0
  222. data/app/views/fae/application/_credit.slim +6 -0
  223. data/app/views/fae/application/_file_uploader.html.slim +36 -0
  224. data/app/views/fae/application/_flash_messages.slim +2 -0
  225. data/app/views/fae/application/_global_search_results.html.slim +37 -0
  226. data/app/views/fae/application/_header.slim +50 -0
  227. data/app/views/fae/application/_markdown_helper.slim +41 -0
  228. data/app/views/fae/application/_mobilenav.slim +66 -0
  229. data/app/views/fae/application/_sidenav.slim +23 -0
  230. data/app/views/fae/application/_user_log.html.slim +36 -0
  231. data/app/views/fae/images/_image_uploader.html.slim +66 -0
  232. data/app/views/fae/options/_form.html.slim +16 -0
  233. data/app/views/fae/options/edit.html.slim +1 -0
  234. data/app/views/fae/pages/activity_log.html.slim +32 -0
  235. data/app/views/fae/pages/disabled_environment.html.slim +4 -0
  236. data/app/views/fae/pages/error404.html.slim +7 -0
  237. data/app/views/fae/pages/help.html.slim +35 -0
  238. data/app/views/fae/pages/home.html.slim +36 -0
  239. data/app/views/fae/setup/first_user.html.slim +11 -0
  240. data/app/views/fae/shared/_errors.slim +4 -0
  241. data/app/views/fae/shared/_form_header.html.slim +40 -0
  242. data/app/views/fae/shared/_index_header.html.slim +26 -0
  243. data/app/views/fae/shared/_nested_table.html.slim +49 -0
  244. data/app/views/fae/shared/_recent_changes.html.slim +22 -0
  245. data/app/views/fae/shared/_shared_nested_table.html.slim +46 -0
  246. data/app/views/fae/static_pages/index.html.slim +13 -0
  247. data/app/views/fae/users/_form.html.slim +19 -0
  248. data/app/views/fae/users/edit.html.slim +1 -0
  249. data/app/views/fae/users/index.html.slim +23 -0
  250. data/app/views/fae/users/new.html.slim +1 -0
  251. data/app/views/fae/users/settings.html.slim +1 -0
  252. data/app/views/kaminari/fae/_gap.html.slim +8 -0
  253. data/app/views/kaminari/fae/_next_page.html.slim +9 -0
  254. data/app/views/kaminari/fae/_page.html.slim +15 -0
  255. data/app/views/kaminari/fae/_paginator.html.slim +15 -0
  256. data/app/views/kaminari/fae/_prev_page.html.slim +9 -0
  257. data/app/views/layouts/devise.html.slim +29 -0
  258. data/app/views/layouts/fae/application.html.slim +23 -0
  259. data/app/views/layouts/fae/error.html.slim +11 -0
  260. data/config/deploy.rb +73 -0
  261. data/config/deploy/dev.rb +19 -0
  262. data/config/deploy/prod.rb +19 -0
  263. data/config/deploy/stage.rb +19 -0
  264. data/config/initializers/assets.rb +1 -0
  265. data/config/initializers/carrierwave.rb +3 -0
  266. data/config/initializers/devise.rb +258 -0
  267. data/config/initializers/devise_monkeypatch.rb +11 -0
  268. data/config/initializers/fae_judge.rb +3 -0
  269. data/config/initializers/inflections.rb +16 -0
  270. data/config/initializers/kaminari_config.rb +10 -0
  271. data/config/initializers/simple_form.rb +147 -0
  272. data/config/initializers/time_formats.rb +3 -0
  273. data/config/locales/devise.en.yml +59 -0
  274. data/config/locales/devise.zh-CN.yml +59 -0
  275. data/config/locales/fae.en.yml +10 -0
  276. data/config/locales/fae.zh-CN.yml +10 -0
  277. data/config/locales/simple_form.en.yml +26 -0
  278. data/config/locales/simple_form.zh-CN.yml +26 -0
  279. data/config/routes.rb +46 -0
  280. data/db/migrate/20140809222030_add_user_table.rb +49 -0
  281. data/db/migrate/20140822224029_create_fae_roles.rb +10 -0
  282. data/db/migrate/20141008180718_create_fae_images_table.rb +19 -0
  283. data/db/migrate/20141017194616_create_fae_options.rb +16 -0
  284. data/db/migrate/20141021181327_create_fae_files.rb +17 -0
  285. data/db/migrate/20141021183047_create_fae_text_areas.rb +16 -0
  286. data/db/migrate/20141021184311_create_fae_pages.rb +13 -0
  287. data/db/migrate/20141105214814_create_fae_text_fields.rb +15 -0
  288. data/db/migrate/20150930224821_create_fae_changes.rb +17 -0
  289. data/lib/fae-rails.rb +6 -0
  290. data/lib/fae/concerns/models/base.rb +8 -0
  291. data/lib/fae/engine.rb +37 -0
  292. data/lib/fae/options.rb +35 -0
  293. data/lib/fae/validation_helper_collection.rb +76 -0
  294. data/lib/fae/version.rb +3 -0
  295. data/lib/file_size_validator.rb +71 -0
  296. data/lib/generators/fae/base_generator.rb +156 -0
  297. data/lib/generators/fae/controller_generator.rb +13 -0
  298. data/lib/generators/fae/install_generator.rb +61 -0
  299. data/lib/generators/fae/model_generator.rb +11 -0
  300. data/lib/generators/fae/nested_index_scaffold_generator.rb +36 -0
  301. data/lib/generators/fae/nested_scaffold_generator.rb +51 -0
  302. data/lib/generators/fae/page_generator.rb +65 -0
  303. data/lib/generators/fae/scaffold_generator.rb +15 -0
  304. data/lib/generators/fae/templates/assets/fae.js +6 -0
  305. data/lib/generators/fae/templates/assets/fae.scss +2 -0
  306. data/lib/generators/fae/templates/controllers/nested_index_scaffold_controller.rb +81 -0
  307. data/lib/generators/fae/templates/controllers/nested_scaffold_controller.rb +13 -0
  308. data/lib/generators/fae/templates/controllers/scaffold_controller.rb +13 -0
  309. data/lib/generators/fae/templates/controllers/static_pages_controller.rb +10 -0
  310. data/lib/generators/fae/templates/initializers/fae.rb +63 -0
  311. data/lib/generators/fae/templates/initializers/fae_fine.rb +51 -0
  312. data/lib/generators/fae/templates/initializers/judge.rb +6 -0
  313. data/lib/generators/fae/templates/models/concerns/authorization_concern.rb +27 -0
  314. data/lib/generators/fae/templates/models/concerns/navigation_concern.rb +33 -0
  315. data/lib/generators/fae/templates/models/pages_model.rb +14 -0
  316. data/lib/generators/fae/templates/tasks/fae_tasks.rake +19 -0
  317. data/lib/generators/fae/templates/views/_form.html.slim +18 -0
  318. data/lib/generators/fae/templates/views/_form_index_nested.html.slim +13 -0
  319. data/lib/generators/fae/templates/views/_form_nested.html.slim +17 -0
  320. data/lib/generators/fae/templates/views/edit.html.slim +1 -0
  321. data/lib/generators/fae/templates/views/edit_nested.html.slim +3 -0
  322. data/lib/generators/fae/templates/views/index.html.slim +35 -0
  323. data/lib/generators/fae/templates/views/index_nested.html.slim +8 -0
  324. data/lib/generators/fae/templates/views/new.html.slim +1 -0
  325. data/lib/generators/fae/templates/views/new_nested.html.slim +3 -0
  326. data/lib/generators/fae/templates/views/static_page_form.html.slim +15 -0
  327. data/lib/generators/fae/templates/views/table_nested.html.slim +4 -0
  328. metadata +692 -0
@@ -0,0 +1,114 @@
1
+ module Fae
2
+ module ApplicationHelper
3
+
4
+ def form_header(name)
5
+ name = name.class.name.split('::').last unless name.is_a? String
6
+ form_title = "#{params[:action]} #{name}".titleize
7
+ form_title = form_title.singularize if params[:action] == 'edit'
8
+ content_tag :h1, form_title
9
+ end
10
+
11
+ def require_locals(local_array, local_assigns)
12
+ local_array.each do |loc|
13
+ raise "#{loc} is a required local, please define it when you render this partial" unless local_assigns[loc.to_sym].present?
14
+ end
15
+ end
16
+
17
+ def nav_active_class(klass, level, idx, parent_idx = nil)
18
+ return klass unless @fae_navigation.coordinates[level] == idx
19
+ return klass unless parent_idx.blank? || @fae_navigation.coordinates[level-1] == parent_idx
20
+ new_klass = parent_idx.blank? ? '-parent-current -open' : '-current'
21
+ new_klass += " #{klass}" if klass.present?
22
+ new_klass
23
+ end
24
+
25
+ def col_name_or_image(item, attribute)
26
+ value = item.send(attribute)
27
+ return if value.blank?
28
+ # if item is an image
29
+ if value.class.name == 'Fae::Image'
30
+ image_tag(value.asset.thumb.url) if value.asset.thumb.url.present?
31
+ # if item's attribute is an association
32
+ elsif item.class.reflections.include?(attribute)
33
+ value.try(:fae_display_field)
34
+ # if item is a date or a time adjust to timezone
35
+ elsif value.is_a?(Date) || value.is_a?(ActiveSupport::TimeWithZone)
36
+ fae_date_format(value)
37
+ elsif value.is_a?(Time)
38
+ fae_datetime_format(value)
39
+ else
40
+ # otherwise it's an attribute so display it's value
41
+ value
42
+ end
43
+ end
44
+
45
+ def fae_scope
46
+ fae.root_path.gsub('/', '')
47
+ end
48
+
49
+ def page_title
50
+ if @page_title.present?
51
+ @page_title
52
+ else
53
+ default_page_title
54
+ end
55
+ end
56
+
57
+ def body_class
58
+ @body_class.present? ? @body_class : "#{controller_name} #{action_name}"
59
+ end
60
+
61
+ def change_item_link(change)
62
+ text = "#{change.changeable_type.gsub('Fae::','')}: "
63
+ test_source_method = :data_source_exists?
64
+
65
+ if change.changeable_type.exclude?('Fae') && change.changeable_type.exclude?('Page') && !ActiveRecord::Base.connection.send(test_source_method, change.changeable_type.tableize)
66
+ return "#{change.changeable_type}: model destroyed"
67
+ else
68
+ display_text = change.try(:changeable).try(:fae_display_field)
69
+ display_text = (display_text.is_a? Integer) ? display_text.to_s : display_text
70
+ text += display_text || "##{change.changeable_id}"
71
+
72
+ begin
73
+ return link_to text, fae.edit_content_block_path(change.changeable.slug) if change.changeable_type == 'Fae::StaticPage'
74
+ parent = change.changeable.respond_to?(:fae_parent) ? change.changeable.fae_parent : nil
75
+ edit_path = edit_polymorphic_path([main_app, fae_scope, parent, change.changeable])
76
+ return link_to text, edit_path
77
+ rescue
78
+ return text
79
+ end
80
+ end
81
+ end
82
+
83
+ private
84
+
85
+ def nav_path_current?(path)
86
+ current_page?(path) || path[1..-1].classify == params[:controller].classify
87
+ end
88
+
89
+ def default_page_title
90
+ pieces = [@option.title]
91
+ pieces << page_title_piece
92
+ pieces.join ' | '
93
+ end
94
+
95
+ def page_title_piece
96
+ return @page_title_piece if @page_title_piece.present?
97
+
98
+ action = params[:action].humanize.titleize unless params[:action] == 'index'
99
+ controller = controller_title unless params[:controller] == 'fae/pages'
100
+ controller = controller.singularize if params[:action] == 'new' || params[:action] == 'edit'
101
+
102
+ "#{action} #{controller}".strip
103
+ end
104
+
105
+ def controller_title
106
+ params[:controller].gsub(/fae\/|#{fae_scope}\//, '').humanize.titleize
107
+ end
108
+
109
+ def tr_id(item)
110
+ "#{item.class.name.underscore.gsub('/', '_').pluralize}_#{item.id}"
111
+ end
112
+
113
+ end
114
+ end
@@ -0,0 +1,6 @@
1
+ # DO NOT add methods to this helper
2
+ # this empty helper is meant to be overridden in the parent app
3
+ module Fae
4
+ module FaeHelper
5
+ end
6
+ end
@@ -0,0 +1,240 @@
1
+ module Fae
2
+ module FormHelper
3
+
4
+ def fae_input(f, attribute, options={})
5
+ custom_options attribute, options
6
+ language_support f, attribute, options
7
+ label_and_hint attribute, options
8
+ list_order f, attribute, options
9
+ set_prompt f, attribute, options
10
+
11
+ add_input_class(options, 'js-markdown-editor') if options[:markdown].present?
12
+ add_input_class(options, 'js-html-editor') if options[:html].present?
13
+
14
+ set_maxlength(f, attribute, options)
15
+
16
+ f.input attribute, options
17
+ end
18
+
19
+ def fae_association(f, attribute, options={})
20
+ custom_options attribute, options
21
+ label_and_hint attribute, options
22
+ list_order f, attribute, options
23
+ set_prompt f, attribute, options if !options[:include_blank].is_a?(String)
24
+
25
+ f.association attribute, options
26
+ end
27
+
28
+ def fae_prefix(f, attribute, options={})
29
+ raise "Fae::MissingRequiredOption: fae_prefix helper method requires the 'prefix' option." if options[:prefix].blank?
30
+ symbol 'prefix', options[:prefix], options
31
+ fae_input f, attribute, options
32
+ end
33
+
34
+ def fae_suffix(f, attribute, options={})
35
+ raise "Fae::MissingRequiredOption: fae_suffix helper method requires the 'suffix' option." if options[:suffix].blank?
36
+ symbol 'suffix', options[:suffix], options
37
+ fae_input f, attribute, options
38
+ end
39
+
40
+ def fae_radio(f, attribute, options={})
41
+ options[:alignment] = 'radio_collection--horizontal' if options[:type] == 'inline'
42
+ options[:alignment] = 'radio_collection--vertical' if options[:type] == 'stacked' || options[:type].blank?
43
+ options.update(as: :radio_collection, wrapper_class: "#{options[:wrapper_class]} #{options[:alignment]}", no_label_div: true)
44
+ association_or_input f, attribute, options
45
+ end
46
+
47
+ def fae_checkbox(f, attribute, options={})
48
+ options[:type] ||= 'stacked'
49
+ options.update(as: :check_boxes, wrapper_class: "checkbox-wrapper js-checkbox-wrapper #{options[:wrapper_class]} -#{options[:type]}", no_label_div: true)
50
+ association_or_input f, attribute, options
51
+ end
52
+
53
+ def fae_pulldown(f, attribute, options={})
54
+ raise "Fae::MissingRequiredOption: fae_pulldown requires a 'collection' when using it on an ActiveRecord attribute." if !options.has_key?(:collection) && f.object.attribute_names.include?(attribute.to_s)
55
+ raise "Fae::ImproperOptionValue: The value #{options[:size]} is not a valid option for 'size'. Please use 'short' or 'long'." if options[:size].present? && ['short','long'].include?(options[:size]) == false
56
+ raise "Fae::ImproperOptionValue: The value #{options[:search]} is not a valid option for 'search'. Please use a Boolean." if options[:search].present? && !!options[:search] != options[:search]
57
+
58
+ add_input_class(options, 'small_pulldown') if options[:size] == "short"
59
+ add_input_class(options, 'select-search') if options[:search]
60
+ options.update(wrapper_class: "#{options[:wrapper_class]} select-no_search") if options[:search] == false
61
+ association_or_input f, attribute, options
62
+ end
63
+
64
+ def fae_multiselect(f, attribute, options={})
65
+ raise "Fae::'#{attribute}' must be an association of #{f.object}" if !is_association?(f, attribute)
66
+ raise "Fae::ImproperOptionValue: The value '#{options[:two_pane]}' is not a valid option for 'two_pane'. Please use a Boolean." if options[:two_pane].present? && !!options[:two_pane] != options[:two_pane]
67
+
68
+ options.update(input_class: "#{options[:input_class]} multiselect") if options[:two_pane] == true
69
+ fae_association f, attribute, options
70
+ end
71
+
72
+ def fae_datepicker(f, attribute, options={})
73
+ options.update(as: :string, wrapper_class: 'datepicker')
74
+ fae_input f, attribute, options
75
+ end
76
+
77
+ def fae_color_picker(f, attribute, options={})
78
+ options.update(
79
+ as: :string,
80
+ input_class: "js-color-picker color-picker #{'alpha-slider' unless options[:alpha] == false}",
81
+ input_html: { value: f.object.send(attribute).to_s } # value needs to be set to clear color picker
82
+ )
83
+ fae_input f, attribute, options
84
+ end
85
+
86
+ def fae_daterange(f, attr_array, options={})
87
+ raise "Fae::MissingRequiredOption: fae_daterange requires the 'label' option." if options[:label].blank?
88
+ raise "Fae::MalformedArgument: fae_daterange requires an array of two attributes as it's second argument." unless attr_array.present? && attr_array.is_a?(Array) && attr_array.length == 2
89
+ options.update(as: :date_range, start_date: attr_array.first, end_date: attr_array.second)
90
+ fae_input f, options[:label], options
91
+ end
92
+
93
+ def fae_grouped_select(f, attribute, options={})
94
+ raise "Fae::MissingRequiredOption: fae_grouped_select requires a `collection` option or `groups` and `labels` options." if !options.has_key?(:collection) && !options.has_key?(:groups) && !options.has_key?(:labels)
95
+ raise "Fae::MissingRequiredOption: fae_grouped_select required a `labels` option with a value containing an array when using the `groups` option." if options[:groups].present? && options[:labels].blank?
96
+ raise "Fae::MissingRequiredOption: fae_grouped_select required a `groups` option with a value containing an array when using the `labels` option." if options[:labels].present? && options[:groups].blank?
97
+
98
+ options[:collection] ||= group_options_for_collection(options[:labels], options[:groups])
99
+ options.update(as: :grouped_select, group_method: :last, wrapper_class: "#{options[:wrapper_class]} select")
100
+ association_or_input f, attribute, options
101
+ end
102
+
103
+ def fae_video_url(f, attribute, options={})
104
+ options[:helper_text] ||= "Please enter your YouTube video ID. The video ID is between v= and & of the video's url. This is typically 11 characters long."
105
+ options[:hint] ||= '<div class="youtube-hint"></div>'
106
+ fae_input f, attribute, options
107
+ end
108
+
109
+
110
+ private
111
+
112
+ def custom_options(attribute, options)
113
+ add_input_class(options, options[:input_class]) if options[:input_class].present?
114
+ add_input_class(options, 'slug') if attribute == :slug
115
+ options.update(wrapper_class: "#{options[:wrapper_class]} input") if options[:wrapper_class].present?
116
+ options.update(validate: true) unless options[:validate].present? && options[:validate] == false
117
+ end
118
+
119
+ def label_and_hint(attribute, options)
120
+ hint = options[:hint]
121
+
122
+ options[:helper_text] = attempt_common_helper_text(attribute) if options[:helper_text].blank?
123
+
124
+ attribute_name = options[:as].to_s == 'hidden' ? '' : attribute.to_s.titleize
125
+ label = options[:label] || attribute_name
126
+ if options[:markdown_supported].present? || options[:helper_text].present?
127
+ label += content_tag :h6, class: 'helper_text' do
128
+ concat(options[:helper_text]) if options[:helper_text].present?
129
+ concat(content_tag(:span, 'Markdown Supported', class: 'markdown-support')) if options[:markdown_supported].present?
130
+ end
131
+ end
132
+ options[:label] = label.html_safe if label.present?
133
+
134
+ options[:hint] = hint.html_safe if hint.present?
135
+ end
136
+
137
+ def is_attribute_or_association?(f, attribute)
138
+ f.object.has_attribute?(attribute) || is_association?(f, attribute)
139
+ end
140
+
141
+ def is_association?(f, attribute)
142
+ f.object.class.reflections.include?(attribute) || f.object.class.reflections.include?(attribute.to_s)
143
+ end
144
+
145
+ def association_or_input(f, attribute, options)
146
+ if is_attribute_or_association?(f, attribute)
147
+ f.object.attribute_names.include?(attribute.to_s) ? fae_input(f, attribute, options) : fae_association(f, attribute, options)
148
+ else
149
+ raise "Fae::undefined method '#{attribute}' for #{f.object}"
150
+ end
151
+ end
152
+
153
+ def symbol(type, val, options)
154
+ options[:as] = :symbol
155
+ options[:wrapper_class] = options[:wrapper_class].present? ? "#{options[:wrapper_class]} input symbol--#{type}" : "input symbol--#{type}"
156
+ options[:span_class] = "input-symbol--#{type}"
157
+ options[:span_class] += " icon-#{val}" if options[:icon].present?
158
+ options[:content_text] = val if options[:icon].blank?
159
+ end
160
+
161
+ def group_options_for_collection(labels, groups)
162
+ raise "Fae::groups and labels must be an array" if !(labels.is_a? Array) || !(groups.is_a? Array)
163
+ raise "Fae::grouped options must be arrays of equal length. label length: #{labels.length}, options_length: #{groups.length}" if labels.length != groups.length
164
+
165
+ collection = {}
166
+ labels.each_with_index { |label, i| collection[label] = groups[i] }
167
+ collection
168
+ end
169
+
170
+ def to_class(attribute)
171
+ attribute.to_s.classify.constantize
172
+ end
173
+
174
+ def add_input_class(options, class_name)
175
+ if options.key?(:input_html)
176
+ options[:input_html].merge!({class: "#{options[:input_html][:class]} #{class_name}"})
177
+ else
178
+ options[:input_html] = { class: class_name }
179
+ end
180
+ end
181
+
182
+ # sets collection to class.for_fae_index if not defined
183
+ def list_order(f, attribute, options)
184
+ if is_association?(f, attribute) && !options[:collection]
185
+ begin
186
+ options[:collection] = to_class(attribute).for_fae_index
187
+ rescue NameError
188
+ raise "Fae::MissingCollection: `#{attribute}` isn't an orderable class, define your order using the `collection` option."
189
+ end
190
+ end
191
+ end
192
+
193
+ # sets default prompt for pulldowns
194
+ def set_prompt(f, attribute, options)
195
+ options[:prompt] = 'Select One' if is_association?(f, attribute) && f.object.class.reflect_on_association(attribute).macro == :belongs_to && options[:prompt].nil? && !options[:two_pane]
196
+ end
197
+
198
+ # removes language suffix from label and adds data attr for languange nav
199
+ def language_support(f, attribute, options)
200
+ return if Fae.languages.blank?
201
+
202
+ attribute_array = attribute.to_s.split('_')
203
+ language_suffix = attribute_array.pop
204
+ return unless Fae.languages.has_key?(language_suffix.to_sym) || Fae.languages.has_key?(language_suffix)
205
+
206
+ label = attribute_array.push("(#{language_suffix})").join(' ').titleize
207
+ options[:label] = label unless options[:label].present?
208
+
209
+ if options[:wrapper_html].present?
210
+ options[:wrapper_html].deep_merge!({ data: { language: language_suffix } })
211
+ else
212
+ options[:wrapper_html] = { data: { language: language_suffix } }
213
+ end
214
+ end
215
+
216
+ def set_maxlength(f, attribute, options)
217
+ column = f.object.class.columns_hash[attribute.to_s]
218
+ if column.present? && (column.sql_type.include?('varchar') || column.sql_type == 'text')
219
+ # Rails 4.1 supports column.limit, 4.2 supports column.cast_type.limit
220
+ limit = column.try(:limit) || column.try(:cast_type).try(:limit)
221
+ if limit.present?
222
+ options[:input_html] ||= {}
223
+ options[:input_html][:maxlength] ||= limit
224
+ end
225
+ end
226
+ end
227
+
228
+ def attempt_common_helper_text(attribute)
229
+ case attribute
230
+ when :seo_title
231
+ return 'A descriptive page title of ~50-65 characters. Displayed in search engine results.'
232
+ when :seo_description
233
+ return 'A helpful page summary of 320 characters or less. Displayed in search engine results.'
234
+ else
235
+ ''
236
+ end
237
+ end
238
+
239
+ end
240
+ end
@@ -0,0 +1,39 @@
1
+ module Fae
2
+ module NestedFormHelper
3
+
4
+ def th_columns(attribute)
5
+ if (attribute.is_a?(Hash) && attribute[:title])
6
+ attribute = attribute[:title]
7
+ attribute_title = attribute
8
+ else
9
+ attribute = :modified if ['updated_at', 'modified_at'].include? attribute.to_s
10
+ attribute_title = attribute.to_s.titleize
11
+ end
12
+
13
+ th_class = '-action-wide' if [:on_production, :on_prod, :on_stage, :updated_at, :created_at, :modified].include?(attribute)
14
+ content_tag(:th, class: th_class) do attribute_title end
15
+ end
16
+
17
+ def td_columns(params)
18
+ attribute = params[:col]
19
+ attributes = params[:cols]
20
+ item = params[:item]
21
+
22
+ attribute = (attribute.is_a?(Hash) && attribute[:attr]) ? attribute[:attr] : attribute
23
+ first_attribute = (attributes.first.kind_of?(Hash) && attributes.first[:attr]) ? attributes.first[:attr] : attributes.first
24
+
25
+ if attribute == first_attribute && !params[:edit_column]
26
+ content_tag(:td) do
27
+ content_tag(:a, class: 'js-edit-link', href: self.send(params[:edit_path], item)) do
28
+ col_name_or_image(item, attribute)
29
+ end
30
+ end
31
+ elsif item.class.columns_hash[attribute.to_s].present? && item.class.columns_hash[attribute.to_s].type == :boolean
32
+ content_tag(:td, fae_toggle(item, attribute))
33
+ else
34
+ content_tag(:td, col_name_or_image(item, attribute))
35
+ end
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,175 @@
1
+ module Fae
2
+ module ViewHelper
3
+
4
+ def fae_date_format(datetime, timezone = @option.time_zone)
5
+ datetime.in_time_zone(timezone).strftime('%m/%d/%y') if is_date_or_time?(datetime)
6
+ end
7
+
8
+ def fae_datetime_format(datetime, timezone = @option.time_zone)
9
+ datetime.in_time_zone(timezone).strftime("%b %-d, %Y %l:%M%P %Z") if is_date_or_time?(datetime)
10
+ end
11
+
12
+ def fae_path
13
+ Rails.application.routes.url_helpers.fae_path[1..-1]
14
+ end
15
+
16
+ def fae_image_form(f, image_name, label: nil, alt_label: nil, caption_label: nil, show_alt: nil, show_caption: nil, required: nil, helper_text: nil, alt_helper_text: nil, caption_helper_text: nil, attached_as: nil)
17
+ render 'fae/images/image_uploader', f: f, image_name: image_name, label: label, alt_label: alt_label, caption_label: caption_label, show_alt: show_alt, show_caption: show_caption, required: required, helper_text: helper_text, alt_helper_text: alt_helper_text, caption_helper_text: caption_helper_text, attached_as: attached_as
18
+ end
19
+
20
+ def fae_file_form(f, file_name, label: nil, helper_text: nil, required: nil)
21
+ render 'fae/application/file_uploader', f: f, file_name: file_name, label: label, required: required, helper_text: helper_text
22
+ end
23
+
24
+ def fae_content_form(f, attribute, label: nil, hint: nil, helper_text: nil, markdown: nil, markdown_supported: nil, input_options: nil)
25
+ render 'fae/application/content_form', f: f, attribute: attribute, label: label, hint: hint, helper_text: helper_text, markdown: markdown, markdown_supported: markdown_supported, input_options: input_options
26
+ end
27
+
28
+ def fae_index_image(image, path = nil)
29
+ return if image.blank? || image.asset.blank? || image.asset.thumb.blank?
30
+ content_tag :div, class: 'image-mat' do
31
+ link_to_if path.present?, image_tag(image.asset.thumb.url), path
32
+ end
33
+ end
34
+
35
+ def fae_toggle(item, column)
36
+ active = item.send(column)
37
+ link_class = active ? 'slider-yes-selected' : ''
38
+ model_name = item.class.to_s.gsub('::','__').underscore.pluralize
39
+ url = fae.toggle_path(model_name, item.id.to_s, column)
40
+
41
+ link_to url, class: "slider-wrapper #{link_class}", method: :post, remote: true do
42
+ '<div class="slider-options">
43
+ <div class="slider-option slider-option-yes">Yes</div>
44
+ <div class="slider-option-selector"></div>
45
+ <div class="slider-option slider-option-no">No</div>
46
+ </div>'.html_safe
47
+ end
48
+ end
49
+
50
+ def fae_clone_button(item)
51
+ return if item.blank?
52
+ link_to "#{@index_path}?from_existing=#{item.id}", method: :post, title: 'Clone', class: 'js-tooltip table-action', data: { confirm: t('fae.clone_confirmation') } do
53
+ concat content_tag :i, nil, class: 'icon-copy'
54
+ end
55
+ end
56
+
57
+ def fae_delete_button(item, delete_path = nil, *custom_attrs)
58
+ return if item.blank?
59
+ delete_path ||= polymorphic_path([main_app, fae_scope, item.try(:fae_parent), item])
60
+ attrs = { method: :delete, title: 'Delete', class: 'js-tooltip table-action', data: { confirm: t('fae.delete_confirmation') } }
61
+ attrs.deep_merge!(custom_attrs[0]) if custom_attrs.present?
62
+ link_to delete_path, attrs do
63
+ concat content_tag :i, nil, class: 'icon-trash'
64
+ end
65
+ end
66
+
67
+ def fae_sort_id(item)
68
+ return if item.blank?
69
+ klass = item.class.name.underscore.gsub('/','__')
70
+ "#{klass}_#{item.id}"
71
+ end
72
+
73
+ def fae_filter_form(options = {}, &block)
74
+ options[:collection] ||= @items
75
+ options[:action] ||= "#{@index_path}/filter"
76
+ options[:title] ||= "Search #{@klass_humanized.pluralize.titleize}"
77
+ options[:search] = true if options[:search].nil?
78
+ options[:cookie_key] ||= false
79
+
80
+ return if options[:collection].blank?
81
+
82
+ form_hash = { class: 'js-filter-form table-filter-area' }
83
+ form_hash['data-cookie-key'] = options[:cookie_key] if options[:cookie_key].present?
84
+
85
+ filter_header = content_tag(:div, class: 'table-filter-header') do
86
+ concat content_tag :h4, options[:title]
87
+ concat filter_search_field if options[:search]
88
+ end
89
+
90
+ form_tag(options[:action], form_hash) do
91
+ concat filter_header
92
+
93
+ if block_given?
94
+ filter_group_wrapper = content_tag(:div, class: 'table-filter-group-wrapper') do
95
+ concat capture(&block)
96
+ concat content_tag(:div, content_tag(:a, 'Reset Search', class: 'js-reset-btn button -small hidden', href: '#'), class: 'table-filter-group')
97
+ end
98
+ end
99
+
100
+ concat filter_group_wrapper
101
+ # I know this `unless !` looks like it should be an `if` but it's definitely supposed to be `unless !`
102
+ concat submit_tag 'Apply Filters', class: 'hidden' unless !options[:search]
103
+ end
104
+ end
105
+
106
+ def fae_filter_select(attribute, options = {})
107
+ options[:label] ||= attribute.to_s.titleize
108
+ options[:collection] ||= default_collection_from_attribute(attribute)
109
+ options[:label_method] ||= :fae_display_field
110
+ options[:placeholder] = "All #{options[:label].pluralize}" if options[:placeholder].nil?
111
+ options[:options] ||= []
112
+ options[:grouped_by] ||= nil
113
+ options[:grouped_options] ||= []
114
+
115
+ # grouped_by takes priority over grouped_options
116
+ if options[:grouped_by].present?
117
+ select_options = filter_generate_select_group(options[:collection], options[:grouped_by], options[:label_method])
118
+ elsif options[:grouped_options].present?
119
+ select_options = grouped_options_for_select(options[:grouped_options])
120
+ else
121
+ select_options = options_from_collection_for_select(options[:collection], 'id', options[:label_method])
122
+ select_options = options_for_select(options[:options]) if options[:options].present?
123
+ end
124
+
125
+
126
+ content_tag :div, class: 'table-filter-group' do
127
+ concat label_tag "filter[#{attribute}]", options[:label]
128
+ concat select_tag "filter[#{attribute}]", select_options, prompt: options[:placeholder]
129
+ end
130
+ end
131
+
132
+ def fae_avatar(user = current_user)
133
+ hash = Digest::MD5.hexdigest(user.email.downcase)
134
+ "https://secure.gravatar.com/avatar/#{hash}?s=80&d=mm"
135
+ end
136
+
137
+ def fae_paginate(items)
138
+ content_tag :nav, class: 'pagination', data: { filter_path: "#{@index_path}/filter" } do
139
+ paginate items, theme: 'fae'
140
+ end
141
+ end
142
+
143
+ private
144
+
145
+ def filter_search_field
146
+ content_tag :div, class: 'table-filter-keyword-wrapper' do
147
+ concat text_field_tag 'filter[search]', nil, placeholder: 'Search by Keyword'
148
+ concat content_tag(:i, '', class: 'icon-search')
149
+ end
150
+ end
151
+
152
+ def filter_generate_select_group(collection, grouped_by, label_method)
153
+ labels = collection.map { |c| c.send(grouped_by).try(:fae_display_field) }.uniq
154
+ grouped_hash = {}
155
+
156
+ labels.each do |label|
157
+ values = collection.select { |c| c.send(grouped_by).try(:fae_display_field) == label }
158
+ grouped_hash[label] = values.map { |v| [v.send(label_method), v.id] }
159
+ end
160
+
161
+ grouped_options_for_select(grouped_hash)
162
+ end
163
+
164
+ def default_collection_from_attribute(attribute)
165
+ attribute.to_s.classify.constantize.for_fae_index
166
+ rescue NameError
167
+ []
168
+ end
169
+
170
+ def is_date_or_time?(datetime)
171
+ datetime.present? && ( datetime.kind_of?(Date) || datetime.kind_of?(Time) || datetime.kind_of?(ActiveSupport::TimeWithZone) )
172
+ end
173
+
174
+ end
175
+ end