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,18 @@
1
+ require "rails_helper"
2
+
3
+ describe Releaf::Builders::Collection, type: :module do
4
+ class CollectionIncluder
5
+ include Releaf::Builders::Base
6
+ include Releaf::Builders::Template
7
+ include Releaf::Builders::Collection
8
+ end
9
+ class CollectionTestHelper < ActionView::Base
10
+ end
11
+
12
+ it "it assigns template collection instance variable to instance 'collection' accessor on initialization" do
13
+ template = CollectionTestHelper.new
14
+ template.instance_variable_set("@collection", "x")
15
+ subject = CollectionIncluder.new(template)
16
+ expect(subject.collection).to eq("x")
17
+ end
18
+ end
@@ -0,0 +1,71 @@
1
+ require "rails_helper"
2
+
3
+ describe Releaf::Builders::ConfirmDestroyDialogBuilder, type: :class do
4
+ class ConfirmDestroyDialogTestHelper < ActionView::Base
5
+ include FontAwesome::Rails::IconHelper
6
+ include Releaf::ButtonHelper
7
+ include Releaf::ApplicationHelper
8
+
9
+ def protect_against_forgery?
10
+ true
11
+ end
12
+
13
+ def form_authenticity_token
14
+ "xxx"
15
+ end
16
+
17
+ def request_forgery_protection_token
18
+ "yyy"
19
+ end
20
+ end
21
+
22
+ let(:template){ ConfirmDestroyDialogTestHelper.new }
23
+ let(:object){ Book.new(id: 99, title: "book title") }
24
+ let(:subject){ described_class.new(template) }
25
+
26
+ before do
27
+ subject.resource = object
28
+ allow(subject.template).to receive(:controller).and_return(Releaf::BaseController.new)
29
+ allow(subject.controller).to receive(:index_url).and_return("y")
30
+ end
31
+
32
+ describe "#question_content" do
33
+ it "localized destroy question" do
34
+ allow(subject).to receive(:t).with("Do you want to delete the following object?").and_return("xx")
35
+ expect(subject.question_content).to eq("xx")
36
+ end
37
+ end
38
+
39
+ describe "#description_content" do
40
+ it "returns `resource_to_text` value" do
41
+ allow(subject).to receive(:resource_to_text).with(object).and_return("xx")
42
+ expect(subject.description_content).to eq("xx")
43
+ end
44
+ end
45
+
46
+ describe "#section_body" do
47
+ it "returns destroy description content" do
48
+ content = '<div class="body"><i class="fa fa-trash-o"></i><div class="question">Do you want to delete the following object?</div><div class="description">book title</div></div>'
49
+ expect(subject.section_body).to eq(content)
50
+ end
51
+ end
52
+
53
+ describe "#confirm_method" do
54
+ it "returns :delete" do
55
+ expect(subject.confirm_method).to eq(:delete)
56
+ end
57
+ end
58
+
59
+ describe "#icon_name" do
60
+ it "returns trash icon" do
61
+ expect(subject.icon_name).to eq("trash-o")
62
+ end
63
+ end
64
+
65
+ describe "#confirm_url" do
66
+ it "returns resource destroy url" do
67
+ allow(subject.template).to receive(:url_for).with(action: 'destroy', id: 99, index_url: "y").and_return("x")
68
+ expect(subject.confirm_url).to eq("x")
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,105 @@
1
+ require "rails_helper"
2
+
3
+ describe Releaf::Builders::ConfirmDialogBuilder, type: :class do
4
+ class ConfirmDestroyDialogTestHelper < ActionView::Base
5
+ include FontAwesome::Rails::IconHelper
6
+ include Releaf::ButtonHelper
7
+ include Releaf::ApplicationHelper
8
+
9
+ def protect_against_forgery?
10
+ true
11
+ end
12
+
13
+ def form_authenticity_token
14
+ "xxx"
15
+ end
16
+
17
+ def request_forgery_protection_token
18
+ "yyy"
19
+ end
20
+ end
21
+
22
+ class ConfirmDialogBuilderInheriter < Releaf::Builders::ConfirmDialogBuilder
23
+ def confirm_url; end
24
+ def icon_name; end
25
+ def question_content; end
26
+ def description_content; end
27
+ def confirm_method; end
28
+ end
29
+
30
+ let(:template){ ConfirmDestroyDialogTestHelper.new }
31
+ let(:object){ Book.new(id: 99, title: "book title") }
32
+ let(:subject){ ConfirmDialogBuilderInheriter.new(template) }
33
+
34
+ before do
35
+ subject.resource = object
36
+ allow(subject.template).to receive(:controller).and_return(Releaf::BaseController.new)
37
+ allow(subject.controller).to receive(:index_url).and_return("y")
38
+ end
39
+
40
+ describe "#section_body" do
41
+ it "returns destroy description content" do
42
+ allow(subject).to receive(:section_body_blocks).and_return(["a", "b"])
43
+ content = '<div class="body">ab</div>'
44
+ expect(subject.section_body).to eq(content)
45
+ end
46
+ end
47
+
48
+ describe "#section_body_blocks" do
49
+ it "returns section body blocks" do
50
+ allow(subject).to receive(:icon_name).and_return("circle")
51
+ allow(subject).to receive(:question_content).and_return("question")
52
+ allow(subject).to receive(:description_content).and_return("description")
53
+
54
+ allow(subject).to receive(:icon).with("circle").and_return("ikon")
55
+ allow(subject).to receive(:tag).with(:div, "question", class: "question").and_return("question")
56
+ allow(subject).to receive(:tag).with(:div, "description", class: "description").and_return("description")
57
+ expect(subject.section_body_blocks).to eq(["ikon", "question", "description"])
58
+ end
59
+ end
60
+
61
+ describe "#section_attributes" do
62
+ it "adds `confirm` class" do
63
+ expect(subject.section_attributes[:class]).to include("confirm")
64
+ end
65
+ end
66
+
67
+ describe "#footer_primary_tools" do
68
+ it "returns array with cancel and confirm forms" do
69
+ allow(subject).to receive(:cancel_button).and_return("a")
70
+ allow(subject).to receive(:confirm_button).and_return("b")
71
+ expect(subject.footer_primary_tools).to eq(["a", "b"])
72
+ end
73
+ end
74
+
75
+ describe "#confirm_form_options" do
76
+ it "returns confirm form options" do
77
+ allow(subject).to receive(:confirm_url).and_return("x")
78
+ allow(subject).to receive(:confirm_method).and_return("tt")
79
+ expect(subject.confirm_form_options).to eq(builder: Releaf::Builders::FormBuilder, url: "x", as: :resource, method: "tt")
80
+ end
81
+ end
82
+
83
+ describe "#confirm_button" do
84
+ it "returns confirm button" do
85
+ allow(subject).to receive(:t).with("Yes").and_return("Yess")
86
+ allow(subject).to receive(:button).with("Yess", "check", class: "danger", type: "submit").and_return("x")
87
+ expect(subject.confirm_button).to eq("x")
88
+ end
89
+ end
90
+
91
+ describe "#cancel_url" do
92
+ it "returns index url" do
93
+ allow(subject).to receive(:index_url).and_return("x")
94
+ expect(subject.cancel_url).to eq("x")
95
+ end
96
+ end
97
+
98
+ describe "#cancel_button" do
99
+ it "returns cancel button" do
100
+ allow(subject).to receive(:t).with("No").and_return("Noo")
101
+ allow(subject).to receive(:button).with("Noo", "ban", class: "secondary", data: {type: "cancel"}, href: "y").and_return("x")
102
+ expect(subject.cancel_button).to eq("x")
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,215 @@
1
+ require "rails_helper"
2
+
3
+ describe Releaf::Builders::EditBuilder, type: :class do
4
+ class TranslationsEditBuilderTestHelper < ActionView::Base
5
+ include Releaf::ApplicationHelper
6
+ include Releaf::ButtonHelper
7
+ include FontAwesome::Rails::IconHelper
8
+
9
+ def protect_against_forgery?
10
+ true
11
+ end
12
+ def form_authenticity_token
13
+ "xxx"
14
+ end
15
+
16
+ def request_forgery_protection_token
17
+ "yyy"
18
+ end
19
+ end
20
+
21
+ let(:template){ TranslationsEditBuilderTestHelper.new }
22
+ let(:subject){ described_class.new(template) }
23
+ let(:controller){ Releaf::BaseController.new }
24
+ let(:resource){ Book.new }
25
+
26
+ before do
27
+ allow(template).to receive(:controller).and_return(controller)
28
+ allow(controller).to receive(:action_name).and_return(:edit)
29
+ allow(subject).to receive(:resource).and_return(resource)
30
+ end
31
+
32
+ describe "#section_content" do
33
+ before do
34
+ allow(subject).to receive(:section_attributes).and_return(a: "b")
35
+ allow(subject).to receive(:form_options).and_return(url: "xxx", builder: Releaf::Builders::FormBuilder)
36
+ allow(subject).to receive(:index_url_preserver).and_return("_index_url_")
37
+ allow(subject).to receive(:section_blocks).and_return(["_section_","_blocks_"])
38
+ end
39
+
40
+ it "returns section with index url preserver and section blocks" do
41
+ expect(subject.section_content).to eq('<form class="new_book" id="new_book" action="xxx" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="&#x2713;" /><input type="hidden" name="yyy" value="xxx" />_index_url__section__blocks_</form>')
42
+ end
43
+
44
+ it "assigns form instance to builder" do
45
+ expect{ subject.section_content }.to change{ subject.form }.from(nil)
46
+ expect(subject.form).to be_instance_of Releaf::Builders::FormBuilder
47
+ end
48
+ end
49
+
50
+ describe "#index_url_preserver" do
51
+ it "returns hidden index url input" do
52
+ allow(subject).to receive(:params).and_return(index_url: "?asd=23&lf=dd")
53
+ result = '<input type="hidden" name="index_url" id="index_url" value="?asd=23&amp;lf=dd" />'
54
+ expect(subject.index_url_preserver).to eq(result)
55
+ end
56
+ end
57
+
58
+ describe "#section_body_blocks" do
59
+ it "returns array with error notices and form fields" do
60
+ allow(subject).to receive(:error_notices).and_return("err")
61
+ allow(subject).to receive(:form_fields).and_return("fields")
62
+ expect(subject.section_body_blocks).to eq(["err", "fields"])
63
+ end
64
+ end
65
+
66
+ describe "#error_notices" do
67
+
68
+ before do
69
+ allow(subject).to receive(:error_notices_header).and_return("<error_notice_header />".html_safe)
70
+ end
71
+
72
+ context "when errors exists" do
73
+
74
+ it "returns errors block" do
75
+ resource.valid?
76
+
77
+ expect(subject.error_notices).to match_html(%Q[
78
+ <div class="form-error-box">
79
+ <error_notice_header />
80
+ <ul>
81
+ <li class="error">Title Blank</li>
82
+ </ul>
83
+ </div>
84
+ ])
85
+ end
86
+ end
87
+
88
+ context "when no errors present" do
89
+ it "returns nil" do
90
+ expect(subject.error_notices).to be nil
91
+ end
92
+ end
93
+ end
94
+
95
+ describe "#error_notices_header" do
96
+ it "returns validation errors notices header" do
97
+ resource.valid?
98
+ expect(subject.error_notices_header).to eq('<strong>1 validation error occured:</strong>')
99
+
100
+ resource.title = "xx"
101
+ resource.valid?
102
+ expect(subject.error_notices_header).to eq('<strong>0 validation errors occured:</strong>')
103
+ end
104
+ end
105
+
106
+ describe "#footer_primary_tools" do
107
+ before do
108
+ allow(subject).to receive(:save_button).and_return("_svbtn_")
109
+ allow(subject).to receive(:save_and_create_another_button).and_return("_svacrbtn_")
110
+ end
111
+
112
+ context "when create_another is availble" do
113
+ it "returns an array with save_and_create_another and save buttons" do
114
+ allow(subject).to receive(:create_another_available?).and_return true
115
+ expect(subject.footer_primary_tools).to eq(["_svacrbtn_", "_svbtn_"])
116
+ end
117
+ end
118
+
119
+ context "when create_another is not available" do
120
+ it "returns an array with save button" do
121
+ allow(subject).to receive(:create_another_available?).and_return false
122
+ expect(subject.footer_primary_tools).to eq(["_svbtn_"])
123
+ end
124
+ end
125
+
126
+ end
127
+
128
+ describe "#create_another_available?" do
129
+
130
+ before do
131
+ controller.setup
132
+ end
133
+
134
+ context "when editing an existing record" do
135
+ let(:resource){ FactoryGirl.create(:book) }
136
+
137
+ context "when controller has create_another feature enabled" do
138
+ it "returns false" do
139
+ expect(subject.create_another_available?).to be false
140
+ end
141
+ end
142
+
143
+ context "when controller has create_another feature disabled" do
144
+ it "returns false" do
145
+ expect(subject.create_another_available?).to be false
146
+ end
147
+ end
148
+ end
149
+
150
+ context "when creating a new record" do
151
+ context "when controller has create_another feature enabled" do
152
+ it "returns true" do
153
+ expect(subject.create_another_available?).to be true
154
+ end
155
+ end
156
+
157
+ context "when controller has create_another feature disabled" do
158
+ it "returns false" do
159
+ allow(controller).to receive(:feature_available?).with(:create_another).and_return false
160
+ expect(subject.create_another_available?).to be false
161
+ end
162
+ end
163
+ end
164
+
165
+ context "when resource is not present" do
166
+ let(:resource){ nil }
167
+ it "returns false" do
168
+ expect(subject.create_another_available?).to be false
169
+ end
170
+ end
171
+
172
+ end
173
+
174
+ describe "#save_and_create_another_button" do
175
+ it "returns save and create button" do
176
+ allow(template).to receive(:fa_icon).with("plus").and_return('<plus_icon />'.html_safe)
177
+ allow(subject).to receive(:t).with("Save and create another").and_return("Save and ccrr")
178
+ expect(subject.save_and_create_another_button).to match_html(%Q[
179
+ <button class="button with-icon secondary" title="Save and ccrr" type="submit" autocomplete="off" name="after_save" value="create_another" data-type="ok" data-disable="true">
180
+ <plus_icon />
181
+ Save and ccrr
182
+ </button>
183
+ ])
184
+ end
185
+ end
186
+
187
+
188
+ describe "#save_button" do
189
+ it "returns save button" do
190
+ allow(subject).to receive(:button)
191
+ .with("to_list", "check", {class: "primary", data: {type: "ok", disable: true}, type: "submit"})
192
+ .and_return("_btn_")
193
+ allow(subject).to receive(:t).with("Save").and_return("to_list")
194
+ expect(subject.save_button).to eq("_btn_")
195
+ end
196
+ end
197
+
198
+ describe "#form_options" do
199
+ it "returns controller form options for current action and resource" do
200
+ allow(controller).to receive(:form_options).with(:edit, resource, :resource).and_return(:y)
201
+ expect(subject.form_options).to eq(:y)
202
+ end
203
+ end
204
+
205
+ describe "#form_fields" do
206
+ it "returns form `releaf_fields` output for form `field_names` casted to array" do
207
+ form = Releaf::Builders::FormBuilder.new(:book, Book.new, template, {})
208
+ subject.form = form
209
+ allow(form).to receive(:field_names).and_return({a: 1, b: 2})
210
+ allow(form).to receive(:releaf_fields).with([[:a, 1], [:b, 2]]).and_return(:x)
211
+
212
+ expect(subject.form_fields).to eq(:x)
213
+ end
214
+ end
215
+ end
@@ -0,0 +1,562 @@
1
+ require "rails_helper"
2
+
3
+ describe Releaf::Builders::FormBuilder, type: :class do
4
+ class FormBuilderTestHelper < ActionView::Base
5
+ include Releaf::ApplicationHelper
6
+ include Releaf::ButtonHelper
7
+ include FontAwesome::Rails::IconHelper
8
+ end
9
+
10
+ let(:template){ FormBuilderTestHelper.new }
11
+ let(:object){ Book.new }
12
+ let(:subject){ described_class.new(:book, object, template, {}) }
13
+ let(:normalized_fields){
14
+ [
15
+ {
16
+ render_method: "render_title",
17
+ field: "title",
18
+ subfields: nil
19
+ },
20
+ {
21
+ render_method: "render_author_id",
22
+ field: "author_id",
23
+ subfields: nil
24
+ },
25
+ {
26
+ render_method: "render_chapters",
27
+ field: :chapters,
28
+ subfields: ["title", "text", "sample_html"]
29
+ },
30
+ {
31
+ render_method: "render_book_sequels",
32
+ field: :book_sequels,
33
+ subfields: ["sequel_id"]
34
+ }
35
+ ]
36
+ }
37
+
38
+ it "includes Releaf::Builders::Base" do
39
+ expect(described_class.ancestors).to include(Releaf::Builders::Base)
40
+ end
41
+
42
+ it "includes Releaf::Builders::Orderer" do
43
+ expect(described_class.ancestors).to include(Releaf::Builders::Orderer)
44
+ end
45
+
46
+ describe "#field_names" do
47
+ it "returns field names for object class" do
48
+ allow(Releaf::Core::ResourceFields).to receive(:new).with(object.class).and_call_original
49
+ allow_any_instance_of(Releaf::Core::ResourceFields).to receive(:values).and_return(["a", "b"])
50
+ expect(subject.field_names).to eq(["a", "b"])
51
+ end
52
+ end
53
+
54
+ describe "#field_render_method_name" do
55
+ it "returns method name for given field" do
56
+ expect(subject.field_render_method_name(:title)).to eq("render_title")
57
+ end
58
+
59
+ context "when builder has parent builder(-s)" do
60
+ it "traverses through all builders and add relation name option to field name" do
61
+ root_builder = described_class.new(:author, Author.new, template, {})
62
+ middle_builder = described_class.new(:author, Author.new, template, {relation_name: :pages, parent_builder: root_builder})
63
+ subject.options[:parent_builder] = middle_builder
64
+ subject.options[:relation_name] = :chapters
65
+
66
+ expect(subject.field_render_method_name(:title)).to eq("render_pages_chapters_title")
67
+ end
68
+ end
69
+ end
70
+
71
+ describe "#normalize_fields" do
72
+ it "returns normalized fields for use with #releaf_fields method" do
73
+ fields = [
74
+ "title",
75
+ "author_id",
76
+ {chapters: ["title", "text", "sample_html"]},
77
+ {book_sequels: ["sequel_id"]}
78
+ ]
79
+ expect(subject.normalize_fields(fields)).to eq(normalized_fields)
80
+ end
81
+
82
+ it "handles multi-key hashes" do
83
+ fields = [
84
+ "title",
85
+ "author_id",
86
+ {
87
+ chapters: ["title", "text", "sample_html"],
88
+ book_sequels: ["sequel_id"]
89
+ }
90
+ ]
91
+ expect(subject.normalize_fields(fields)).to eq(normalized_fields)
92
+ end
93
+ end
94
+
95
+ describe "#releaf_fields" do
96
+ it "normalizes given fields with #normalize_fields" do
97
+ allow(subject).to receive(:render_field_by_options)
98
+ expect(subject).to receive(:normalize_fields).with([:a, :b]).and_return([:x, :y])
99
+ subject.releaf_fields(:a, :b)
100
+ end
101
+
102
+ it "passes all normalized field options to #render_field" do
103
+ allow(subject).to receive(:normalize_fields).and_return([:x, :y])
104
+ expect(subject).to receive(:render_field_by_options).with(:x)
105
+ expect(subject).to receive(:render_field_by_options).with(:y)
106
+ subject.releaf_fields(:a, :b)
107
+ end
108
+
109
+ it "concatenates and return all #render_field_by_options outputs with #safe_join" do
110
+ allow(subject).to receive(:render_field_by_options).and_return('_a_', '_b_')
111
+ allow(subject).to receive(:normalize_fields).and_return([:x, :y])
112
+ expect(subject).to receive(:safe_join).with(no_args){|&block|
113
+ expect(block.call).to eq(['_a_', '_b_'])
114
+ }.and_return("xxx")
115
+ expect(subject.releaf_fields(:a, :b)).to eq("xxx")
116
+ end
117
+ end
118
+
119
+ describe "#render_field_by_options" do
120
+ let(:options){ {
121
+ render_method: "sortable_column_name", # just random method here
122
+ field: "title",
123
+ subfields: [:a, :b],
124
+ } }
125
+
126
+ before do
127
+ allow(subject).to receive(:reflect_on_association).with("title").and_return(:x)
128
+ allow(subject).to receive(:sortable_column_name)
129
+ .with(no_args).and_return("_render_method_content_")
130
+ allow(subject).to receive(:releaf_association_fields)
131
+ .with(:x, [:a, :b]).and_return("_association_method_content_")
132
+ allow(subject).to receive(:releaf_field)
133
+ .with("title").and_return("_releaf_field_content_")
134
+ end
135
+
136
+ context "when method defined in options[:render_method] exists" do
137
+ it "returns this method output" do
138
+ expect(subject.render_field_by_options(options)).to eq("_render_method_content_")
139
+ end
140
+ end
141
+
142
+ context "when custom method does not exist" do
143
+ before do
144
+ options[:render_method] = "something_unexisting"
145
+ end
146
+
147
+ context "when reflection exists for given field" do
148
+ it "returns #releaf_association_fields by passing options[:field] and options[:subfields]" do
149
+ expect(subject.render_field_by_options(options)).to eq("_association_method_content_")
150
+ end
151
+ end
152
+
153
+ context "when reflection does not exist for given field" do
154
+ it "returns #releaf_field with options[:field] as argument" do
155
+ allow(subject).to receive(:reflect_on_association).with("title").and_return(nil)
156
+ expect(subject.render_field_by_options(options)).to eq("_releaf_field_content_")
157
+ end
158
+ end
159
+ end
160
+ end
161
+
162
+ describe "#reflect_on_association" do
163
+ it "returns reflection for given reflection name" do
164
+ expect(subject.reflect_on_association(:author)).to eq(object.class.reflections["author"])
165
+ expect(subject.reflect_on_association("author")).to eq(object.class.reflections["author"])
166
+ end
167
+ end
168
+
169
+ describe "#association_reflector" do
170
+ before do
171
+ resource_fields = subject.resource_fields
172
+ allow(resource_fields).to receive(:association_attributes).with(:x).and_return([:c, :d])
173
+
174
+ allow(subject).to receive(:resource_fields).and_return(resource_fields)
175
+ allow(subject).to receive(:sortable_column_name).and_return("sortable column name")
176
+ end
177
+
178
+ it "returns association reflector for given reflection" do
179
+ expect(subject.association_reflector(:x, [:a, :b])).to be_instance_of Releaf::Builders::AssociationReflector
180
+ end
181
+
182
+ it "pass reflection, fields and sortable column name to association reflector constructor" do
183
+ expect(Releaf::Builders::AssociationReflector).to receive(:new)
184
+ .with(:x, [:a, :b], "sortable column name")
185
+ subject.association_reflector(:x, [:a, :b])
186
+ end
187
+
188
+ context "when given fields is nil" do
189
+ it "uses resource fields returned association fields instead" do
190
+ expect(Releaf::Builders::AssociationReflector).to receive(:new)
191
+ .with(:x, [:c, :d], "sortable column name")
192
+ subject.association_reflector(:x, nil)
193
+ end
194
+ end
195
+ end
196
+
197
+ describe "#releaf_association_fields" do
198
+ let(:reflector){ Releaf::Builders::AssociationReflector.new(:a, :b, :c) }
199
+ let(:fields){ ["a"] }
200
+
201
+ before do
202
+ allow(subject).to receive(:association_reflector).with(:author, fields).and_return(reflector)
203
+ allow(subject).to receive(:releaf_has_many_association).with(reflector).and_return("_has_many_content_")
204
+ allow(subject).to receive(:releaf_belongs_to_association).with(reflector).and_return("_belongs_to_content_")
205
+ allow(subject).to receive(:releaf_has_one_association).with(reflector).and_return("_has_one_content_")
206
+ end
207
+
208
+ context "when reflector macro is :has_many" do
209
+ it "renders association with #releaf_has_many_association" do
210
+ allow(reflector).to receive(:macro).and_return(:has_many)
211
+ expect(subject.releaf_association_fields(:author, fields)).to eq("_has_many_content_")
212
+ end
213
+ end
214
+
215
+ context "when :belongs_to association given" do
216
+ it "renders association with #releaf_belongs_to_association" do
217
+ allow(reflector).to receive(:macro).and_return(:belongs_to)
218
+ expect(subject.releaf_association_fields(:author, fields)).to eq("_belongs_to_content_")
219
+ end
220
+ end
221
+
222
+ context "when :has_one association given" do
223
+ it "renders association with #releaf_has_one_association" do
224
+ allow(reflector).to receive(:macro).and_return(:has_one)
225
+ expect(subject.releaf_association_fields(:author, fields)).to eq("_has_one_content_")
226
+ end
227
+ end
228
+
229
+ context "when non implemented assocation type given" do
230
+ it "raises error" do
231
+ allow(reflector).to receive(:macro).and_return(:new_macro_type)
232
+ expect{ subject.releaf_association_fields(:author, fields) }.to raise_error("not implemented")
233
+ end
234
+ end
235
+ end
236
+
237
+ describe "#input_wrapper_with_label" do
238
+ before do
239
+ allow(subject).to receive(:wrapper).with("input_content", class: "value").and_return("input_content")
240
+ allow(subject).to receive(:releaf_label).with(:color, "label_attributes", "options").and_return("label_content")
241
+ allow(subject).to receive(:field).with(:color, "field_attributes", "options"){ |name, field, options, &block|
242
+ expect(block.call).to eq("label_contentinput_content")
243
+ }.and_return("content")
244
+ end
245
+
246
+ it "returns wrapped label and input content" do
247
+ expect(subject.input_wrapper_with_label(:color, "input_content", label: "label_attributes", field: "field_attributes", options: "options"))
248
+ .to eq("content")
249
+ end
250
+
251
+ context "when block given" do
252
+ it "safely concatinate block output to content" do
253
+ content = 'input_content<input type="hidden" name="book[id]" id="book_id" />'
254
+ allow(subject).to receive(:wrapper).with(content, class: "value").and_return("input_content")
255
+ expect(subject.input_wrapper_with_label(:color, "input_content", label: "label_attributes", field: "field_attributes", options: "options"){ subject.hidden_field(:id) })
256
+ .to eq("content")
257
+ end
258
+
259
+ it "correctly handles block nil output" do
260
+ expect(subject.input_wrapper_with_label(:color, "input_content", label: "label_attributes", field: "field_attributes", options: "options"){ })
261
+ .to eq("content")
262
+ end
263
+ end
264
+ end
265
+
266
+ describe "#releaf_label" do
267
+ it "passes options :label value to #label_text and use returned value for label text content" do
268
+ allow(subject).to receive(:label_text).with(:color, a: "b").and_return("xx")
269
+ result = '<div class="label-wrap"><label for="book_color">xx</label></div>'
270
+
271
+ expect(subject.releaf_label(:color, {}, label: {a: "b"})).to eq(result)
272
+ end
273
+
274
+ it "uses #label_attributes for label attributes" do
275
+ allow(subject).to receive(:label_attributes).with(:color, {class: "red"}, {a: "b"}).and_return(class: "red blue")
276
+ result = '<div class="label-wrap"><label class="red blue" for="book_color">Color</label></div>'
277
+
278
+ expect(subject.releaf_label(:color, {class: "red"}, {a: "b"})).to eq(result)
279
+ end
280
+
281
+ context "when options[:label][:description] is not blank" do
282
+ context "when label has full version" do
283
+ it "includes description" do
284
+ result = '<div class="label-wrap"><label for="book_color">Color</label><div class="description">xxx</div></div>'
285
+ expect(subject.releaf_label(:color, {}, label: {description: "xxx"})).to eq(result)
286
+ end
287
+ end
288
+
289
+ context "when label has minimal version" do
290
+ it "does not include description" do
291
+ result = '<label for="book_color">Color</label>'
292
+ expect(subject.releaf_label(:color, {}, label: {minimal: true})).to eq(result)
293
+ end
294
+ end
295
+ end
296
+
297
+ context "when options[:label][:minimal] is true" do
298
+ it "returns label tag without wrap element" do
299
+ result = '<label for="book_color">Color</label>'
300
+ expect(subject).to_not receive(:wrapper)
301
+ expect(subject.releaf_label(:color, {}, label: {minimal: true})).to eq(result)
302
+ end
303
+ end
304
+
305
+ context "when options[:label][:minimal] is not true" do
306
+ it "returns label tag with wrap element" do
307
+ allow(subject).to receive(:wrapper).with('<label for="book_color">Color</label>', class: "label-wrap").and_return("x")
308
+ expect(subject.releaf_label(:color, {}, label: {minimal: false})).to eq("x")
309
+ expect(subject.releaf_label(:color, {}, label: {minimal: nil})).to eq("x")
310
+ expect(subject.releaf_label(:color, {}, label: {adasd: "xx"})).to eq("x")
311
+ end
312
+ end
313
+
314
+ end
315
+
316
+ describe "#releaf_number_field" do
317
+ it "returns input with type 'number'" do
318
+ expect(subject).to receive(:number_field).with("title", { value: nil, step: "any", class: "text" }).and_return("x")
319
+ expect(subject).to receive(:input_wrapper_with_label).with("title", "x", { label: {}, field: {}, options: { field: { type: "number" }}}).and_return("y")
320
+ expect(subject.releaf_number_field("title")).to eq("y")
321
+ end
322
+
323
+ context "aliases" do
324
+ let(:releaf_number_field_method) { subject.method(:releaf_number_field) }
325
+
326
+ it "is aliased by #releaf_integer_field" do
327
+ expect(subject.method(:releaf_integer_field)).to eq(releaf_number_field_method)
328
+ end
329
+
330
+ it "is aliased by #releaf_float_field" do
331
+ expect(subject.method(:releaf_float_field)).to eq(releaf_number_field_method)
332
+ end
333
+
334
+ it "is aliased by #releaf_decimal_field" do
335
+ expect(subject.method(:releaf_decimal_field)).to eq(releaf_number_field_method)
336
+ end
337
+ end
338
+ end
339
+
340
+ describe "#field_attributes" do
341
+ it "adds field data and class attributes" do
342
+ expect(subject.field_attributes(:color, {}, {field: {type: "text"}})).to eq(data: {name: :color}, class: ["field", "type-text"])
343
+ end
344
+
345
+ it "merges attributes over build-in data hash" do
346
+ expect(subject.field_attributes(:color, {data: {other: "x"}}, {})[:data]).to eq(name: :color, other: "x")
347
+ expect(subject.field_attributes(:color, {data: {other: "x", name: :lll}}, {})[:data]).to eq(name: :lll, other: "x")
348
+ end
349
+
350
+ it "supports class attributes merging" do
351
+ expect(subject.field_attributes(:color, {class: ["a", "b"]}, {})[:class]).to eq(["field", "type-", "a", "b"])
352
+ end
353
+ end
354
+
355
+ describe "#label_attributes" do
356
+ it "returns unmodified attributes (allow further override by other builders)" do
357
+ expect(subject.label_attributes(:color, {data: "x"}, {})).to eq(data: "x")
358
+ end
359
+ end
360
+
361
+ describe "#input_attributes" do
362
+ it "returns unmodified attributes (allow further override by other builders)" do
363
+ expect(subject.input_attributes(:color, {data: "x"}, {})).to eq(data: "x")
364
+ end
365
+ end
366
+
367
+ describe "#label_text" do
368
+ it "returns model attributes scoped translated value" do
369
+ allow(subject).to receive(:translate_attribute).with("color").and_return("x")
370
+ expect(subject.label_text(:color)).to eq("x")
371
+ end
372
+
373
+ context "when :label_text option exists" do
374
+ context "when :label_text is not blank" do
375
+ it "returns :label_text option" do
376
+ expect(subject.label_text(:color, label_text: "krāsa")).to eq("krāsa")
377
+ end
378
+ end
379
+
380
+ context "when :label_text is blank" do
381
+ it "returns translated value" do
382
+ expect(subject.label_text(:color, label_text: nil)).to eq("Color")
383
+ expect(subject.label_text(:color, label_text: "")).to eq("Color")
384
+ end
385
+ end
386
+ end
387
+
388
+ context "when :translation_key option exists" do
389
+ context "when :translation_key is not blank" do
390
+ it "passes :translation_key option to translation and return translated value" do
391
+ allow(subject).to receive(:translate_attribute).with("true_color").and_return("x")
392
+ expect(subject.label_text(:color, translation_key: "true_color")).to eq("x")
393
+ end
394
+ end
395
+
396
+ context "when :translation_key is blank" do
397
+ it "returns translated value" do
398
+ expect(subject.label_text(:color, translation_key: nil)).to eq("Color")
399
+ expect(subject.label_text(:color, translation_key: "")).to eq("Color")
400
+ end
401
+ end
402
+ end
403
+ end
404
+
405
+ describe "#sortable_column_name" do
406
+ it "returns 'item_position'" do
407
+ expect( subject.sortable_column_name ).to eq 'item_position'
408
+ end
409
+ end
410
+
411
+ describe "#releaf_item_field_collection" do
412
+ context "when collection exists within options" do
413
+ it "returns collection" do
414
+ expect(subject.releaf_item_field_collection(:author_id, collection: "x")).to eq("x")
415
+ end
416
+ end
417
+
418
+ context "when collection does not exist within options" do
419
+ it "returns all relation objects" do
420
+ allow(Author).to receive(:all).and_return("y")
421
+ expect(subject.releaf_item_field_collection(:author_id)).to eq("y")
422
+ end
423
+ end
424
+ end
425
+
426
+ describe "#releaf_item_field_choices" do
427
+ before do
428
+ subject.object.author_id = 3
429
+ end
430
+
431
+ context "when no select_options passed within options" do
432
+ it "prefills select_options with corresponding collection array" do
433
+ collection = [Author.new(name: "a", surname: "b", id: 1), Author.new(name: "c", surname: "d", id: 2)]
434
+ allow(subject).to receive(:releaf_item_field_collection)
435
+ .with(:author_id, x: "a").and_return(collection)
436
+ allow(subject).to receive(:options_for_select).with([["a b", 1], ["c d", 2]], 3).and_return("xx")
437
+ expect(subject.releaf_item_field_choices(:author_id, x: "a")).to eq("xx")
438
+ end
439
+ end
440
+
441
+ context "when options have select_options passed" do
442
+ context "when select_options is array" do
443
+ it "process and return select options with `options_for_select` rails helper" do
444
+ collection = [["a b", 1], ["c d", 2]]
445
+ allow(subject).to receive(:options_for_select).with(collection, 3).and_return("xx")
446
+ expect(subject.releaf_item_field_choices(:author_id, select_options: collection)).to eq("xx")
447
+ end
448
+ end
449
+
450
+ context "when select_options is not array" do
451
+ it "returns select_options value" do
452
+ expect(subject.releaf_item_field_choices(:author_id, select_options: "xx")).to eq("xx")
453
+ end
454
+ end
455
+ end
456
+ end
457
+
458
+ describe "#relation_name" do
459
+ it "strips _id from given string and returns it as symbol" do
460
+ expect(subject.relation_name("admin_id")).to eq(:admin)
461
+ end
462
+ end
463
+
464
+ describe "#format_date_or_time_value" do
465
+ context "when given value type is :time" do
466
+ it "format normalized value to default format with `strftime`" do
467
+ value = Date.parse("15 Jan 2015")
468
+ time = Time.parse("15 Jan 2015 12:10:04")
469
+ allow(subject).to receive(:date_or_time_default_format).with(:time).and_return("%H:%M")
470
+ allow(subject).to receive(:normalize_date_or_time_value).with(value, :time).and_return(time)
471
+
472
+ expect(subject.format_date_or_time_value(value, :time)).to eq("12:10")
473
+ end
474
+ end
475
+
476
+ context "when given value type is other than :time" do
477
+ it "format normalized value to default format with `I18n.l`" do
478
+ value = Date.parse("15 Jan 2015")
479
+ time = Time.parse("15 Jan 2015 12:10:04")
480
+
481
+ allow(subject).to receive(:date_or_time_default_format).with(:date).and_return("_format_")
482
+ allow(subject).to receive(:normalize_date_or_time_value).with(value, :date).and_return(time)
483
+ allow(I18n).to receive(:l).with(time, default: "_format_").and_return("x")
484
+ expect(subject.format_date_or_time_value(value, :date)).to eq("x")
485
+
486
+
487
+ allow(subject).to receive(:date_or_time_default_format).with(:datetime).and_return("_format_")
488
+ allow(subject).to receive(:normalize_date_or_time_value).with(value, :datetime).and_return(time)
489
+ allow(I18n).to receive(:l).with(time, default: "_format_").and_return("y")
490
+ expect(subject.format_date_or_time_value(value, :datetime)).to eq("y")
491
+ end
492
+ end
493
+ end
494
+
495
+ describe "#locales" do
496
+ it "returns object globalize locales" do
497
+ allow(subject.object.class).to receive(:globalize_locales).and_return([:de, :ru])
498
+ expect(subject.locales).to eq([:de, :ru])
499
+ end
500
+ end
501
+
502
+ describe "#default_locale" do
503
+ before do
504
+ allow(subject).to receive(:cookies).and_return({})
505
+ allow(I18n).to receive(:locale).and_return(:ru)
506
+ allow(subject).to receive(:locales).and_return([:de, :ru])
507
+ end
508
+
509
+ context "when cookies has stored locale" do
510
+ it "returns stored locale normalized to symbol" do
511
+ allow(subject).to receive(:cookies).and_return("releaf.i18n.locale".to_sym => "de")
512
+ expect(subject.default_locale).to eq(:de)
513
+ end
514
+ end
515
+
516
+ context "when cookies hasn't stored locale" do
517
+ it "returns current I18n locale" do
518
+ expect(subject.default_locale).to eq(:ru)
519
+ end
520
+ end
521
+
522
+ context "when stored locale or I18n locale is not within form locales" do
523
+ it "returns first form locale" do
524
+ allow(subject).to receive(:locales).and_return([:lv, :en])
525
+ expect(subject.default_locale).to eq(:lv)
526
+ end
527
+ end
528
+ end
529
+
530
+ describe "#normalize_date_or_time_value" do
531
+ context "when :time type given" do
532
+ it "casts value to time" do
533
+ value = Date.parse("15 Jan 2015")
534
+ expect(subject.normalize_date_or_time_value(value, :time)).to be_instance_of Time
535
+ expect(subject.normalize_date_or_time_value(value, :time)).to eq(value.to_time)
536
+ end
537
+ end
538
+
539
+ context "when :datetime type given" do
540
+ it "casts value to datetime" do
541
+ value = Time.parse("15 Jan 2015 12:10:04")
542
+ expect(subject.normalize_date_or_time_value(value, :datetime)).to be_instance_of DateTime
543
+ expect(subject.normalize_date_or_time_value(value, :datetime)).to eq(value.to_datetime)
544
+ end
545
+ end
546
+
547
+ context "when :time type given" do
548
+ it "casts value to date" do
549
+ value = DateTime.parse("15 Jan 2015 12:10:04")
550
+ expect(subject.normalize_date_or_time_value(value, :date)).to be_instance_of Date
551
+ expect(subject.normalize_date_or_time_value(value, :date)).to eq(value.to_date)
552
+ end
553
+ end
554
+ end
555
+
556
+ describe "#translate_attribute" do
557
+ it "translates given attribute within object translation scope" do
558
+ allow(object.class).to receive(:human_attribute_name).with("x", create_default: false).and_return("z")
559
+ expect(subject.translate_attribute("x")).to eq("z")
560
+ end
561
+ end
562
+ end