releaf-core 0.2.1

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 (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