releaf-core 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (288) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +24 -0
  3. data/app/assets/fonts/releaf/RobotoRegular_normal_400.ttf +0 -0
  4. data/app/assets/fonts/releaf/RobotoRegular_normal_400.woff +0 -0
  5. data/app/assets/fonts/releaf/RobotoRegular_normal_400.woff2 +0 -0
  6. data/app/assets/images/releaf/icons/apple-touch-icon-114x114-precomposed.png +0 -0
  7. data/app/assets/images/releaf/icons/apple-touch-icon-152x152-precomposed.png +0 -0
  8. data/app/assets/images/releaf/icons/apple-touch-icon-72x72-precomposed.png +0 -0
  9. data/app/assets/images/releaf/icons/favicon.ico +0 -0
  10. data/app/assets/images/releaf/icons/favicon.png +0 -0
  11. data/app/assets/images/releaf/icons/msapplication-tile-144x144.png +0 -0
  12. data/app/assets/images/releaf/logo-login.png +0 -0
  13. data/app/assets/images/releaf/logo.png +0 -0
  14. data/app/assets/javascripts/ckeditor/plugins/mediaembed/icons/hidpi/mediaembed.png +0 -0
  15. data/app/assets/javascripts/ckeditor/plugins/mediaembed/icons/mediaembed.png +0 -0
  16. data/app/assets/javascripts/ckeditor/plugins/mediaembed/lang/en.js +12 -0
  17. data/app/assets/javascripts/ckeditor/plugins/mediaembed/lang/es.js +12 -0
  18. data/app/assets/javascripts/ckeditor/plugins/mediaembed/plugin.js +63 -0
  19. data/app/assets/javascripts/releaf/3rd_party/jquery-ui-timepicker-addon.js +1882 -0
  20. data/app/assets/javascripts/releaf/3rd_party/jquery.magnific-popup.min.js +4 -0
  21. data/app/assets/javascripts/releaf/application.js +13 -0
  22. data/app/assets/javascripts/releaf/include/ajax.js +66 -0
  23. data/app/assets/javascripts/releaf/include/ajaxbox.js +179 -0
  24. data/app/assets/javascripts/releaf/include/dialogs.js +13 -0
  25. data/app/assets/javascripts/releaf/include/field.type_associated_set.js +32 -0
  26. data/app/assets/javascripts/releaf/include/field.type_date_or_datetime_or_time.js +73 -0
  27. data/app/assets/javascripts/releaf/include/field.type_richtext.js +188 -0
  28. data/app/assets/javascripts/releaf/include/loader.js +45 -0
  29. data/app/assets/javascripts/releaf/include/localization.js +213 -0
  30. data/app/assets/javascripts/releaf/include/nested_fields.js +295 -0
  31. data/app/assets/javascripts/releaf/include/notifications.js +267 -0
  32. data/app/assets/javascripts/releaf/include/pagination.js +19 -0
  33. data/app/assets/javascripts/releaf/include/profile_settings.js +28 -0
  34. data/app/assets/javascripts/releaf/include/remote_validator.js +437 -0
  35. data/app/assets/javascripts/releaf/include/search.js +140 -0
  36. data/app/assets/javascripts/releaf/include/sidebar.js +149 -0
  37. data/app/assets/javascripts/releaf/include/sortable.js +69 -0
  38. data/app/assets/javascripts/releaf/include/toolbox.js +221 -0
  39. data/app/assets/javascripts/releaf/include/url_builder.js +193 -0
  40. data/app/assets/stylesheets/releaf/application.scss +9 -0
  41. data/app/assets/stylesheets/releaf/environment/extras.scss +11 -0
  42. data/app/assets/stylesheets/releaf/environment/functions/units.scss +12 -0
  43. data/app/assets/stylesheets/releaf/environment/functions.scss +1 -0
  44. data/app/assets/stylesheets/releaf/environment/mixins/blocks.scss +133 -0
  45. data/app/assets/stylesheets/releaf/environment/mixins/elements.scss +64 -0
  46. data/app/assets/stylesheets/releaf/environment/mixins/text.scss +61 -0
  47. data/app/assets/stylesheets/releaf/environment/mixins.scss +3 -0
  48. data/app/assets/stylesheets/releaf/environment/variables/colors.scss +93 -0
  49. data/app/assets/stylesheets/releaf/environment/variables/dimensions.scss +0 -0
  50. data/app/assets/stylesheets/releaf/environment/variables/magnific-popup.scss +6 -0
  51. data/app/assets/stylesheets/releaf/environment/variables.scss +5 -0
  52. data/app/assets/stylesheets/releaf/environment.scss +4 -0
  53. data/app/assets/stylesheets/releaf/layout/base.scss +32 -0
  54. data/app/assets/stylesheets/releaf/layout/breadcrumbs.scss +47 -0
  55. data/app/assets/stylesheets/releaf/layout/buttons.scss +107 -0
  56. data/app/assets/stylesheets/releaf/layout/deprecated.scss +29 -0
  57. data/app/assets/stylesheets/releaf/layout/dialogs.scss +138 -0
  58. data/app/assets/stylesheets/releaf/layout/errors.scss +28 -0
  59. data/app/assets/stylesheets/releaf/layout/extras.scss +10 -0
  60. data/app/assets/stylesheets/releaf/layout/fields.scss +305 -0
  61. data/app/assets/stylesheets/releaf/layout/fonts.scss +16 -0
  62. data/app/assets/stylesheets/releaf/layout/footer.scss +80 -0
  63. data/app/assets/stylesheets/releaf/layout/forms.scss +23 -0
  64. data/app/assets/stylesheets/releaf/layout/header.scss +55 -0
  65. data/app/assets/stylesheets/releaf/layout/icons.scss +4 -0
  66. data/app/assets/stylesheets/releaf/layout/images.scss +4 -0
  67. data/app/assets/stylesheets/releaf/layout/links.scss +7 -0
  68. data/app/assets/stylesheets/releaf/layout/localization.scss +79 -0
  69. data/app/assets/stylesheets/releaf/layout/main.scss +43 -0
  70. data/app/assets/stylesheets/releaf/layout/notifications.scss +67 -0
  71. data/app/assets/stylesheets/releaf/layout/pagination.scss +18 -0
  72. data/app/assets/stylesheets/releaf/layout/search.scss +70 -0
  73. data/app/assets/stylesheets/releaf/layout/sections.scss +138 -0
  74. data/app/assets/stylesheets/releaf/layout/sidebar.scss +306 -0
  75. data/app/assets/stylesheets/releaf/layout/tables.scss +99 -0
  76. data/app/assets/stylesheets/releaf/layout/text.scss +31 -0
  77. data/app/assets/stylesheets/releaf/layout/toolboxes.scss +69 -0
  78. data/app/assets/stylesheets/releaf/layout.scss +35 -0
  79. data/app/assets/stylesheets/releaf/vendor/magnific-popup/main.scss +596 -0
  80. data/app/assets/stylesheets/releaf/vendor/magnific-popup/settings.scss +45 -0
  81. data/app/builders/releaf/builders/association_reflector.rb +58 -0
  82. data/app/builders/releaf/builders/base.rb +80 -0
  83. data/app/builders/releaf/builders/collection.rb +8 -0
  84. data/app/builders/releaf/builders/confirm_destroy_dialog_builder.rb +25 -0
  85. data/app/builders/releaf/builders/confirm_dialog_builder.rb +54 -0
  86. data/app/builders/releaf/builders/edit_builder.rb +66 -0
  87. data/app/builders/releaf/builders/form_builder.rb +594 -0
  88. data/app/builders/releaf/builders/index_builder.rb +118 -0
  89. data/app/builders/releaf/builders/orderer.rb +5 -0
  90. data/app/builders/releaf/builders/page/header_builder.rb +70 -0
  91. data/app/builders/releaf/builders/page/layout_builder.rb +155 -0
  92. data/app/builders/releaf/builders/page/menu_builder.rb +140 -0
  93. data/app/builders/releaf/builders/pagination_builder.rb +107 -0
  94. data/app/builders/releaf/builders/refused_destroy_dialog_builder.rb +68 -0
  95. data/app/builders/releaf/builders/resource.rb +9 -0
  96. data/app/builders/releaf/builders/resource_dialog.rb +8 -0
  97. data/app/builders/releaf/builders/resource_view.rb +54 -0
  98. data/app/builders/releaf/builders/show_builder.rb +3 -0
  99. data/app/builders/releaf/builders/table_builder.rb +280 -0
  100. data/app/builders/releaf/builders/tags/releaf_associated_set_field.rb +40 -0
  101. data/app/builders/releaf/builders/template.rb +8 -0
  102. data/app/builders/releaf/builders/toolbox.rb +23 -0
  103. data/app/builders/releaf/builders/toolbox_builder.rb +27 -0
  104. data/app/builders/releaf/builders/view.rb +132 -0
  105. data/app/builders/releaf/builders.rb +38 -0
  106. data/app/builders/releaf/core/settings/form_builder.rb +21 -0
  107. data/app/builders/releaf/core/settings/table_builder.rb +11 -0
  108. data/app/controllers/concerns/releaf/breadcrumbs.rb +42 -0
  109. data/app/controllers/concerns/releaf/richtext_attachments.rb +20 -0
  110. data/app/controllers/releaf/base_controller.rb +458 -0
  111. data/app/controllers/releaf/core/errors_controller.rb +5 -0
  112. data/app/controllers/releaf/core/settings_controller.rb +50 -0
  113. data/app/helpers/releaf/application_helper.rb +53 -0
  114. data/app/helpers/releaf/button_helper.rb +50 -0
  115. data/app/helpers/releaf/javascript_helper.rb +75 -0
  116. data/app/lib/releaf/core/assets_resolver.rb +58 -0
  117. data/app/lib/releaf/core/default_searchable_fields.rb +43 -0
  118. data/app/lib/releaf/core/error_formatter.rb +103 -0
  119. data/app/lib/releaf/core/item_orderer.rb +102 -0
  120. data/app/lib/releaf/core/resource_base.rb +66 -0
  121. data/app/lib/releaf/core/resource_fields.rb +6 -0
  122. data/app/lib/releaf/core/resource_params.rb +47 -0
  123. data/app/lib/releaf/core/resource_table_fields.rb +10 -0
  124. data/app/lib/releaf/core/resource_utilities.rb +36 -0
  125. data/app/lib/releaf/core/responders/access_denied_responder.rb +9 -0
  126. data/app/lib/releaf/core/responders/after_save_responder.rb +28 -0
  127. data/app/lib/releaf/core/responders/confirm_destroy_responder.rb +13 -0
  128. data/app/lib/releaf/core/responders/destroy_responder.rb +10 -0
  129. data/app/lib/releaf/core/responders/error_responder.rb +9 -0
  130. data/app/lib/releaf/core/responders/feature_disabled_responder.rb +9 -0
  131. data/app/lib/releaf/core/responders/page_not_found_responder.rb +9 -0
  132. data/app/lib/releaf/core/responders.rb +31 -0
  133. data/app/lib/releaf/core/search.rb +147 -0
  134. data/app/lib/releaf/core/template_field_type_mapper.rb +127 -0
  135. data/app/models/releaf/richtext_attachment.rb +6 -0
  136. data/app/models/releaf/settings.rb +27 -0
  137. data/app/views/layouts/releaf/admin.html.erb +1 -0
  138. data/app/views/releaf/base/confirm_destroy.ruby +1 -0
  139. data/app/views/releaf/base/create_releaf_richtext_attachment.haml +1 -0
  140. data/app/views/releaf/base/edit.ruby +1 -0
  141. data/app/views/releaf/base/index.ruby +1 -0
  142. data/app/views/releaf/base/new.ruby +1 -0
  143. data/app/views/releaf/base/refused_destroy.ruby +1 -0
  144. data/app/views/releaf/base/show.ruby +1 -0
  145. data/app/views/releaf/base/toolbox.ruby +1 -0
  146. data/app/views/releaf/error_pages/_error.html.haml +10 -0
  147. data/app/views/releaf/error_pages/access_denied.html.haml +1 -0
  148. data/app/views/releaf/error_pages/feature_disabled.html.haml +1 -0
  149. data/app/views/releaf/error_pages/page_not_found.html.haml +2 -0
  150. data/lib/generators/dummy/install_generator.rb +18 -0
  151. data/lib/generators/dummy/templates/builders/admin/books/form_builder.rb +13 -0
  152. data/lib/generators/dummy/templates/builders/admin/books/index_builder.rb +30 -0
  153. data/lib/generators/dummy/templates/builders/admin/books/table_builder.rb +7 -0
  154. data/lib/generators/dummy/templates/builders/admin/nodes/form_builder.rb +7 -0
  155. data/lib/generators/dummy/templates/config/routes.rb +19 -0
  156. data/lib/generators/dummy/templates/controllers/admin/authors_controller.rb +12 -0
  157. data/lib/generators/dummy/templates/controllers/admin/books_controller.rb +17 -0
  158. data/lib/generators/dummy/templates/controllers/admin/chapters_controller.rb +3 -0
  159. data/lib/generators/dummy/templates/controllers/admin/publishers_controller.rb +3 -0
  160. data/lib/generators/dummy/templates/controllers/application_controller.rb +39 -0
  161. data/lib/generators/dummy/templates/controllers/concerns/.keep +0 -0
  162. data/lib/generators/dummy/templates/controllers/concerns/node_controller.rb +37 -0
  163. data/lib/generators/dummy/templates/controllers/contacts_controller.rb +3 -0
  164. data/lib/generators/dummy/templates/controllers/home_pages_controller.rb +3 -0
  165. data/lib/generators/dummy/templates/controllers/text_pages_controller.rb +3 -0
  166. data/lib/generators/dummy/templates/initializers/releaf.rb +35 -0
  167. data/lib/generators/dummy/templates/migrations/create_authors.rb +14 -0
  168. data/lib/generators/dummy/templates/migrations/create_banners.rb +11 -0
  169. data/lib/generators/dummy/templates/migrations/create_book_sequels.rb +14 -0
  170. data/lib/generators/dummy/templates/migrations/create_books.rb +27 -0
  171. data/lib/generators/dummy/templates/migrations/create_bundles.rb +7 -0
  172. data/lib/generators/dummy/templates/migrations/create_chapters.rb +13 -0
  173. data/lib/generators/dummy/templates/migrations/create_home_pages.rb +9 -0
  174. data/lib/generators/dummy/templates/migrations/create_node_extra_fields.rb +5 -0
  175. data/lib/generators/dummy/templates/migrations/create_publishers.rb +8 -0
  176. data/lib/generators/dummy/templates/migrations/create_text_pages.rb +9 -0
  177. data/lib/generators/dummy/templates/models/author.rb +10 -0
  178. data/lib/generators/dummy/templates/models/banner.rb +5 -0
  179. data/lib/generators/dummy/templates/models/book.rb +19 -0
  180. data/lib/generators/dummy/templates/models/book_sequel.rb +4 -0
  181. data/lib/generators/dummy/templates/models/bundle.rb +17 -0
  182. data/lib/generators/dummy/templates/models/chapter.rb +7 -0
  183. data/lib/generators/dummy/templates/models/home_page.rb +5 -0
  184. data/lib/generators/dummy/templates/models/node.rb +10 -0
  185. data/lib/generators/dummy/templates/models/publisher.rb +9 -0
  186. data/lib/generators/dummy/templates/models/text_page.rb +5 -0
  187. data/lib/generators/dummy/templates/views/contacts/show.html.haml +1 -0
  188. data/lib/generators/dummy/templates/views/home_pages/show.haml +1 -0
  189. data/lib/generators/dummy/templates/views/layouts/application.html.haml +22 -0
  190. data/lib/generators/dummy/templates/views/text_pages/show.haml +1 -0
  191. data/lib/generators/releaf/install_generator.rb +93 -0
  192. data/lib/generators/releaf/templates/initializers/haml.rb +1 -0
  193. data/lib/generators/releaf/templates/initializers/releaf.rb +30 -0
  194. data/lib/generators/releaf/templates/migrations/create_releaf_nodes.rb +28 -0
  195. data/lib/generators/releaf/templates/migrations/create_releaf_permissions.rb +12 -0
  196. data/lib/generators/releaf/templates/migrations/create_releaf_richtext_attachments.rb +12 -0
  197. data/lib/generators/releaf/templates/migrations/create_releaf_roles.rb +9 -0
  198. data/lib/generators/releaf/templates/migrations/create_releaf_settings.rb +17 -0
  199. data/lib/generators/releaf/templates/migrations/create_releaf_translations.rb +21 -0
  200. data/lib/generators/releaf/templates/migrations/create_releaf_users.rb +52 -0
  201. data/lib/generators/releaf/templates/models/node.rb +3 -0
  202. data/lib/generators/releaf/templates/seeds/seeds.rb +54 -0
  203. data/lib/releaf/core/application.rb +17 -0
  204. data/lib/releaf/core/builders_autoload.rb +27 -0
  205. data/lib/releaf/core/component.rb +9 -0
  206. data/lib/releaf/core/configuration.rb +101 -0
  207. data/lib/releaf/core/engine.rb +35 -0
  208. data/lib/releaf/core/exceptions.rb +38 -0
  209. data/lib/releaf/core/route_mapper.rb +59 -0
  210. data/lib/releaf/core/settings_ui_component.rb +7 -0
  211. data/lib/releaf/core/validation_error_codes.rb +36 -0
  212. data/lib/releaf/version.rb +3 -0
  213. data/lib/releaf-core.rb +14 -0
  214. data/lib/tasks/releaf_tasks.rake +4 -0
  215. data/releaf-core.gemspec +35 -0
  216. data/spec/builders/builders/association_reflector_spec.rb +138 -0
  217. data/spec/builders/builders/base_spec.rb +276 -0
  218. data/spec/builders/builders/collection_spec.rb +18 -0
  219. data/spec/builders/builders/confirm_destroy_dialog_builder_spec.rb +71 -0
  220. data/spec/builders/builders/confirm_dialog_builder_spec.rb +105 -0
  221. data/spec/builders/builders/edit_builder_spec.rb +215 -0
  222. data/spec/builders/builders/form_builder_spec.rb +562 -0
  223. data/spec/builders/builders/index_builder_spec.rb +345 -0
  224. data/spec/builders/builders/orderer_spec.rb +22 -0
  225. data/spec/builders/builders/page/header_builder_spec.rb +143 -0
  226. data/spec/builders/builders/page/layout_builder_spec.rb +73 -0
  227. data/spec/builders/builders/page/menu_builder_spec.rb +160 -0
  228. data/spec/builders/builders/pagination_builder_spec.rb +330 -0
  229. data/spec/builders/builders/resource_dialog_spec.rb +21 -0
  230. data/spec/builders/builders/resource_view_spec.rb +158 -0
  231. data/spec/builders/builders/show_builder_spec.rb +7 -0
  232. data/spec/builders/builders/table_builder_spec.rb +638 -0
  233. data/spec/builders/builders/template_spec.rb +12 -0
  234. data/spec/builders/builders/toolbox_builder_spec.rb +67 -0
  235. data/spec/builders/builders/toolbox_spec.rb +48 -0
  236. data/spec/builders/builders/view_spec.rb +281 -0
  237. data/spec/builders/builders_spec.rb +134 -0
  238. data/spec/builders/core/settings/form_builder_spec.rb +69 -0
  239. data/spec/builders/core/settings/table_builder_spec.rb +21 -0
  240. data/spec/controllers/concerns/releaf/richtext_attachments_spec.rb +51 -0
  241. data/spec/controllers/releaf/base_controller_spec.rb +447 -0
  242. data/spec/controllers/releaf/core/settings_controller_spec.rb +31 -0
  243. data/spec/features/ajaxbox_spec.rb +111 -0
  244. data/spec/features/authorization_spec.rb +50 -0
  245. data/spec/features/dragonfly_integration_spec.rb +24 -0
  246. data/spec/features/edit_actions_spec.rb +142 -0
  247. data/spec/features/errors_spec.rb +29 -0
  248. data/spec/features/index_actions_spec.rb +85 -0
  249. data/spec/features/index_table_spec.rb +32 -0
  250. data/spec/features/menu_spec.rb +71 -0
  251. data/spec/features/richtext_attachments_spec.rb +64 -0
  252. data/spec/features/richtext_embed_spec.rb +29 -0
  253. data/spec/features/richtext_spec.rb +19 -0
  254. data/spec/features/search_spec.rb +825 -0
  255. data/spec/features/settings_spec.rb +38 -0
  256. data/spec/features/title_spec.rb +13 -0
  257. data/spec/fixtures/common_fields.yml +17 -0
  258. data/spec/fixtures/cs.png +0 -0
  259. data/spec/fixtures/time.formats.xlsx +0 -0
  260. data/spec/fixtures/unicorn.jpg +0 -0
  261. data/spec/helpers/application_helper_spec.rb +75 -0
  262. data/spec/helpers/button_helper_spec.rb +146 -0
  263. data/spec/lib/releaf/core/application_spec.rb +42 -0
  264. data/spec/lib/releaf/core/assets_resolver_spec.rb +113 -0
  265. data/spec/lib/releaf/core/configuration_spec.rb +230 -0
  266. data/spec/lib/releaf/core/default_searchable_fields_spec.rb +161 -0
  267. data/spec/lib/releaf/core/error_formatter_spec.rb +242 -0
  268. data/spec/lib/releaf/core/item_orderer_spec.rb +142 -0
  269. data/spec/lib/releaf/core/resource_base_spec.rb +174 -0
  270. data/spec/lib/releaf/core/resource_fields_spec.rb +12 -0
  271. data/spec/lib/releaf/core/resource_params_spec.rb +117 -0
  272. data/spec/lib/releaf/core/resource_table_fields_spec.rb +18 -0
  273. data/spec/lib/releaf/core/resource_utilities_spec.rb +87 -0
  274. data/spec/lib/releaf/core/responders/access_denied_responder_spec.rb +12 -0
  275. data/spec/lib/releaf/core/responders/after_save_responder_spec.rb +102 -0
  276. data/spec/lib/releaf/core/responders/confirm_destroy_responder_spec.rb +26 -0
  277. data/spec/lib/releaf/core/responders/destroy_responder_spec.rb +30 -0
  278. data/spec/lib/releaf/core/responders/error_responder_spec.rb +26 -0
  279. data/spec/lib/releaf/core/responders/feature_disabled_responder_spec.rb +12 -0
  280. data/spec/lib/releaf/core/responders/page_not_found_responder_spec.rb +12 -0
  281. data/spec/lib/releaf/core/responders_spec.rb +60 -0
  282. data/spec/lib/releaf/core/template_field_type_mapper_spec.rb +311 -0
  283. data/spec/lib/validation_error_codes_spec.rb +56 -0
  284. data/spec/misc/factories_spec.rb +43 -0
  285. data/spec/models/settings_spec.rb +58 -0
  286. data/spec/routing/route_mapper_spec.rb +185 -0
  287. data/spec/rspec_helpers/test_helpers_spec.rb +20 -0
  288. metadata +657 -0
