alchemy_cms 3.2.1 → 3.3.0.rc1

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 (556) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +28 -0
  3. data/.gitignore +2 -2
  4. data/.travis.yml +11 -3
  5. data/CHANGELOG.md +100 -0
  6. data/CONTRIBUTING.md +1 -1
  7. data/Gemfile +12 -1
  8. data/README.md +25 -7
  9. data/Rakefile +1 -3
  10. data/alchemy_cms.gemspec +7 -15
  11. data/app/assets/fonts/alchemy/icons.eot +0 -0
  12. data/app/assets/fonts/alchemy/icons.svg +28 -66
  13. data/app/assets/fonts/alchemy/icons.ttf +0 -0
  14. data/app/assets/fonts/alchemy/icons.woff +0 -0
  15. data/app/assets/images/alchemy/icons.png +0 -0
  16. data/app/assets/javascripts/alchemy/alchemy.base.js.coffee +10 -3
  17. data/app/assets/javascripts/alchemy/alchemy.buttons.js.coffee +15 -6
  18. data/app/assets/javascripts/alchemy/alchemy.char_counter.js.coffee +1 -1
  19. data/app/assets/javascripts/alchemy/alchemy.datepicker.js.coffee +1 -1
  20. data/app/assets/javascripts/alchemy/alchemy.dialog.js.coffee +10 -4
  21. data/app/assets/javascripts/alchemy/alchemy.dirty.js.coffee +16 -22
  22. data/app/assets/javascripts/alchemy/alchemy.dragndrop.js.coffee +69 -32
  23. data/app/assets/javascripts/alchemy/alchemy.element_editors.js.coffee +147 -83
  24. data/app/assets/javascripts/alchemy/alchemy.file_progress.js.coffee +14 -14
  25. data/app/assets/javascripts/alchemy/alchemy.hotkeys.js.coffee +1 -1
  26. data/app/assets/javascripts/alchemy/alchemy.i18n.js.coffee +1 -1
  27. data/app/assets/javascripts/alchemy/alchemy.image_overlay.coffee +55 -0
  28. data/app/assets/javascripts/alchemy/alchemy.initializer.js.coffee +8 -1
  29. data/app/assets/javascripts/alchemy/alchemy.js +3 -1
  30. data/app/assets/javascripts/alchemy/alchemy.link_dialog.js.coffee +36 -31
  31. data/app/assets/javascripts/alchemy/alchemy.preview.js.coffee +35 -29
  32. data/app/assets/javascripts/alchemy/alchemy.sitemap.js.coffee +51 -5
  33. data/app/assets/javascripts/alchemy/alchemy.tinymce.js.coffee +26 -10
  34. data/app/assets/javascripts/alchemy/{alchemy.windows.js.coffee → alchemy.trash_window.js.coffee} +1 -13
  35. data/app/assets/javascripts/alchemy/alchemy.uploader.js.coffee +15 -17
  36. data/app/assets/javascripts/tinymce/plugins/alchemy_link/plugin.min.js +3 -3
  37. data/app/assets/stylesheets/alchemy/_extends.scss +1 -1
  38. data/app/assets/stylesheets/alchemy/_mixins.scss +27 -0
  39. data/app/assets/stylesheets/alchemy/_variables.scss +1 -0
  40. data/app/assets/stylesheets/alchemy/admin.scss +1 -0
  41. data/app/assets/stylesheets/alchemy/archive.scss +0 -57
  42. data/app/assets/stylesheets/alchemy/base.scss +1 -18
  43. data/app/assets/stylesheets/alchemy/buttons.scss +30 -25
  44. data/app/assets/stylesheets/alchemy/dialogs.scss +25 -9
  45. data/app/assets/stylesheets/alchemy/elements.scss +182 -126
  46. data/app/assets/stylesheets/alchemy/form_fields.scss +14 -8
  47. data/app/assets/stylesheets/alchemy/forms.scss +10 -1
  48. data/app/assets/stylesheets/alchemy/frame.scss +3 -10
  49. data/app/assets/stylesheets/alchemy/icon-font.scss +13 -6
  50. data/app/assets/stylesheets/alchemy/icons.scss +16 -0
  51. data/app/assets/stylesheets/alchemy/image_library.scss +269 -0
  52. data/app/assets/stylesheets/alchemy/selects.scss +1 -0
  53. data/app/assets/stylesheets/alchemy/sitemap.scss +12 -1
  54. data/app/assets/stylesheets/alchemy/toolbar.scss +2 -2
  55. data/app/assets/stylesheets/alchemy/upload.scss +97 -87
  56. data/app/assets/stylesheets/alchemy/welcome.sass +49 -0
  57. data/app/controllers/alchemy/admin/attachments_controller.rb +21 -29
  58. data/app/controllers/alchemy/admin/base_controller.rb +23 -4
  59. data/app/controllers/alchemy/admin/clipboard_controller.rb +0 -1
  60. data/app/controllers/alchemy/admin/contents_controller.rb +2 -4
  61. data/app/controllers/alchemy/admin/dashboard_controller.rb +4 -4
  62. data/app/controllers/alchemy/admin/elements_controller.rb +20 -11
  63. data/app/controllers/alchemy/admin/essence_files_controller.rb +2 -2
  64. data/app/controllers/alchemy/admin/essence_pictures_controller.rb +10 -9
  65. data/app/controllers/alchemy/admin/languages_controller.rb +0 -1
  66. data/app/controllers/alchemy/admin/layoutpages_controller.rb +0 -2
  67. data/app/controllers/alchemy/admin/legacy_page_urls_controller.rb +0 -1
  68. data/app/controllers/alchemy/admin/pages_controller.rb +46 -29
  69. data/app/controllers/alchemy/admin/pictures_controller.rb +44 -55
  70. data/app/controllers/alchemy/admin/resources_controller.rb +8 -75
  71. data/app/controllers/alchemy/admin/tags_controller.rb +10 -8
  72. data/app/controllers/alchemy/admin/trash_controller.rb +0 -6
  73. data/app/controllers/alchemy/api/contents_controller.rb +0 -1
  74. data/app/controllers/alchemy/api/elements_controller.rb +0 -1
  75. data/app/controllers/alchemy/api/pages_controller.rb +4 -1
  76. data/app/controllers/alchemy/attachments_controller.rb +4 -5
  77. data/app/controllers/alchemy/base_controller.rb +6 -5
  78. data/app/controllers/alchemy/elements_controller.rb +1 -1
  79. data/app/controllers/alchemy/messages_controller.rb +9 -4
  80. data/app/controllers/alchemy/pages_controller.rb +133 -137
  81. data/app/controllers/alchemy/pictures_controller.rb +12 -10
  82. data/app/controllers/concerns/alchemy/admin/uploader_responses.rb +41 -0
  83. data/app/controllers/concerns/alchemy/legacy_page_redirects.rb +56 -0
  84. data/app/controllers/concerns/alchemy/locale_redirects.rb +38 -0
  85. data/app/controllers/concerns/alchemy/page_redirects.rb +80 -0
  86. data/app/controllers/concerns/alchemy/site_redirects.rb +22 -0
  87. data/app/helpers/alchemy/admin/attachments_helper.rb +1 -2
  88. data/app/helpers/alchemy/admin/base_helper.rb +36 -62
  89. data/app/helpers/alchemy/admin/contents_helper.rb +6 -80
  90. data/app/helpers/alchemy/admin/elements_helper.rb +36 -15
  91. data/app/helpers/alchemy/admin/essences_helper.rb +15 -8
  92. data/app/helpers/alchemy/admin/form_helper.rb +6 -10
  93. data/app/helpers/alchemy/admin/navigation_helper.rb +4 -7
  94. data/app/helpers/alchemy/admin/pages_helper.rb +14 -35
  95. data/app/helpers/alchemy/admin/pictures_helper.rb +12 -14
  96. data/app/helpers/alchemy/admin/tags_helper.rb +5 -7
  97. data/app/helpers/alchemy/base_helper.rb +9 -17
  98. data/app/helpers/alchemy/elements_block_helper.rb +5 -13
  99. data/app/helpers/alchemy/elements_helper.rb +6 -6
  100. data/app/helpers/alchemy/essences_helper.rb +3 -16
  101. data/app/helpers/alchemy/pages_helper.rb +32 -25
  102. data/app/helpers/alchemy/url_helper.rb +14 -16
  103. data/app/mailers/alchemy/messages.rb +0 -2
  104. data/app/models/alchemy.rb +0 -2
  105. data/app/models/alchemy/attachment.rb +45 -56
  106. data/app/models/alchemy/cell.rb +7 -8
  107. data/app/models/alchemy/content.rb +39 -24
  108. data/app/models/alchemy/content/factory.rb +27 -44
  109. data/app/models/alchemy/element.rb +101 -267
  110. data/app/models/alchemy/element/definitions.rb +9 -8
  111. data/app/models/alchemy/element/element_contents.rb +150 -0
  112. data/app/models/alchemy/element/element_essences.rb +109 -0
  113. data/app/models/alchemy/element/presenters.rb +18 -7
  114. data/app/models/alchemy/essence_date.rb +1 -2
  115. data/app/models/alchemy/essence_file.rb +10 -6
  116. data/app/models/alchemy/essence_html.rb +0 -1
  117. data/app/models/alchemy/essence_picture.rb +12 -4
  118. data/app/models/alchemy/essence_richtext.rb +6 -3
  119. data/app/models/alchemy/language.rb +48 -21
  120. data/app/models/alchemy/language/code.rb +1 -4
  121. data/app/models/alchemy/page.rb +33 -35
  122. data/app/models/alchemy/page/page_cells.rb +6 -10
  123. data/app/models/alchemy/page/page_elements.rb +130 -100
  124. data/app/models/alchemy/page/page_naming.rb +2 -3
  125. data/app/models/alchemy/page/page_natures.rb +50 -16
  126. data/app/models/alchemy/page/page_scopes.rb +7 -7
  127. data/app/models/alchemy/page/page_users.rb +3 -3
  128. data/app/models/alchemy/picture.rb +48 -33
  129. data/app/models/alchemy/picture/transformations.rb +8 -9
  130. data/app/models/alchemy/site.rb +19 -17
  131. data/app/models/alchemy/site/layout.rb +9 -9
  132. data/app/models/alchemy/tag.rb +0 -2
  133. data/app/models/alchemy/tree_node.rb +5 -4
  134. data/app/serializers/alchemy/attachment_serializer.rb +0 -1
  135. data/app/serializers/alchemy/base_serializer.rb +30 -0
  136. data/app/serializers/alchemy/cell_serializer.rb +0 -1
  137. data/app/serializers/alchemy/essence_boolean_serializer.rb +0 -1
  138. data/app/serializers/alchemy/essence_date_serializer.rb +0 -1
  139. data/app/serializers/alchemy/essence_file_serializer.rb +0 -1
  140. data/app/serializers/alchemy/essence_html_serializer.rb +0 -1
  141. data/app/serializers/alchemy/essence_link_serializer.rb +0 -1
  142. data/app/serializers/alchemy/essence_picture_serializer.rb +0 -1
  143. data/app/serializers/alchemy/essence_richtext_serializer.rb +0 -1
  144. data/app/serializers/alchemy/essence_select_serializer.rb +0 -1
  145. data/app/serializers/alchemy/essence_text_serializer.rb +0 -1
  146. data/app/serializers/alchemy/legacy_element_serializer.rb +0 -1
  147. data/app/serializers/alchemy/page_serializer.rb +0 -1
  148. data/app/serializers/alchemy/page_tree_serializer.rb +90 -0
  149. data/app/serializers/alchemy/picture_serializer.rb +0 -1
  150. data/app/views/alchemy/_menubar.html.erb +3 -3
  151. data/app/views/alchemy/admin/attachments/_archive_overlay.html.erb +11 -16
  152. data/app/views/alchemy/admin/attachments/_attachment.html.erb +9 -9
  153. data/app/views/alchemy/admin/attachments/_files_list.html.erb +7 -15
  154. data/app/views/alchemy/admin/attachments/_overlay_file_list.html.erb +1 -1
  155. data/app/views/alchemy/admin/attachments/_tag_list.html.erb +2 -2
  156. data/app/views/alchemy/admin/attachments/edit.html.erb +3 -3
  157. data/app/views/alchemy/admin/attachments/index.html.erb +10 -17
  158. data/app/views/alchemy/admin/clipboard/clear.js.erb +1 -1
  159. data/app/views/alchemy/admin/clipboard/index.html.erb +3 -3
  160. data/app/views/alchemy/admin/clipboard/insert.js.erb +3 -3
  161. data/app/views/alchemy/admin/clipboard/remove.js.erb +2 -2
  162. data/app/views/alchemy/admin/contents/_missing.html.erb +5 -7
  163. data/app/views/alchemy/admin/contents/create.js.erb +1 -1
  164. data/app/views/alchemy/admin/contents/new.html.erb +2 -2
  165. data/app/views/alchemy/admin/dashboard/_locked_pages.html.erb +6 -6
  166. data/app/views/alchemy/admin/dashboard/_recent_pages.html.erb +2 -2
  167. data/app/views/alchemy/admin/dashboard/_users.html.erb +2 -2
  168. data/app/views/alchemy/admin/dashboard/help.html.erb +15 -15
  169. data/app/views/alchemy/admin/dashboard/index.html.erb +6 -6
  170. data/app/views/alchemy/admin/dashboard/info.html.erb +5 -5
  171. data/app/views/alchemy/admin/elements/_add_picture.html.erb +1 -1
  172. data/app/views/alchemy/admin/elements/_element.html.erb +52 -18
  173. data/app/views/alchemy/admin/elements/_element_footer.html.erb +11 -0
  174. data/app/views/alchemy/admin/elements/{_element_head.html.erb → _element_header.html.erb} +8 -8
  175. data/app/views/alchemy/admin/elements/_element_toolbar.html.erb +49 -0
  176. data/app/views/alchemy/admin/elements/_new_element_form.html.erb +7 -6
  177. data/app/views/alchemy/admin/elements/_picture_gallery_editor.html.erb +1 -1
  178. data/app/views/alchemy/admin/elements/_refresh_editor.js.erb +1 -1
  179. data/app/views/alchemy/admin/elements/create.js.erb +13 -8
  180. data/app/views/alchemy/admin/elements/fold.js.erb +12 -7
  181. data/app/views/alchemy/admin/elements/index.html.erb +12 -8
  182. data/app/views/alchemy/admin/elements/list.html.erb +3 -3
  183. data/app/views/alchemy/admin/elements/new.html.erb +4 -4
  184. data/app/views/alchemy/admin/elements/order.js.erb +3 -4
  185. data/app/views/alchemy/admin/elements/publish.js.erb +15 -0
  186. data/app/views/alchemy/admin/elements/trash.js.erb +3 -3
  187. data/app/views/alchemy/admin/elements/update.js.erb +7 -8
  188. data/app/views/alchemy/admin/essence_files/edit.html.erb +16 -13
  189. data/app/views/alchemy/admin/essence_pictures/crop.html.erb +3 -3
  190. data/app/views/alchemy/admin/essence_pictures/edit.html.erb +8 -8
  191. data/app/views/alchemy/admin/languages/_form.html.erb +12 -3
  192. data/app/views/alchemy/admin/languages/_language.html.erb +8 -2
  193. data/app/views/alchemy/admin/languages/_table.html.erb +11 -5
  194. data/app/views/alchemy/admin/languages/index.html.erb +1 -1
  195. data/app/views/alchemy/admin/layoutpages/_layoutpage.html.erb +8 -8
  196. data/app/views/alchemy/admin/layoutpages/edit.html.erb +2 -2
  197. data/app/views/alchemy/admin/layoutpages/index.html.erb +6 -13
  198. data/app/views/alchemy/admin/leave.html.erb +5 -5
  199. data/app/views/alchemy/admin/legacy_page_urls/_form.html.erb +1 -1
  200. data/app/views/alchemy/admin/legacy_page_urls/_legacy_page_url.html.erb +4 -4
  201. data/app/views/alchemy/admin/legacy_page_urls/_new.html.erb +1 -1
  202. data/app/views/alchemy/admin/pages/_create_language_form.html.erb +9 -9
  203. data/app/views/alchemy/admin/pages/_external_link.html.erb +6 -6
  204. data/app/views/alchemy/admin/pages/_file_link.html.erb +6 -6
  205. data/app/views/alchemy/admin/pages/_form.html.erb +6 -6
  206. data/app/views/alchemy/admin/pages/_internal_link.html.erb +9 -11
  207. data/app/views/alchemy/admin/pages/_legacy_urls.html.erb +3 -3
  208. data/app/views/alchemy/admin/pages/_locked_page.html.erb +4 -4
  209. data/app/views/alchemy/admin/pages/_new_page_form.html.erb +2 -2
  210. data/app/views/alchemy/admin/pages/_page.html.erb +95 -80
  211. data/app/views/alchemy/admin/pages/_page_for_links.html.erb +22 -22
  212. data/app/views/alchemy/admin/pages/_page_infos.html.erb +12 -0
  213. data/app/views/alchemy/admin/pages/_page_status.html.erb +7 -9
  214. data/app/views/alchemy/admin/pages/_sitemap.html.erb +35 -6
  215. data/app/views/alchemy/admin/pages/_tinymce_custom_config.html.erb +0 -3
  216. data/app/views/alchemy/admin/pages/configure.html.erb +1 -1
  217. data/app/views/alchemy/admin/pages/configure_external.html.erb +4 -4
  218. data/app/views/alchemy/admin/pages/edit.html.erb +39 -44
  219. data/app/views/alchemy/admin/pages/flush.js.erb +1 -1
  220. data/app/views/alchemy/admin/pages/fold.js.erb +2 -3
  221. data/app/views/alchemy/admin/pages/index.html.erb +15 -22
  222. data/app/views/alchemy/admin/pages/info.html.erb +8 -8
  223. data/app/views/alchemy/admin/pages/link.html.erb +3 -3
  224. data/app/views/alchemy/admin/pages/locked.html.erb +1 -1
  225. data/app/views/alchemy/admin/pages/new.html.erb +4 -4
  226. data/app/views/alchemy/admin/pages/sort.js.erb +1 -2
  227. data/app/views/alchemy/admin/pages/unlock.js.erb +1 -1
  228. data/app/views/alchemy/admin/pages/update.js.erb +3 -3
  229. data/app/views/alchemy/admin/partials/_autocomplete_tag_list.html.erb +1 -1
  230. data/app/views/alchemy/admin/partials/_language_tree_select.html.erb +1 -1
  231. data/app/views/alchemy/admin/partials/_main_navigation_entry.html.erb +1 -1
  232. data/app/views/alchemy/admin/partials/_remote_search_form.html.erb +9 -15
  233. data/app/views/alchemy/admin/partials/_search_form.html.erb +14 -13
  234. data/app/views/alchemy/admin/partials/_sub_navigation.html.erb +1 -1
  235. data/app/views/alchemy/admin/pictures/_archive.html.erb +14 -14
  236. data/app/views/alchemy/admin/pictures/_filter_and_size_bar.html.erb +30 -36
  237. data/app/views/alchemy/admin/pictures/_filter_bar.html.erb +5 -5
  238. data/app/views/alchemy/admin/pictures/{edit.html.erb → _form.html.erb} +7 -6
  239. data/app/views/alchemy/admin/pictures/_infos.html.erb +50 -0
  240. data/app/views/alchemy/admin/pictures/_overlay_picture_list.html.erb +1 -1
  241. data/app/views/alchemy/admin/pictures/_picture.html.erb +17 -51
  242. data/app/views/alchemy/admin/pictures/_picture_to_assign.html.erb +1 -1
  243. data/app/views/alchemy/admin/pictures/_tag_list.html.erb +2 -2
  244. data/app/views/alchemy/admin/pictures/edit_multiple.html.erb +6 -6
  245. data/app/views/alchemy/admin/pictures/index.html.erb +28 -36
  246. data/app/views/alchemy/admin/pictures/show.html.erb +46 -9
  247. data/app/views/alchemy/admin/pictures/update.js.erb +6 -0
  248. data/app/views/alchemy/admin/resources/_form.html.erb +3 -3
  249. data/app/views/alchemy/admin/resources/_resource.html.erb +4 -4
  250. data/app/views/alchemy/admin/resources/_table.html.erb +5 -6
  251. data/app/views/alchemy/admin/resources/index.csv.erb +12 -10
  252. data/app/views/alchemy/admin/resources/index.html.erb +4 -4
  253. data/app/views/alchemy/admin/sites/index.html.erb +1 -1
  254. data/app/views/alchemy/admin/tags/_tag.html.erb +4 -4
  255. data/app/views/alchemy/admin/tags/edit.html.erb +5 -5
  256. data/app/views/alchemy/admin/tags/index.html.erb +8 -8
  257. data/app/views/alchemy/admin/tags/new.html.erb +2 -2
  258. data/app/views/alchemy/admin/trash/clear.js.erb +1 -1
  259. data/app/views/alchemy/admin/trash/index.html.erb +8 -6
  260. data/app/views/alchemy/admin/uploader/_button.html.erb +39 -0
  261. data/app/views/alchemy/admin/uploader/_setup.html.erb +13 -0
  262. data/app/views/alchemy/base/500.html.erb +4 -4
  263. data/app/views/alchemy/elements/_editor_not_found.html.erb +1 -1
  264. data/app/views/alchemy/essences/_essence_boolean_editor.html.erb +3 -4
  265. data/app/views/alchemy/essences/_essence_boolean_view.html.erb +1 -1
  266. data/app/views/alchemy/essences/_essence_date_editor.html.erb +2 -6
  267. data/app/views/alchemy/essences/_essence_date_view.html.erb +1 -1
  268. data/app/views/alchemy/essences/_essence_file_editor.html.erb +9 -11
  269. data/app/views/alchemy/essences/_essence_file_view.html.erb +11 -5
  270. data/app/views/alchemy/essences/_essence_html_editor.html.erb +1 -1
  271. data/app/views/alchemy/essences/_essence_link_editor.html.erb +1 -1
  272. data/app/views/alchemy/essences/_essence_link_view.html.erb +1 -1
  273. data/app/views/alchemy/essences/_essence_picture_editor.html.erb +47 -52
  274. data/app/views/alchemy/essences/_essence_richtext_editor.html.erb +1 -1
  275. data/app/views/alchemy/essences/_essence_richtext_view.html.erb +1 -1
  276. data/app/views/alchemy/essences/_essence_select_editor.html.erb +23 -13
  277. data/app/views/alchemy/essences/_essence_text_editor.html.erb +1 -1
  278. data/app/views/alchemy/essences/_essence_text_view.html.erb +1 -1
  279. data/app/views/alchemy/essences/shared/_essence_picture_tools.html.erb +29 -36
  280. data/app/views/alchemy/essences/shared/_linkable_essence_tools.html.erb +5 -5
  281. data/app/views/alchemy/language_links/_language.html.erb +15 -9
  282. data/app/views/alchemy/messages/contact_form_mail.de.text.erb +1 -1
  283. data/app/views/alchemy/messages/contact_form_mail.en.text.erb +1 -1
  284. data/app/views/alchemy/messages/contact_form_mail.es.text.erb +1 -1
  285. data/app/views/alchemy/navigation/_link.html.erb +0 -1
  286. data/app/views/alchemy/pages/show.rss.builder +6 -4
  287. data/app/views/alchemy/welcome.html.erb +28 -0
  288. data/app/views/layouts/alchemy/admin.html.erb +14 -10
  289. data/bin/alchemy +3 -4
  290. data/bin/rspec +7 -0
  291. data/bin/spring +15 -0
  292. data/config/alchemy/config.yml +16 -17
  293. data/config/initializers/assets.rb +13 -0
  294. data/config/locales/alchemy.de.yml +27 -29
  295. data/config/locales/alchemy.en.yml +23 -29
  296. data/config/locales/alchemy.es.yml +23 -29
  297. data/config/locales/alchemy.fr.yml +19 -28
  298. data/config/locales/alchemy.nl.yml +19 -27
  299. data/config/locales/alchemy.ru.yml +19 -28
  300. data/config/routes.rb +53 -54
  301. data/config/spring.rb +2 -0
  302. data/db/migrate/20130827094554_alchemy_two_point_six.rb +1 -3
  303. data/db/migrate/20150608204610_add_parent_element_id_to_alchemy_elements.rb +6 -0
  304. data/db/migrate/20150729151825_add_link_text_to_alchemy_essence_files.rb +5 -0
  305. data/db/migrate/20150906195818_add_locale_to_alchemy_languages.rb +7 -0
  306. data/lib/alchemy/auth_accessors.rb +1 -1
  307. data/lib/alchemy/cache_digests/template_tracker.rb +7 -13
  308. data/lib/alchemy/config.rb +5 -7
  309. data/lib/alchemy/configuration_methods.rb +11 -1
  310. data/lib/alchemy/controller_actions.rb +9 -12
  311. data/lib/alchemy/engine.rb +11 -28
  312. data/lib/alchemy/errors.rb +0 -1
  313. data/lib/alchemy/essence.rb +20 -20
  314. data/lib/alchemy/filetypes.rb +1 -3
  315. data/lib/alchemy/forms/builder.rb +0 -2
  316. data/lib/alchemy/hints.rb +1 -3
  317. data/lib/alchemy/i18n.rb +81 -53
  318. data/lib/alchemy/kaminari/scoped_pagination_url_helper.rb +0 -2
  319. data/lib/alchemy/locale.rb +0 -1
  320. data/lib/alchemy/logger.rb +1 -3
  321. data/lib/alchemy/modules.rb +3 -3
  322. data/lib/alchemy/mount_point.rb +0 -2
  323. data/lib/alchemy/name_conversions.rb +1 -3
  324. data/lib/alchemy/on_page_layout.rb +37 -23
  325. data/lib/alchemy/on_page_layout/callbacks_runner.rb +34 -0
  326. data/lib/alchemy/page_layout.rb +23 -24
  327. data/lib/alchemy/paths.rb +32 -0
  328. data/lib/alchemy/permissions.rb +20 -20
  329. data/lib/alchemy/picture_attributes.rb +0 -3
  330. data/lib/alchemy/resource.rb +66 -22
  331. data/lib/alchemy/resources_helper.rb +48 -11
  332. data/lib/alchemy/routing_constraints.rb +4 -5
  333. data/lib/alchemy/seeder.rb +1 -4
  334. data/lib/alchemy/shell.rb +12 -14
  335. data/lib/alchemy/tasks/helpers.rb +5 -7
  336. data/lib/alchemy/test_support/essence_shared_examples.rb +24 -24
  337. data/lib/alchemy/test_support/factories.rb +2 -146
  338. data/lib/alchemy/test_support/factories/attachment_factory.rb +9 -0
  339. data/lib/alchemy/test_support/factories/cell_factory.rb +9 -0
  340. data/lib/alchemy/test_support/factories/content_factory.rb +10 -0
  341. data/lib/alchemy/test_support/factories/dummy_user_factory.rb +21 -0
  342. data/lib/alchemy/test_support/factories/element_factory.rb +21 -0
  343. data/lib/alchemy/test_support/factories/essence_file_factory.rb +8 -0
  344. data/lib/alchemy/test_support/factories/essence_picture_factory.rb +8 -0
  345. data/lib/alchemy/test_support/factories/essence_text_factory.rb +7 -0
  346. data/lib/alchemy/test_support/factories/language_factory.rb +28 -0
  347. data/lib/alchemy/test_support/factories/page_factory.rb +45 -0
  348. data/lib/alchemy/test_support/factories/picture_factory.rb +10 -0
  349. data/lib/alchemy/test_support/factories/site_factory.rb +12 -0
  350. data/lib/alchemy/test_support/integration_helpers.rb +0 -3
  351. data/lib/alchemy/tinymce.rb +24 -35
  352. data/lib/alchemy/touching.rb +5 -6
  353. data/lib/alchemy/upgrader.rb +3 -5
  354. data/lib/alchemy/upgrader/tasks/available_contents_upgrader.rb +155 -0
  355. data/lib/alchemy/upgrader/tasks/nestable_elements_migration.rb +71 -0
  356. data/lib/alchemy/upgrader/tasks/three_point_two_task.rb +31 -0
  357. data/lib/alchemy/upgrader/three_point_three.rb +50 -0
  358. data/lib/alchemy/upgrader/three_point_two.rb +3 -32
  359. data/lib/alchemy/upgrader/three_point_zero.rb +0 -1
  360. data/lib/alchemy/version.rb +1 -1
  361. data/lib/rails/generators/alchemy/base.rb +1 -1
  362. data/lib/rails/generators/alchemy/elements/elements_generator.rb +1 -7
  363. data/lib/rails/generators/alchemy/elements/templates/editor.html.erb +5 -7
  364. data/lib/rails/generators/alchemy/elements/templates/editor.html.haml +6 -8
  365. data/lib/rails/generators/alchemy/elements/templates/editor.html.slim +6 -7
  366. data/lib/rails/generators/alchemy/elements/templates/view.html.erb +4 -4
  367. data/lib/rails/generators/alchemy/elements/templates/view.html.haml +3 -3
  368. data/lib/rails/generators/alchemy/elements/templates/view.html.slim +3 -3
  369. data/lib/rails/generators/alchemy/essence/essence_generator.rb +2 -3
  370. data/lib/rails/generators/alchemy/essence/templates/editor.html.erb +1 -1
  371. data/lib/rails/generators/alchemy/install/files/alchemy.de.yml +2 -2
  372. data/lib/rails/generators/alchemy/install/files/alchemy.en.yml +2 -2
  373. data/lib/rails/generators/alchemy/install/files/alchemy.es.yml +3 -3
  374. data/lib/rails/generators/alchemy/install/install_generator.rb +0 -1
  375. data/lib/rails/generators/alchemy/install/templates/elements.yml.tt +2 -2
  376. data/lib/rails/generators/alchemy/install/templates/page_layouts.yml.tt +1 -1
  377. data/lib/rails/generators/alchemy/module/module_generator.rb +1 -1
  378. data/lib/rails/templates/alchemy.rb +2 -2
  379. data/lib/tasks/alchemy/convert.rake +4 -8
  380. data/lib/tasks/alchemy/db.rake +2 -3
  381. data/lib/tasks/alchemy/install.rake +3 -4
  382. data/lib/tasks/alchemy/tidy.rake +4 -5
  383. data/lib/tasks/alchemy/upgrade.rake +2 -4
  384. data/spec/controllers/{admin → alchemy/admin}/attachments_controller_spec.rb +26 -44
  385. data/spec/controllers/{admin → alchemy/admin}/base_controller_spec.rb +14 -1
  386. data/spec/controllers/{admin → alchemy/admin}/clipboard_controller_spec.rb +3 -3
  387. data/spec/controllers/{admin → alchemy/admin}/contents_controller_spec.rb +4 -4
  388. data/spec/controllers/{admin → alchemy/admin}/dashboard_controller_spec.rb +11 -6
  389. data/spec/controllers/{admin → alchemy/admin}/elements_controller_spec.rb +54 -31
  390. data/spec/controllers/{admin → alchemy/admin}/essence_files_controller_spec.rb +8 -3
  391. data/spec/controllers/{admin → alchemy/admin}/essence_pictures_controller_spec.rb +3 -3
  392. data/spec/controllers/{admin → alchemy/admin}/languages_controller_spec.rb +13 -1
  393. data/spec/controllers/{admin → alchemy/admin}/layoutpages_controller_spec.rb +0 -6
  394. data/spec/controllers/{admin → alchemy/admin}/pages_controller_spec.rb +103 -35
  395. data/spec/controllers/{admin → alchemy/admin}/pictures_controller_spec.rb +133 -108
  396. data/spec/controllers/alchemy/admin/resources_controller_spec.rb +81 -0
  397. data/spec/controllers/{admin → alchemy/admin}/trash_controller_spec.rb +12 -13
  398. data/spec/controllers/alchemy/api/contents_controller_spec.rb +12 -13
  399. data/spec/controllers/alchemy/api/elements_controller_spec.rb +8 -9
  400. data/spec/controllers/alchemy/api/pages_controller_spec.rb +40 -7
  401. data/spec/controllers/{attachments_controller_spec.rb → alchemy/attachments_controller_spec.rb} +7 -7
  402. data/spec/controllers/alchemy/base_controller_spec.rb +106 -0
  403. data/spec/controllers/{elements_controller_spec.rb → alchemy/elements_controller_spec.rb} +4 -4
  404. data/spec/controllers/{messages_controller_spec.rb → alchemy/messages_controller_spec.rb} +14 -9
  405. data/spec/controllers/alchemy/on_page_layout_mixin_spec.rb +330 -0
  406. data/spec/controllers/{pages_controller_spec.rb → alchemy/pages_controller_spec.rb} +167 -89
  407. data/spec/controllers/{pictures_controller_spec.rb → alchemy/pictures_controller_spec.rb} +42 -20
  408. data/spec/dummy/app/models/dummy_user.rb +4 -0
  409. data/spec/dummy/app/views/alchemy/elements/_all_you_can_eat_view.html.erb +31 -0
  410. data/spec/dummy/app/views/alchemy/elements/_article_editor.html.erb +6 -10
  411. data/spec/dummy/app/views/alchemy/elements/_article_view.html.erb +9 -24
  412. data/spec/dummy/app/views/alchemy/elements/_bild_editor.html.erb +3 -0
  413. data/spec/dummy/app/views/alchemy/elements/_bild_view.html.erb +5 -0
  414. data/spec/dummy/app/views/alchemy/elements/_contactform_editor.html.erb +6 -0
  415. data/spec/dummy/app/views/alchemy/elements/_contactform_view.html.erb +16 -0
  416. data/spec/dummy/app/views/alchemy/elements/_download_editor.html.erb +3 -0
  417. data/spec/dummy/app/views/alchemy/elements/_download_view.html.erb +5 -0
  418. data/spec/dummy/app/views/alchemy/elements/_erb_element_editor.html.erb +3 -0
  419. data/spec/dummy/app/views/alchemy/elements/_erb_element_view.html.erb +5 -0
  420. data/spec/dummy/app/views/alchemy/elements/_header_editor.html.erb +3 -0
  421. data/spec/dummy/app/views/alchemy/elements/_header_view.html.erb +5 -0
  422. data/spec/dummy/app/views/alchemy/elements/_news_editor.html.erb +5 -0
  423. data/spec/dummy/app/views/alchemy/elements/_search_editor.html.erb +1 -0
  424. data/spec/dummy/app/views/alchemy/elements/_search_view.html.erb +4 -0
  425. data/spec/dummy/app/views/alchemy/elements/_slide_editor.html.erb +3 -0
  426. data/spec/dummy/app/views/alchemy/elements/_slide_view.html.erb +5 -0
  427. data/spec/dummy/app/views/alchemy/elements/_slider_editor.html.erb +2 -0
  428. data/spec/dummy/app/views/alchemy/elements/_slider_view.html.erb +4 -0
  429. data/spec/dummy/app/views/alchemy/elements/_text_editor.html.erb +3 -0
  430. data/spec/dummy/app/views/alchemy/elements/_text_view.html.erb +5 -0
  431. data/spec/dummy/app/views/alchemy/page_layouts/_standard.html.erb +1 -0
  432. data/spec/dummy/config/alchemy/elements.yml +10 -13
  433. data/spec/dummy/config/alchemy/page_layouts.yml +1 -1
  434. data/spec/dummy/config/initializers/alchemy.rb +1 -0
  435. data/spec/dummy/config/locales/kl.yml +2 -0
  436. data/spec/dummy/db/migrate/20150608204610_add_parent_element_id_to_alchemy_elements.rb +1 -0
  437. data/spec/dummy/db/migrate/20150729151825_add_link_text_to_alchemy_essence_files.rb +1 -0
  438. data/spec/dummy/db/migrate/20150906195818_add_locale_to_alchemy_languages.rb +1 -0
  439. data/spec/dummy/db/schema.rb +10 -6
  440. data/spec/factories.rb +13 -0
  441. data/spec/features/admin/admin_layout_spec.rb +14 -0
  442. data/spec/features/admin/dashboard_spec.rb +1 -2
  443. data/spec/features/admin/edit_elements_feature_spec.rb +36 -0
  444. data/spec/features/admin/language_tree_feature_spec.rb +7 -8
  445. data/spec/features/admin/languages_features_spec.rb +65 -0
  446. data/spec/features/admin/legacy_page_url_management_spec.rb +3 -3
  447. data/spec/features/admin/link_overlay_spec.rb +16 -17
  448. data/spec/features/admin/locale_select_feature_spec.rb +1 -1
  449. data/spec/features/admin/modules_integration_spec.rb +0 -1
  450. data/spec/features/admin/navigation_feature_spec.rb +11 -2
  451. data/spec/features/admin/page_creation_feature_spec.rb +5 -5
  452. data/spec/features/admin/page_editing_feature_spec.rb +6 -6
  453. data/spec/features/admin/picture_library_integration_spec.rb +3 -3
  454. data/spec/features/admin/resources_integration_spec.rb +7 -12
  455. data/spec/features/admin/site_select_feature_spec.rb +1 -2
  456. data/spec/features/admin/tinymce_feature_spec.rb +0 -1
  457. data/spec/features/page_feature_spec.rb +57 -158
  458. data/spec/features/page_redirects_spec.rb +358 -0
  459. data/spec/features/picture_security_spec.rb +1 -7
  460. data/spec/fixtures/animated.gif +0 -0
  461. data/spec/helpers/{admin → alchemy/admin}/attachments_helper_spec.rb +0 -0
  462. data/spec/helpers/{admin → alchemy/admin}/base_helper_spec.rb +39 -29
  463. data/spec/helpers/{admin → alchemy/admin}/contents_helper_spec.rb +4 -23
  464. data/spec/helpers/{admin → alchemy/admin}/elements_helper_spec.rb +141 -5
  465. data/spec/helpers/{admin → alchemy/admin}/essences_helper_spec.rb +69 -8
  466. data/spec/helpers/{admin → alchemy/admin}/navigation_helper_spec.rb +43 -37
  467. data/spec/helpers/{admin → alchemy/admin}/pages_helper_spec.rb +6 -38
  468. data/spec/helpers/{admin → alchemy/admin}/pictures_helper_spec.rb +0 -1
  469. data/spec/helpers/{admin → alchemy/admin}/tags_helper_spec.rb +1 -3
  470. data/spec/helpers/{base_helper_spec.rb → alchemy/base_helper_spec.rb} +1 -2
  471. data/spec/helpers/{elements_block_helper_spec.rb → alchemy/elements_block_helper_spec.rb} +3 -3
  472. data/spec/helpers/{elements_helper_spec.rb → alchemy/elements_helper_spec.rb} +18 -19
  473. data/spec/helpers/alchemy/essences_helper_spec.rb +85 -0
  474. data/spec/helpers/{pages_helper_spec.rb → alchemy/pages_helper_spec.rb} +125 -39
  475. data/spec/helpers/alchemy/picture_url_helpers_spec.rb +78 -0
  476. data/spec/helpers/{url_helper_spec.rb → alchemy/url_helper_spec.rb} +66 -40
  477. data/spec/libraries/config_spec.rb +2 -3
  478. data/spec/libraries/controller_actions_spec.rb +18 -18
  479. data/spec/libraries/i18n_spec.rb +7 -0
  480. data/spec/libraries/page_layout_spec.rb +13 -7
  481. data/spec/libraries/paths_spec.rb +15 -0
  482. data/spec/libraries/permissions_spec.rb +6 -7
  483. data/spec/libraries/resource_spec.rb +48 -75
  484. data/spec/libraries/resources_helper_spec.rb +55 -6
  485. data/spec/libraries/shell_spec.rb +0 -4
  486. data/spec/libraries/template_tracker_spec.rb +4 -13
  487. data/spec/libraries/tinymce_spec.rb +53 -9
  488. data/spec/mailers/{messages_spec.rb → alchemy/messages_spec.rb} +0 -2
  489. data/spec/models/{attachment_spec.rb → alchemy/attachment_spec.rb} +43 -20
  490. data/spec/models/{cell_spec.rb → alchemy/cell_spec.rb} +2 -3
  491. data/spec/models/{content_spec.rb → alchemy/content_spec.rb} +179 -70
  492. data/spec/models/{element_spec.rb → alchemy/element_spec.rb} +315 -70
  493. data/spec/models/{element_to_page_spec.rb → alchemy/element_to_page_spec.rb} +0 -1
  494. data/spec/models/{essence_boolean_spec.rb → alchemy/essence_boolean_spec.rb} +0 -0
  495. data/spec/models/{essence_date_spec.rb → alchemy/essence_date_spec.rb} +2 -3
  496. data/spec/models/{essence_file_spec.rb → alchemy/essence_file_spec.rb} +2 -5
  497. data/spec/models/{essence_html_spec.rb → alchemy/essence_html_spec.rb} +1 -1
  498. data/spec/models/{essence_link_spec.rb → alchemy/essence_link_spec.rb} +0 -0
  499. data/spec/models/{essence_picture_spec.rb → alchemy/essence_picture_spec.rb} +101 -29
  500. data/spec/models/{essence_richtext_spec.rb → alchemy/essence_richtext_spec.rb} +7 -2
  501. data/spec/models/{essence_select_spec.rb → alchemy/essence_select_spec.rb} +0 -0
  502. data/spec/models/{essence_text_spec.rb → alchemy/essence_text_spec.rb} +4 -8
  503. data/spec/models/alchemy/language_spec.rb +243 -0
  504. data/spec/models/{legacy_page_url_spec.rb → alchemy/legacy_page_url_spec.rb} +1 -1
  505. data/spec/models/{message_spec.rb → alchemy/message_spec.rb} +0 -0
  506. data/spec/models/{page_spec.rb → alchemy/page_spec.rb} +460 -248
  507. data/spec/models/{picture_spec.rb → alchemy/picture_spec.rb} +118 -30
  508. data/spec/models/{site_spec.rb → alchemy/site_spec.rb} +19 -84
  509. data/spec/models/{tag_spec.rb → alchemy/tag_spec.rb} +1 -3
  510. data/spec/models/dummy_model_spec.rb +1 -2
  511. data/spec/requests/alchemy/admin/resources_requests_spec.rb +26 -0
  512. data/spec/requests/alchemy/admin/site_requests_spec.rb +19 -0
  513. data/spec/requests/alchemy/site_requests_spec.rb +18 -0
  514. data/spec/requests/alchemy/sitemap_spec.rb +56 -0
  515. data/spec/routing/api_routing_spec.rb +1 -1
  516. data/spec/routing/routing_spec.rb +121 -15
  517. data/spec/spec_helper.rb +2 -1
  518. data/spec/support/hint_examples.rb +1 -3
  519. data/spec/support/test_tweaks.rb +3 -3
  520. data/spec/support/transformation_examples.rb +6 -7
  521. data/spec/tasks/helpers_spec.rb +2 -4
  522. data/spec/views/admin/pictures/show_spec.rb +43 -0
  523. data/spec/views/essences/essence_boolean_editor_spec.rb +0 -1
  524. data/spec/views/essences/essence_boolean_view_spec.rb +2 -4
  525. data/spec/views/essences/essence_date_view_spec.rb +0 -1
  526. data/spec/views/essences/essence_file_editor_spec.rb +4 -6
  527. data/spec/views/essences/essence_file_view_spec.rb +56 -3
  528. data/spec/views/essences/essence_link_view_spec.rb +1 -1
  529. data/spec/views/essences/essence_picture_editor_spec.rb +80 -0
  530. data/spec/views/essences/essence_picture_view_spec.rb +0 -1
  531. data/spec/views/essences/essence_select_view_spec.rb +0 -1
  532. data/spec/views/essences/essence_text_view_spec.rb +0 -1
  533. data/vendor/assets/javascripts/handlebars.js +4608 -0
  534. data/vendor/assets/javascripts/tinymce/langs/de.js +19 -0
  535. data/vendor/assets/javascripts/tinymce/langs/es.js +19 -0
  536. data/vendor/assets/javascripts/tinymce/langs/fr.js +23 -4
  537. data/vendor/assets/javascripts/tinymce/langs/nl.js +22 -3
  538. data/vendor/assets/javascripts/tinymce/langs/ru.js +22 -3
  539. data/vendor/assets/javascripts/tinymce/plugins/paste/plugin.min.js +1 -1
  540. data/vendor/assets/javascripts/tinymce/plugins/table/plugin.min.js +1 -1
  541. data/vendor/assets/javascripts/tinymce/themes/modern/theme.min.js +1 -1
  542. data/vendor/assets/javascripts/tinymce/tinymce.min.js +12 -13
  543. metadata +274 -256
  544. data/app/views/alchemy/admin/attachments/create.js.erb +0 -11
  545. data/app/views/alchemy/admin/attachments/new.html.erb +0 -14
  546. data/app/views/alchemy/admin/elements/_element_foot.html.erb +0 -36
  547. data/app/views/alchemy/admin/partials/_upload_form.html.erb +0 -67
  548. data/app/views/alchemy/admin/pictures/info.html.erb +0 -38
  549. data/app/views/alchemy/admin/pictures/new.html.erb +0 -16
  550. data/lib/alchemy/middleware/rescue_old_cookies.rb +0 -27
  551. data/spec/controllers/admin/resources_controller_spec.rb +0 -53
  552. data/spec/controllers/base_controller_spec.rb +0 -51
  553. data/spec/helpers/essences_helper_spec.rb +0 -156
  554. data/spec/helpers/picture_url_helpers_spec.rb +0 -35
  555. data/spec/libraries/on_page_layout_spec.rb +0 -112
  556. data/spec/models/language_spec.rb +0 -123