@@ -0,0 +1,40 @@
1
+ module Releaf::Tags
2
+ module AssociatedSetField
3
+ def releaf_associated_set_field(name, input: {}, label: {}, field: {}, options: {}, &block)
4
+ options = {field: {type: "associated-set"}}.deep_merge(options)
5
+ content = releaf_associated_set_content(name, input: input, options: options)
6
+ input_wrapper_with_label(name, content, label: label, field: field, options: options, &block)
7
+ end
8
+
9
+ def releaf_associated_set_content(name, input: {}, options: {})
10
+ association_options = options[:association]
11
+ association = object.send(name)
12
+ key_field = association_options[:field]
13
+
14
+ list = []
15
+
16
+ association_options[:items].each_pair do|value, label_text|
17
+ item = association.find_by(key_field => value) || association.build(key_field => value)
18
+
19
+ list << fields_for(name, item, relation_name: name, builder: self.class) do |builder|
20
+ builder.releaf_associated_set_item(association_options, label_text)
21
+ end
22
+ end
23
+
24
+ safe_join do
25
+ list
26
+ end
27
+ end
28
+
29
+
30
+ def releaf_associated_set_item(association_options, label_text)
31
+ wrapper(class: "type-associated-set-item") do
32
+ [hidden_field(:_destroy, value: object.new_record?, class: "destroy"),
33
+ check_box(association_options[:field], {class: "keep", name: "keep"}, (object.send(association_options[:field]) if object.persisted?)),
34
+ label(association_options[:field], label_text),
35
+ hidden_field(association_options[:field])
36
+ ]
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,8 @@
1
+ module Releaf::Builders::Template
2
+ attr_accessor :template
3
+
4
+ def initialize(template)
5
+ self.template = template
6
+ end
7
+
8
+ end
@@ -0,0 +1,23 @@
1
+ module Releaf::Builders::Toolbox
2
+ def toolbox(resource, extra_params = {})
3
+ return '' if resource.new_record?
4
+
5
+ url = url_for({action: :toolbox, id: resource.id, context: action_name}.merge(extra_params))
6
+
7
+ tag(:div, class: "toolbox", data: {url: url}) do
8
+ [toolbox_button, toolbox_menu]
9
+ end
10
+ end
11
+
12
+ def toolbox_menu
13
+ tag(:menu, class: %w(toolbox-items), type: "toolbar") do
14
+ [icon("caret-up"), tag(:ul, "")]
15
+ end
16
+ end
17
+
18
+ def toolbox_button
19
+ tag(:button, class: %w(button trigger only-icon), type: "button", title: t("Tools")) do
20
+ icon("ellipsis-v")
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,27 @@
1
+ class Releaf::Builders::ToolboxBuilder
2
+ include Releaf::Builders::Base
3
+ include Releaf::Builders::Template
4
+ include Releaf::Builders::Resource
5
+
6
+ def output
7
+ safe_join do
8
+ items.map do |item|
9
+ tag('li', item)
10
+ end
11
+ end
12
+ end
13
+
14
+ def items
15
+ list = []
16
+ list << destroy_confirmation_link if feature_available? :destroy
17
+ list
18
+ end
19
+
20
+ def destroy_confirmation_link
21
+ button(t("Delete"), nil, class: %w(ajaxbox danger), href: destroy_confirmation_url, data: {modal: true})
22
+ end
23
+
24
+ def destroy_confirmation_url
25
+ url_for(action: :confirm_destroy, id: resource.id, index_url: index_url)
26
+ end
27
+ end
@@ -0,0 +1,132 @@
1
+ module Releaf::Builders::View
2
+ include Releaf::Builders::Base
3
+ include Releaf::Builders::Template
4
+
5
+ def output
6
+ safe_join do
7
+ list = []
8
+ list << header unless dialog?
9
+ list << section
10
+ end
11
+ end
12
+
13
+ def dialog?
14
+ controller.ajax?
15
+ end
16
+
17
+ def dialog_name
18
+ self.class.name.split("::").last.gsub(/(Dialog)?Builder$/, "").underscore.dasherize
19
+ end
20
+
21
+ def header
22
+ tag(:header) do
23
+ [breadcrumbs, flash_notices, header_extras]
24
+ end
25
+ end
26
+
27
+ def section
28
+ tag(:section, section_attributes) do
29
+ section_blocks
30
+ end
31
+ end
32
+
33
+ def section_attributes
34
+ attributes = {}
35
+ attributes[:class] = ["dialog", dialog_name] if dialog?
36
+ attributes
37
+ end
38
+
39
+ def breadcrumbs
40
+ breadcrumb_items = template_variable("breadcrumbs")
41
+ return unless breadcrumb_items.present?
42
+
43
+ tag(:nav) do
44
+ tag(:ul, class: "breadcrumbs") do
45
+ safe_join do
46
+ last_item = breadcrumb_items.last
47
+ breadcrumb_items.each.collect do |item, index|
48
+ breadcrumb_item(item, item == last_item)
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ def breadcrumb_item(item, last)
56
+ content = []
57
+ if item[:url].present?
58
+ content << tag(:a, item[:name], href: item[:url])
59
+ else
60
+ content << item[:name]
61
+ end
62
+
63
+ content << icon("chevron-right") unless last
64
+
65
+ tag(:li) do
66
+ safe_join{ content }
67
+ end
68
+ end
69
+
70
+ def flash_notices
71
+ safe_join do
72
+ flash.collect{|name, item| flash_item(name, item) }
73
+ end
74
+ end
75
+
76
+ def flash_item(name, item)
77
+ tag(:div, class: "flash", 'data-type' => name, :'data-id' => (item.is_a? (Hash)) && (item.has_key? "id") ? item["id"] : nil) do
78
+ item.is_a?(Hash) ? item["message"] : item
79
+ end
80
+ end
81
+
82
+ def header_extras; end
83
+
84
+ def section_blocks
85
+ [section_header, section_body, section_footer]
86
+ end
87
+
88
+ def section_header
89
+ tag(:header) do
90
+ [tag(:h1, section_header_text), section_header_extras]
91
+ end
92
+ end
93
+
94
+ def section_header_text; end
95
+ def section_header_extras; end
96
+ def section_body; end
97
+
98
+ def section_footer
99
+ tag(:footer, class: section_footer_class) do
100
+ footer_tools
101
+ end
102
+ end
103
+
104
+ def section_footer_class
105
+ :main unless dialog?
106
+ end
107
+
108
+ def footer_tools
109
+ tag(:div, class: "tools") do
110
+ footer_blocks
111
+ end
112
+ end
113
+
114
+ def footer_blocks
115
+ [footer_primary_block, footer_secondary_block]
116
+ end
117
+
118
+ def footer_primary_block
119
+ tag(:div, class: "primary") do
120
+ footer_primary_tools
121
+ end
122
+ end
123
+
124
+ def footer_secondary_block
125
+ tag(:div, class: "secondary") do
126
+ footer_secondary_tools
127
+ end
128
+ end
129
+
130
+ def footer_primary_tools; end
131
+ def footer_secondary_tools; end
132
+ end
@@ -0,0 +1,38 @@
1
+ class Releaf::Builders
2
+ def self.builder_class(scopes, type)
3
+ (scopes + inherited_builder_scopes).each do |scope|
4
+ builder_class = builder_class_at_scope(scope, type)
5
+ return builder_class if builder_class
6
+ end
7
+
8
+ raise ArgumentError, "unexisting builder (type: #{type}; scopes: #{scopes.join(", ")})"
9
+ end
10
+
11
+ def self.builder_class_at_scope(scope, type)
12
+ builder_class_name = "#{scope}::#{type.to_s.camelize}Builder"
13
+
14
+ if constant_defined_at_scope?(scope, Object) && constant_defined_at_scope?(builder_class_name, scope.constantize)
15
+ builder_class_name.constantize
16
+ end
17
+ end
18
+
19
+ def self.constant_defined_at_scope?(mapping, at)
20
+ constant_defined = false
21
+
22
+ begin
23
+ constant_defined = at.const_get(mapping).present? && mapping.constantize == at.const_get(mapping)
24
+ rescue NameError => error
25
+ raise unless constant_name_error?(error.message, mapping)
26
+ end
27
+
28
+ constant_defined
29
+ end
30
+
31
+ def self.constant_name_error?(error_message, mapping)
32
+ (error_message =~ /#{mapping}$/).present?
33
+ end
34
+
35
+ def self.inherited_builder_scopes
36
+ (ancestors.grep(Class) - [Object, BasicObject]).collect{|c| c.name }
37
+ end
38
+ end
@@ -0,0 +1,21 @@
1
+ module Releaf::Core::Settings
2
+ class FormBuilder < Releaf::Builders::FormBuilder
3
+ def field_names
4
+ [:value]
5
+ end
6
+
7
+ def render_value
8
+ method_name = "releaf_#{settings_field_type}_field"
9
+ send(method_name, :value, options: { label: { label_text: settings_field_label_text }})
10
+ end
11
+
12
+ def settings_field_label_text
13
+ label_text = Releaf::Settings.registry[object.var][:description]
14
+ label_text.present? ? t(label_text, scope: "settings") : "Value"
15
+ end
16
+
17
+ def settings_field_type
18
+ Releaf::Settings.registry[object.var].fetch(:type, :text)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,11 @@
1
+ module Releaf::Core::Settings
2
+ class TableBuilder < Releaf::Builders::TableBuilder
3
+ def column_names
4
+ [:var, :value, :updated_at]
5
+ end
6
+
7
+ def value_content(resource)
8
+ resource.value.to_s
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,42 @@
1
+ module Releaf
2
+ module Breadcrumbs
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ before_filter :build_breadcrumbs
7
+ end
8
+
9
+ def build_breadcrumbs
10
+ @breadcrumbs = [home_breadcrumb, controller_breadcrumb].compact
11
+ end
12
+
13
+ def home_breadcrumb
14
+ { name: I18n.t('Home', scope: 'admin.breadcrumbs'), url: releaf_root_path }
15
+ end
16
+
17
+ def controller_breadcrumb
18
+ controller_params = Releaf.application.config.controllers[self.class.name.sub(/Controller$/, '').underscore]
19
+ if controller_params
20
+ {
21
+ name: I18n.t(controller_params[:name], scope: "admin.controllers"),
22
+ url: send("#{controller_params[:url_helper]}_path")
23
+ }
24
+ end
25
+ end
26
+
27
+ def add_resource_breadcrumb resource, url = nil
28
+ if resource.new_record?
29
+ name= I18n.t('New record', scope: 'admin.breadcrumbs')
30
+ url = url_for(action: :new, only_path: true) if url.nil?
31
+ else
32
+ if resource.respond_to?(:to_text)
33
+ name = resource.send(:to_text)
34
+ else
35
+ name = I18n.t('Edit record', scope: 'admin.breadcrumbs')
36
+ end
37
+ url = url_for(action: :edit, id: resource.id, only_path: true) if url.nil?
38
+ end
39
+ @breadcrumbs << { name: name, url: url }
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,20 @@
1
+ module Releaf::RichtextAttachments
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ skip_before_action :verify_authenticity_token, only: [:create_releaf_richtext_attachment]
6
+ end
7
+
8
+ def releaf_richtext_attachment_upload_url
9
+ begin
10
+ url_for(action: :create_releaf_richtext_attachment)
11
+ rescue ::ActionController::UrlGenerationError
12
+ nil
13
+ end
14
+ end
15
+
16
+ def create_releaf_richtext_attachment
17
+ return unless params[:upload]
18
+ @resource = Releaf::RichtextAttachment.create!(file_type: params[:upload].content_type, file: params[:upload])
19
+ end
20
+ end
@@ -0,0 +1,458 @@
1
+ module Releaf
2
+ class FeatureDisabled < StandardError; end
3
+
4
+ class BaseController < ActionController::Base
5
+ respond_to :html
6
+ respond_to :json, only: [:create, :update]
7
+ protect_from_forgery
8
+ include Releaf.application.config.access_control_module
9
+ include Releaf::Breadcrumbs
10
+ include Releaf::RichtextAttachments
11
+ include Releaf::Core::Responders
12
+
13
+ before_filter :manage_ajax, :setup, :verify_feature_availability!
14
+
15
+ rescue_from Releaf::Core::AccessDenied, with: :access_denied
16
+ rescue_from Releaf::FeatureDisabled, with: :feature_disabled
17
+
18
+ layout :layout
19
+
20
+ helper_method \
21
+ :form_options,
22
+ :table_options,
23
+ :ajax?,
24
+ :controller_scope_name,
25
+ :current_url,
26
+ :active_view,
27
+ :index_url,
28
+ :page_title,
29
+ :resource_class,
30
+ :feature_available?,
31
+ :builder_class,
32
+ :searchable_fields
33
+
34
+ def search(text)
35
+ return if text.blank?
36
+ return if searchable_fields.blank?
37
+ @collection = searcher_class.prepare(relation: @collection, fields: searchable_fields, text: text)
38
+ end
39
+
40
+ def searcher_class
41
+ Releaf::Core::Search
42
+ end
43
+
44
+ def index
45
+ prepare_index
46
+ respond_with(@collection)
47
+ end
48
+
49
+ def new
50
+ prepare_new
51
+ respond_with(@resource)
52
+ end
53
+
54
+ def show
55
+ if feature_available?(:show)
56
+ prepare_show
57
+ else
58
+ redirect_to url_for(action: 'edit', id: params[:id])
59
+ end
60
+ end
61
+
62
+ def edit
63
+ prepare_edit
64
+ respond_with(@resource)
65
+ end
66
+
67
+ def create
68
+ prepare_create
69
+ @resource.save
70
+ respond_with(@resource, location: (success_url if @resource.persisted?), redirect: true)
71
+ end
72
+
73
+ def update
74
+ prepare_update
75
+ @resource.update_attributes(resource_params)
76
+ respond_with(@resource, location: success_url)
77
+ end
78
+
79
+ def confirm_destroy
80
+ prepare_destroy
81
+ @restricted_relations = Releaf::Core::ResourceUtilities.restricted_relations(@resource)
82
+ respond_with(@resource, destroyable: destroyable?)
83
+ end
84
+
85
+ def toolbox
86
+ prepare_toolbox
87
+ respond_with(@resource)
88
+ end
89
+
90
+ def destroy
91
+ prepare_destroy
92
+ @resource.destroy if destroyable?
93
+ respond_with(@resource, location: index_url)
94
+ end
95
+
96
+ # Check if @resource has existing restrict relation and it can be deleted
97
+ #
98
+ # @return boolean true or false
99
+ def destroyable?
100
+ Releaf::Core::ResourceUtilities.destroyable?(@resource)
101
+ end
102
+
103
+ # Helper methods ##############################################################################
104
+
105
+ # Returns current url without internal params
106
+ #
107
+ # @return String
108
+ def current_url
109
+ @current_url ||= [request.path, (request.query_parameters.to_query if request.query_parameters.present?)].compact.join("?")
110
+ end
111
+
112
+ # Returns index url for current request
113
+ #
114
+ # @return String
115
+ def index_url
116
+ if @index_url.nil?
117
+ # use current url
118
+ if action_name == "index"
119
+ @index_url = current_url
120
+ # use from get params
121
+ elsif params[:index_url].present?
122
+ @index_url = params[:index_url]
123
+ # fallback to index view
124
+ else
125
+ @index_url = url_for(action: 'index')
126
+ end
127
+ end
128
+
129
+ @index_url
130
+ end
131
+
132
+ # Tries to return resource class.
133
+ #
134
+ # If it fails to return proper resource class for your controller, or your
135
+ # controllers name has no relation to resource class name, then simply
136
+ # override this method to return class that you want.
137
+ #
138
+ # @return class
139
+ def self.resource_class
140
+ self.name.split('::', 2).last.sub(/Controller$/, '').classify.constantize
141
+ end
142
+
143
+ # Tries to return resource class.
144
+ #
145
+ # If it fails to return proper resource class for your controller, or your
146
+ # controllers name has no relation to resource class name, then simply
147
+ # override this method to return class that you want.
148
+ #
149
+ # @return class
150
+ def resource_class
151
+ @resource_class ||= self.class.resource_class
152
+ end
153
+
154
+ # Returns action > view translation hash
155
+ # @return Hash
156
+ def action_views
157
+ {
158
+ new: :edit,
159
+ update: :edit,
160
+ create: :edit,
161
+ }
162
+ end
163
+
164
+ # Returns generic view name for given action
165
+ # @return String
166
+ def action_view(_action_name)
167
+ action_views[_action_name.to_sym] || _action_name
168
+ end
169
+
170
+ # Returns generic view name for current action
171
+ # @return String
172
+ def active_view
173
+ action_view(action_name)
174
+ end
175
+
176
+ def form_url(form_type, object)
177
+ url_for(action: object.new_record? ? 'create' : 'update', id: object.id)
178
+ end
179
+
180
+ def form_attributes(form_type, object, object_name)
181
+ action = object.respond_to?(:persisted?) && object.persisted? ? :edit : :new
182
+ action_object_name = "#{action}-#{object_name}"
183
+ classes = [ action_object_name ]
184
+ classes << "has-error" if object.errors.any?
185
+ {
186
+ multipart: true,
187
+ id: action_object_name,
188
+ class: classes,
189
+ data: {
190
+ "remote" => true,
191
+ "remote-validation" => true,
192
+ "type" => :json,
193
+ },
194
+ novalidate: ''
195
+ }
196
+ end
197
+
198
+
199
+
200
+ def builder_class(builder_type)
201
+ Releaf::Builders.builder_class(builder_scopes, builder_type)
202
+ end
203
+
204
+ def application_builder_scope
205
+ [application_scope, "Builders"].reject(&:blank?).join("::")
206
+ end
207
+
208
+ def application_scope
209
+ scope = Releaf.application.config.mount_location.capitalize
210
+ scope if scope.present? && Releaf::Builders.constant_defined_at_scope?(scope, Object)
211
+ end
212
+
213
+ def builder_scopes
214
+ [self.class.name.gsub(/Controller$/, ""), application_builder_scope]
215
+ end
216
+
217
+ def form_options(form_type, object, object_name)
218
+ {
219
+ builder: builder_class(:form),
220
+ as: object_name,
221
+ url: form_url(form_type, object),
222
+ html: form_attributes(form_type, object, object_name)
223
+ }
224
+ end
225
+
226
+ def table_options
227
+ {
228
+ builder: builder_class(:table),
229
+ toolbox: feature_available?(:toolbox)
230
+ }
231
+ end
232
+
233
+ # return contoller translation scope name for using
234
+ # with I18.translation call within hash params
235
+ # ex. t("save", scope: controller_scope_name)
236
+ def controller_scope_name
237
+ @controller_scope_name ||= 'admin.' + self.class.name.sub(/Controller$/, '').underscore.gsub('/', '_')
238
+ end
239
+
240
+ def feature_available? feature
241
+ @features[feature].present?
242
+ end
243
+
244
+ def page_title
245
+ I18n.t(params[:controller], scope: "admin.controllers") + " - " + Rails.application.class.parent_name
246
+ end
247
+
248
+ def render_notification(status, success_message_key: "#{params[:action]} succeeded", failure_message_key: "#{params[:action]} failed", now: false)
249
+ if now == true
250
+ flash_target = flash.now
251
+ else
252
+ flash_target = flash
253
+ end
254
+
255
+ if status
256
+ flash_target["success"] = { "id" => "resource_status", "message" => I18n.t(success_message_key, scope: notice_scope_name) }
257
+ else
258
+ flash_target["error"] = { "id" => "resource_status", "message" => I18n.t(failure_message_key, scope: notice_scope_name) }
259
+ end
260
+ end
261
+
262
+ def prepare_index
263
+ # load resource only if they are not loaded yet
264
+ @collection = resources unless collection_given?
265
+
266
+ search(params[:search])
267
+
268
+ unless @resources_per_page.nil?
269
+ @collection = @collection.page( params[:page] ).per_page( @resources_per_page )
270
+ end
271
+ end
272
+
273
+ def prepare_new
274
+ # load resource only if is not initialized yet
275
+ new_resource unless resource_given?
276
+ add_resource_breadcrumb(@resource)
277
+ end
278
+
279
+ def prepare_create
280
+ # load resource only if is not initialized yet
281
+ new_resource unless resource_given?
282
+ @resource.assign_attributes(resource_params)
283
+ end
284
+
285
+ def prepare_show
286
+ prepare_resource_view
287
+ end
288
+
289
+ def prepare_edit
290
+ prepare_resource_view
291
+ end
292
+
293
+ def prepare_resource_view
294
+ # load resource only if is not loaded yet
295
+ load_resource unless resource_given?
296
+ add_resource_breadcrumb(@resource)
297
+ end
298
+
299
+ def prepare_update
300
+ # load resource only if is not loaded yet
301
+ load_resource unless resource_given?
302
+ end
303
+
304
+ def prepare_destroy
305
+ load_resource
306
+ end
307
+
308
+ def prepare_toolbox
309
+ load_resource
310
+ end
311
+
312
+ def new_resource
313
+ @resource = resource_class.new
314
+ end
315
+
316
+ def load_resource
317
+ @resource = resource_class.find(params[:id])
318
+ end
319
+
320
+ def verify_feature_availability!
321
+ feature = action_feature(params[:action])
322
+ raise FeatureDisabled, feature.to_s if (feature.present? && !feature_available?(feature))
323
+ end
324
+
325
+ def action_feature action
326
+ action_features[action]
327
+ end
328
+
329
+ def action_features
330
+ {
331
+ index: :index,
332
+ new: :create,
333
+ create: :create,
334
+ show: (feature_available?(:show) ? :show : :edit),
335
+ edit: :edit,
336
+ update: :edit,
337
+ confirm_destroy: :destroy,
338
+ destroy: :destroy
339
+ }.with_indifferent_access
340
+ end
341
+
342
+ # Returns true if @resource is assigned (even if it's nil)
343
+ def resource_given?
344
+ !!defined? @resource
345
+ end
346
+
347
+ # Returns true if @collection is assigned (even if it's nil)
348
+ def collection_given?
349
+ !!defined? @collection
350
+ end
351
+
352
+ # Returns notice scope name
353
+ def notice_scope_name
354
+ 'notices.' + controller_scope_name
355
+ end
356
+
357
+ # Return ActiveRecord::Relation used in index
358
+ #
359
+ # @return ActiveRecord::Relation
360
+ def resources
361
+ resource_class.all
362
+ end
363
+
364
+ def required_params
365
+ params.require(:resource)
366
+ end
367
+
368
+ # Called before each request by before_filter.
369
+ # It sets various instance variables, that are later used in views and # controllers
370
+ #
371
+ # == Defines
372
+ # @features::
373
+ # Hash with symbol keys and boolean values. Each key represents action
374
+ # (currently only `:edit`, `:create`, `:destroy` are supported). If one
375
+ # of features is disabled, then routing to it will raise <tt>Releaf::FeatureDisabled</tt>
376
+ # error
377
+ #
378
+ # @resources_per_page::
379
+ # Integer - sets the number of resources to display on `#index` view
380
+ #
381
+ # To change controller settings `setup` method should be overriden like this
382
+ #
383
+ # @example
384
+ # def setup
385
+ # super
386
+ # @features[:edit] = false
387
+ # @resources_per_page = 20
388
+ # end
389
+ def setup
390
+ @features = {
391
+ show: false,
392
+ edit: true,
393
+ create: true,
394
+ create_another: true,
395
+ destroy: true,
396
+ index: true,
397
+ toolbox: true
398
+ }
399
+ @panel_layout = true
400
+ @resources_per_page = 40
401
+ end
402
+
403
+ def searchable_fields
404
+ @searchable_fields ||= Releaf::Core::DefaultSearchableFields.new(resource_class).find
405
+ end
406
+
407
+ def resource_params
408
+ required_params.permit(*permitted_params)
409
+ end
410
+
411
+ # Returns which resource attributes can be updated with mass assignment.
412
+ #
413
+ # The resulting array will be passed to strong_parameters ``permit``
414
+ def permitted_params
415
+ Releaf::Core::ResourceParams.new(resource_class).values
416
+ end
417
+
418
+ # Returns url to redirect after successul resource create/update actions
419
+ #
420
+ # @return [String] url
421
+ def success_url
422
+ if create_another?
423
+ url_for(action: 'new')
424
+ else
425
+ url_for(action: 'edit', id: @resource.id, index_url: index_url)
426
+ end
427
+ end
428
+
429
+ def create_another?
430
+ params[:after_save] == "create_another" && feature_available?(:create_another)
431
+ end
432
+
433
+ def feature_disabled exception
434
+ @feature = exception.message
435
+ respond_with(nil, responder: action_responder(:feature_disabled))
436
+ end
437
+
438
+ def access_denied
439
+ respond_with(nil, responder: action_responder(:access_denied))
440
+ end
441
+
442
+ def ajax?
443
+ @_ajax || false
444
+ end
445
+
446
+ def layout
447
+ ajax? ? false : "releaf/admin"
448
+ end
449
+
450
+ def manage_ajax
451
+ @_ajax = params.has_key? :ajax
452
+ if @_ajax
453
+ request.query_parameters.delete(:ajax)
454
+ params.delete(:ajax)
455
+ end
456
+ end
457
+ end
458
+ end