@@ -37,36 +37,87 @@ module Alchemy
37
37
  end
38
38
 
39
39
  describe '.copy' do
40
- let(:element) { FactoryGirl.create(:element, :create_contents_after_create => true, :tag_list => 'red, yellow') }
40
+ subject { Element.copy(element) }
41
+
42
+ let(:element) do
43
+ create(:alchemy_element, create_contents_after_create: true, tag_list: 'red, yellow')
44
+ end
41
45
 
42
46
  it "should not create contents from scratch" do
43
- copy = Element.copy(element)
44
- expect(copy.contents.count).to eq(element.contents.count)
47
+ expect(subject.contents.count).to eq(element.contents.count)
45
48
  end
46
49
 
47
- it "should create a new record with all attributes of source except given differences" do
48
- copy = Element.copy(element, {:name => 'foobar'})
49
- expect(copy.name).to eq('foobar')
50
+ context 'with differences' do
51
+ subject(:copy) { Element.copy(element, {name: 'foobar'}) }
52
+
53
+ it "should create a new record with all attributes of source except given differences" do
54
+ expect(copy.name).to eq('foobar')
55
+ end
50
56
  end
51
57
 
52
58
  it "should make copies of all contents of source" do
53
- copy = Element.copy(element)
54
- expect(copy.contents.pluck(:id)).not_to eq(element.contents.pluck(:id))
59
+ expect(subject.contents).not_to be_empty
60
+ expect(subject.contents.pluck(:id)).not_to eq(element.contents.pluck(:id))
55
61
  end
56
62
 
57
63
  it "the copy should include source element tags" do
58
- copy = Element.copy(element)
59
- expect(copy.tag_list).to eq(element.tag_list)
64
+ expect(subject.tag_list).to eq(element.tag_list)
65
+ end
66
+
67
+ context 'with nested elements' do
68
+ let(:element) do
69
+ create(:alchemy_element, :with_nestable_elements, {
70
+ create_contents_after_create: true,
71
+ tag_list: 'red, yellow',
72
+ page: create(:alchemy_page)
73
+ })
74
+ end
75
+
76
+ before do
77
+ element.nested_elements << create(:alchemy_element, name: 'slide')
78
+ end
79
+
80
+ it "should copy nested elements" do
81
+ expect(subject.nested_elements).to_not be_empty
82
+ end
83
+
84
+ context 'copy to new page' do
85
+ let(:new_page) { create(:alchemy_page) }
86
+
87
+ subject(:new_element) do
88
+ Element.copy(element, {page_id: new_page.id})
89
+ end
90
+
91
+ it "should set page id to new page's id" do
92
+ new_element.nested_elements.each do |nested_element|
93
+ expect(nested_element.page_id).to eq(new_page.id)
94
+ end
95
+ end
96
+ end
97
+
98
+ context 'copy to new cell' do
99
+ let(:new_cell) { create(:alchemy_cell) }
100
+
101
+ subject(:new_element) do
102
+ Element.copy(element, {cell_id: new_cell.id})
103
+ end
104
+
105
+ it "should set cell id to new cell's id" do
106
+ new_element.nested_elements.each do |nested_element|
107
+ expect(nested_element.cell_id).to eq(new_cell.id)
108
+ end
109
+ end
110
+ end
60
111
  end
61
112
  end
62
113
 
63
114
  describe '.definitions' do
64
115
  it "should allow erb generated elements" do
65
- expect(Element.definitions.collect { |el| el['name']} ).to include('erb_element')
116
+ expect(Element.definitions.collect { |el| el['name'] }).to include('erb_element')
66
117
  end
67
118
 
68
119
  context "without existing yml files" do
69
- before { allow(File).to receive(:exists?).and_return(false) }
120
+ before { allow(File).to receive(:exist?).and_return(false) }
70
121
 
71
122
  it "should raise an error" do
72
123
  expect { Element.definitions }.to raise_error(LoadError)
@@ -85,7 +136,7 @@ module Alchemy
85
136
 
86
137
  describe '.display_name_for' do
87
138
  it "should return the translation for the given name" do
88
- expect(I18n).to receive(:t).with('subheadline', scope: "element_names", default: 'Subheadline').and_return('Überschrift')
139
+ expect(Alchemy).to receive(:t).with('subheadline', scope: "element_names", default: 'Subheadline').and_return('Überschrift')
89
140
  expect(Element.display_name_for('subheadline')).to eq('Überschrift')
90
141
  end
91
142
 
@@ -96,44 +147,64 @@ module Alchemy
96
147
 
97
148
  describe '.excluded' do
98
149
  it "should return all elements but excluded ones" do
99
- FactoryGirl.create(:element, :name => 'article')
100
- FactoryGirl.create(:element, :name => 'article')
101
- excluded = FactoryGirl.create(:element, :name => 'claim')
150
+ create(:alchemy_element, name: 'article')
151
+ create(:alchemy_element, name: 'article')
152
+ excluded = create(:alchemy_element, name: 'claim')
102
153
  expect(Element.excluded(['claim'])).not_to include(excluded)
103
154
  end
104
155
  end
105
156
 
106
157
  describe '.named' do
107
158
  it "should return all elements by name" do
108
- element_1 = FactoryGirl.create(:element, :name => 'article')
109
- element_2 = FactoryGirl.create(:element, :name => 'article')
159
+ element_1 = create(:alchemy_element, name: 'article')
160
+ element_2 = create(:alchemy_element, name: 'headline')
110
161
  elements = Element.named(['article'])
111
162
  expect(elements).to include(element_1)
112
- expect(elements).to include(element_2)
163
+ expect(elements).to_not include(element_2)
113
164
  end
114
165
  end
115
166
 
116
167
  describe '.not_in_cell' do
117
168
  it "should return all elements that are not in a cell" do
118
169
  Element.delete_all
119
- FactoryGirl.create(:element, :cell_id => 6)
120
- FactoryGirl.create(:element, :cell_id => nil)
170
+ create(:alchemy_element, cell_id: 6)
171
+ create(:alchemy_element, cell_id: nil)
121
172
  expect(Element.not_in_cell.size).to eq(1)
122
173
  end
123
174
  end
124
175
 
125
176
  describe '.published' do
126
177
  it "should return all public elements" do
127
- element_1 = FactoryGirl.create(:element, :public => true)
128
- element_2 = FactoryGirl.create(:element, :public => true)
178
+ element_1 = create(:alchemy_element, public: true)
179
+ element_2 = create(:alchemy_element, public: false)
129
180
  elements = Element.published
130
181
  expect(elements).to include(element_1)
131
- expect(elements).to include(element_2)
182
+ expect(elements).to_not include(element_2)
183
+ end
184
+ end
185
+
186
+ describe '.folded' do
187
+ it "returns all folded elements" do
188
+ element_1 = create(:alchemy_element, folded: true)
189
+ element_2 = create(:alchemy_element, folded: false)
190
+ elements = Element.folded
191
+ expect(elements).to include(element_1)
192
+ expect(elements).to_not include(element_2)
193
+ end
194
+ end
195
+
196
+ describe '.expanded' do
197
+ it "returns all expanded elements" do
198
+ element_1 = create(:alchemy_element, folded: false)
199
+ element_2 = create(:alchemy_element, folded: true)
200
+ elements = Element.expanded
201
+ expect(elements).to include(element_1)
202
+ expect(elements).to_not include(element_2)
132
203
  end
133
204
  end
134
205
 
135
206
  context 'trash' do
136
- let(:element) { FactoryGirl.create(:element, page_id: 1) }
207
+ let(:element) { create(:alchemy_element, page_id: 1) }
137
208
 
138
209
  describe '.not_trashed' do
139
210
  before { element }
@@ -153,9 +224,9 @@ module Alchemy
153
224
  end
154
225
 
155
226
  describe '.all_from_clipboard_for_page' do
156
- let(:element_1) { FactoryGirl.build_stubbed(:element) }
157
- let(:element_2) { FactoryGirl.build_stubbed(:element, name: 'news') }
158
- let(:page) { FactoryGirl.build_stubbed(:public_page) }
227
+ let(:element_1) { build_stubbed(:alchemy_element) }
228
+ let(:element_2) { build_stubbed(:alchemy_element, name: 'news') }
229
+ let(:page) { build_stubbed(:alchemy_page, :public) }
159
230
  let(:clipboard) { [{'id' => element_1.id.to_s}, {'id' => element_2.id.to_s}] }
160
231
 
161
232
  before do
@@ -184,7 +255,7 @@ module Alchemy
184
255
  # InstanceMethods
185
256
 
186
257
  describe '#all_contents_by_type' do
187
- let(:element) { FactoryGirl.create(:element, create_contents_after_create: true) }
258
+ let(:element) { create(:alchemy_element, create_contents_after_create: true) }
188
259
  let(:expected_contents) { element.contents.essence_texts }
189
260
 
190
261
  context "with namespaced essence type" do
@@ -201,8 +272,8 @@ module Alchemy
201
272
  end
202
273
 
203
274
  describe '#available_page_cell_names' do
204
- let(:page) { FactoryGirl.create(:public_page) }
205
- let(:element) { FactoryGirl.create(:element, page: page) }
275
+ let(:page) { create(:alchemy_page, :public) }
276
+ let(:element) { create(:alchemy_element, page: page) }
206
277
 
207
278
  context "with page having cells defining the correct elements" do
208
279
  before do
@@ -214,9 +285,9 @@ module Alchemy
214
285
  end
215
286
 
216
287
  it "should return a list of all cells from given page this element could be placed in" do
217
- FactoryGirl.create(:cell, name: 'header', page: page)
218
- FactoryGirl.create(:cell, name: 'footer', page: page)
219
- FactoryGirl.create(:cell, name: 'sidebar', page: page)
288
+ create(:alchemy_cell, name: 'header', page: page)
289
+ create(:alchemy_cell, name: 'footer', page: page)
290
+ create(:alchemy_cell, name: 'sidebar', page: page)
220
291
  expect(element.available_page_cell_names(page)).to include('header')
221
292
  expect(element.available_page_cell_names(page)).to include('footer')
222
293
  end
@@ -226,7 +297,6 @@ module Alchemy
226
297
  expect(element.available_page_cell_names(page)).to eq(['for_other_elements'])
227
298
  end
228
299
  end
229
-
230
300
  end
231
301
 
232
302
  context "with page having cells defining the wrong elements" do
@@ -239,9 +309,9 @@ module Alchemy
239
309
  end
240
310
 
241
311
  it "should return the 'nil cell'" do
242
- FactoryGirl.create(:cell, name: 'header', page: page)
243
- FactoryGirl.create(:cell, name: 'footer', page: page)
244
- FactoryGirl.create(:cell, name: 'sidebar', page: page)
312
+ create(:alchemy_cell, name: 'header', page: page)
313
+ create(:alchemy_cell, name: 'footer', page: page)
314
+ create(:alchemy_cell, name: 'sidebar', page: page)
245
315
  expect(element.available_page_cell_names(page)).to eq(['for_other_elements'])
246
316
  end
247
317
  end
@@ -249,7 +319,7 @@ module Alchemy
249
319
 
250
320
  describe '#content_by_type' do
251
321
  before(:each) do
252
- @element = FactoryGirl.create(:element, :name => 'headline')
322
+ @element = create(:alchemy_element, name: 'headline')
253
323
  @content = @element.contents.first
254
324
  end
255
325
 
@@ -275,17 +345,34 @@ module Alchemy
275
345
  end
276
346
  end
277
347
 
348
+ describe '#essence_errors' do
349
+ let(:element) { Element.new(name: 'article') }
350
+ let(:content) { Content.new(name: 'headline') }
351
+ let(:essence) { EssenceText.new(body: '') }
352
+
353
+ before do
354
+ allow(element).to receive(:contents) { [content] }
355
+ allow(content).to receive(:essence) { essence }
356
+ allow(content).to receive(:essence_validation_failed?) { true }
357
+ allow(essence).to receive(:validation_errors) { 'Cannot be blank' }
358
+ end
359
+
360
+ it "returns hash with essence errors" do
361
+ expect(element.essence_errors).to eq({'headline' => 'Cannot be blank'})
362
+ end
363
+ end
364
+
278
365
  describe '#essence_error_messages' do
279
366
  let(:element) { Element.new(name: 'article') }
280
367
 
281
368
  it "should return the translation with the translated content label" do
282
- expect(I18n).to receive(:t)
369
+ expect(Alchemy).to receive(:t)
283
370
  .with('content_names.content', default: 'Content')
284
371
  .and_return('Content')
285
- expect(I18n).to receive(:t)
372
+ expect(Alchemy).to receive(:t)
286
373
  .with('content', scope: "content_names.article", default: 'Content')
287
374
  .and_return('Contenido')
288
- expect(I18n).to receive(:t)
375
+ expect(Alchemy).to receive(:t)
289
376
  .with('article.content.invalid', {
290
377
  scope: "content_validations",
291
378
  default: [:"fields.content.invalid", :"errors.invalid"],
@@ -298,7 +385,7 @@ module Alchemy
298
385
  end
299
386
 
300
387
  describe '#display_name_with_preview_text' do
301
- let(:element) { FactoryGirl.build_stubbed(:element, name: 'Foo') }
388
+ let(:element) { build_stubbed(:alchemy_element, name: 'Foo') }
302
389
 
303
390
  it "returns a string with display name and preview text" do
304
391
  allow(element).to receive(:preview_text).and_return('Fula')
@@ -307,7 +394,7 @@ module Alchemy
307
394
  end
308
395
 
309
396
  describe '#dom_id' do
310
- let(:element) { FactoryGirl.build_stubbed(:element) }
397
+ let(:element) { build_stubbed(:alchemy_element) }
311
398
 
312
399
  it "returns an string from element name and id" do
313
400
  expect(element.dom_id).to eq("#{element.name}_#{element.id}")
@@ -315,14 +402,26 @@ module Alchemy
315
402
  end
316
403
 
317
404
  describe '#preview_text' do
318
- let(:element) { FactoryGirl.build_stubbed(:element) }
319
- let(:content) { mock_model(Content, preview_text: 'Lorem', preview_content?: false) }
320
- let(:content_2) { mock_model(Content, preview_text: 'Lorem', preview_content?: false) }
321
- let(:preview_content) { mock_model(Content, preview_text: 'Lorem', preview_content?: true) }
405
+ let(:element) { build_stubbed(:alchemy_element) }
406
+
407
+ let(:content) do
408
+ mock_model(Content, preview_text: 'Content 1', preview_content?: false)
409
+ end
410
+
411
+ let(:content_2) do
412
+ mock_model(Content, preview_text: 'Content 2', preview_content?: false)
413
+ end
414
+
415
+ let(:preview_content) do
416
+ mock_model(Content, preview_text: 'Preview Content', preview_content?: true)
417
+ end
322
418
 
323
419
  context "without a content marked as preview" do
324
420
  let(:contents) { [content, content_2] }
325
- before { allow(element).to receive(:contents).and_return(contents) }
421
+
422
+ before do
423
+ allow(element).to receive(:contents).and_return(contents)
424
+ end
326
425
 
327
426
  it "returns the preview text of first content found" do
328
427
  expect(content).to receive(:preview_text).with(30)
@@ -332,7 +431,10 @@ module Alchemy
332
431
 
333
432
  context "with a content marked as preview" do
334
433
  let(:contents) { [content, preview_content] }
335
- before { allow(element).to receive(:contents).and_return(contents) }
434
+
435
+ before do
436
+ allow(element).to receive(:contents).and_return(contents)
437
+ end
336
438
 
337
439
  it "should return the preview_text of this content" do
338
440
  expect(preview_content).to receive(:preview_text).with(30)
@@ -341,21 +443,61 @@ module Alchemy
341
443
  end
342
444
 
343
445
  context "without any contents present" do
344
- before { allow(element).to receive(:contents).and_return([]) }
446
+ before do
447
+ allow(element).to receive(:contents).and_return([])
448
+ end
345
449
 
346
450
  it "should return nil" do
347
451
  expect(element.preview_text).to be_nil
348
452
  end
349
453
  end
454
+
455
+ context 'with nested elements' do
456
+ let(:element) do
457
+ build_stubbed(:alchemy_element, :with_nestable_elements)
458
+ end
459
+
460
+ let(:nested_element) do
461
+ build_stubbed(:alchemy_element, name: 'slide')
462
+ end
463
+
464
+ before do
465
+ allow(nested_element).to receive(:contents) { [content_2] }
466
+ allow(element).to receive(:nested_elements) { [nested_element] }
467
+ end
468
+
469
+ context 'when parent element has contents' do
470
+ before do
471
+ allow(element).to receive(:contents) { [content] }
472
+ end
473
+
474
+ it 'returns the preview text from the parent element' do
475
+ expect(content).to receive(:preview_text)
476
+ expect(element.preview_text)
477
+ end
478
+ end
479
+
480
+ context 'when parent element has no contents but nestable element has' do
481
+ before do
482
+ allow(element).to receive(:contents) { [] }
483
+ allow(nested_element).to receive(:contents) { [content_2] }
484
+ end
485
+
486
+ it 'returns the preview text from the first nested element' do
487
+ expect(content_2).to receive(:preview_text)
488
+ expect(element.preview_text)
489
+ end
490
+ end
491
+ end
350
492
  end
351
493
 
352
494
  context 'previous and next elements.' do
353
- let(:page) { FactoryGirl.create(:language_root_page) }
495
+ let(:page) { create(:alchemy_page, :language_root) }
354
496
 
355
497
  before(:each) do
356
- @element1 = FactoryGirl.create(:element, :page => page, :name => 'headline')
357
- @element2 = FactoryGirl.create(:element, :page => page)
358
- @element3 = FactoryGirl.create(:element, :page => page, :name => 'text')
498
+ @element1 = create(:alchemy_element, page: page, name: 'headline')
499
+ @element2 = create(:alchemy_element, page: page)
500
+ @element3 = create(:alchemy_element, page: page, name: 'text')
359
501
  end
360
502
 
361
503
  describe '#prev' do
@@ -384,7 +526,7 @@ module Alchemy
384
526
  end
385
527
 
386
528
  context 'retrieving contents, essences and ingredients' do
387
- let(:element) { FactoryGirl.create(:element, :name => 'news', :create_contents_after_create => true) }
529
+ let(:element) { create(:alchemy_element, name: 'news', create_contents_after_create: true) }
388
530
 
389
531
  it "should return an ingredient by name" do
390
532
  expect(element.ingredient('news_headline')).to eq(EssenceText.first.ingredient)
@@ -399,7 +541,7 @@ module Alchemy
399
541
  end
400
542
 
401
543
  context 'if no content is defined as rss title' do
402
- before { expect(element).to receive(:content_descriptions).and_return([]) }
544
+ before { expect(element).to receive(:content_definitions).and_return([]) }
403
545
 
404
546
  it "should return nil" do
405
547
  expect(element.content_for_rss_title).to be_nil
@@ -407,7 +549,7 @@ module Alchemy
407
549
  end
408
550
 
409
551
  context 'if no content is defined as rss description' do
410
- before { expect(element).to receive(:content_descriptions).and_return([]) }
552
+ before { expect(element).to receive(:content_definitions).and_return([]) }
411
553
 
412
554
  it "should return nil" do
413
555
  expect(element.content_for_rss_description).to be_nil
@@ -418,8 +560,8 @@ module Alchemy
418
560
  describe '#update_contents' do
419
561
  subject { element.update_contents(params) }
420
562
 
421
- let(:page) { build_stubbed(:page) }
422
- let(:element) { build_stubbed(:element, page: page) }
563
+ let(:page) { build_stubbed(:alchemy_page) }
564
+ let(:element) { build_stubbed(:alchemy_element, page: page) }
423
565
  let(:content1) { double(:content, id: 1) }
424
566
  let(:content2) { double(:content, id: 2) }
425
567
 
@@ -431,7 +573,7 @@ module Alchemy
431
573
  end
432
574
 
433
575
  context "with valid attributes hash" do
434
- let(:params) { {"#{content1.id}" => {body: 'Title'}} }
576
+ let(:params) { {content1.id.to_s => {body: 'Title'}} }
435
577
 
436
578
  context 'when certain content is not part of the attributes hash (cause it was not filled by the user)' do
437
579
  before do
@@ -469,9 +611,9 @@ module Alchemy
469
611
  end
470
612
 
471
613
  describe '.after_update' do
472
- let(:page) { create(:page) }
473
- let(:element) { create(:element, page: page) }
474
- let(:now) { Time.now }
614
+ let(:page) { create(:alchemy_page) }
615
+ let(:element) { create(:alchemy_element, page: page) }
616
+ let(:now) { Time.current }
475
617
 
476
618
  before do
477
619
  allow(Time).to receive(:now).and_return(now)
@@ -519,7 +661,7 @@ module Alchemy
519
661
  end
520
662
 
521
663
  describe '#taggable?' do
522
- let(:element) { FactoryGirl.build(:element) }
664
+ let(:element) { build(:alchemy_element) }
523
665
 
524
666
  context "definition has 'taggable' key with true value" do
525
667
  it "should return true" do
@@ -552,8 +694,8 @@ module Alchemy
552
694
  end
553
695
 
554
696
  describe '#trash!' do
555
- let(:element) { FactoryGirl.create(:element, page_id: 1, cell_id: 1) }
556
- let(:trashed_element) { element.trash! ; element }
697
+ let(:element) { create(:alchemy_element, page_id: 1, cell_id: 1) }
698
+ let(:trashed_element) { element.trash!; element }
557
699
  subject { trashed_element }
558
700
 
559
701
  it { is_expected.not_to be_public }
@@ -567,7 +709,7 @@ module Alchemy
567
709
  specify { expect { element.trash! }.to_not change(element, :cell_id) }
568
710
 
569
711
  context "with already one trashed element on the same page" do
570
- let(:element_2) { FactoryGirl.create(:element, page_id: 1) }
712
+ let(:element_2) { create(:alchemy_element, page_id: 1) }
571
713
 
572
714
  before do
573
715
  trashed_element
@@ -588,8 +730,8 @@ module Alchemy
588
730
  end
589
731
 
590
732
  describe '#cache_key' do
591
- let(:page) { stub_model(Page, published_at: Time.now - 1.week) }
592
- let(:element) { stub_model(Element, page: page, updated_at: Time.now) }
733
+ let(:page) { stub_model(Page, published_at: Time.current - 1.week) }
734
+ let(:element) { stub_model(Element, page: page, updated_at: Time.current) }
593
735
 
594
736
  subject { element.cache_key }
595
737
 
@@ -613,5 +755,108 @@ module Alchemy
613
755
  it_behaves_like "having a hint" do
614
756
  let(:subject) { Element.new }
615
757
  end
758
+
759
+ describe "#nestable_elements" do
760
+ let(:element) { Element.new }
761
+
762
+ subject { element.nestable_elements }
763
+
764
+ context 'with nestable_elements defined' do
765
+ before do
766
+ allow(element).to receive(:definition) do
767
+ {
768
+ 'nestable_elements' => %w(news article)
769
+ }
770
+ end
771
+ end
772
+
773
+ it 'returns an array containing all available nested element names' do
774
+ is_expected.to eq %w(news article)
775
+ end
776
+ end
777
+
778
+ context 'without nestable_elements defined' do
779
+ before do
780
+ allow(element).to receive(:definition) do
781
+ {}
782
+ end
783
+ end
784
+
785
+ it 'returns an empty array' do
786
+ is_expected.to eq []
787
+ end
788
+ end
789
+ end
790
+
791
+ describe "#nested_elements" do
792
+ subject { element.nested_elements }
793
+
794
+ context 'with nestable_elements defined' do
795
+ let(:element) { create(:alchemy_element, :with_nestable_elements) }
796
+
797
+ before do
798
+ element.nested_elements << create(:alchemy_element, name: 'slide')
799
+ end
800
+
801
+ it 'returns an AR scope containing nested elements' do
802
+ expect(subject.count).to eq(1)
803
+ end
804
+ end
805
+ end
806
+
807
+ describe '#richtext_contents_ids' do
808
+ subject { element.richtext_contents_ids }
809
+
810
+ let(:element) { create(:alchemy_element, :with_contents, name: 'text') }
811
+
812
+ it { is_expected.to eq(element.content_ids) }
813
+
814
+ context 'for element with nested elements' do
815
+ let!(:element) do
816
+ create(:alchemy_element, :with_contents, name: 'text')
817
+ end
818
+
819
+ let!(:nested_element_1) do
820
+ create(:alchemy_element, :with_contents, {
821
+ name: 'text',
822
+ parent_element: element,
823
+ folded: false
824
+ })
825
+ end
826
+
827
+ let!(:nested_element_2) do
828
+ create(:alchemy_element, :with_contents, {
829
+ name: 'text',
830
+ parent_element: nested_element_1,
831
+ folded: false
832
+ })
833
+ end
834
+
835
+ let!(:folded_nested_element_3) do
836
+ create(:alchemy_element, :with_contents, {
837
+ name: 'text',
838
+ parent_element: nested_element_1,
839
+ folded: true
840
+ })
841
+ end
842
+
843
+ it 'includes all richtext contents from all expanded descendent elements' do
844
+ is_expected.to eq(
845
+ element.content_ids +
846
+ nested_element_1.content_ids +
847
+ nested_element_2.content_ids
848
+ )
849
+ end
850
+ end
851
+ end
852
+
853
+ context 'with parent element' do
854
+ let!(:parent_element) { create(:alchemy_element, :with_nestable_elements) }
855
+ let!(:element) { create(:alchemy_element, name: 'slide', parent_element: parent_element) }
856
+
857
+ it "touches parent after update" do
858
+ expect { element.update!(public: false) }.to change(parent_element, :updated_at)
859
+ end
860
+ end
616
861
  end
617
862
  end