alchemy_cms 3.4.2 → 3.5.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (247) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +9 -3
  3. data/.teatro.yml +1 -0
  4. data/.travis.yml +14 -17
  5. data/CHANGELOG.md +44 -6
  6. data/Gemfile +7 -4
  7. data/README.md +60 -10
  8. data/Rakefile +1 -1
  9. data/alchemy_cms.gemspec +5 -8
  10. data/app/assets/javascripts/alchemy/admin.js +2 -0
  11. data/app/assets/javascripts/alchemy/alchemy.dialog.js.coffee +1 -0
  12. data/app/assets/javascripts/alchemy/alchemy.gui.js.coffee +1 -0
  13. data/app/assets/javascripts/alchemy/alchemy.hotkeys.js.coffee +1 -1
  14. data/app/assets/javascripts/alchemy/alchemy.initializer.js.coffee +9 -7
  15. data/app/assets/javascripts/alchemy/alchemy.link_dialog.js.coffee +1 -0
  16. data/app/assets/javascripts/alchemy/alchemy.preview_window.js.coffee +11 -7
  17. data/app/assets/javascripts/alchemy/alchemy.sitemap.js.coffee +1 -1
  18. data/app/assets/javascripts/alchemy/alchemy.tinymce.js.coffee +8 -3
  19. data/app/assets/javascripts/alchemy/alchemy.tooltips.coffee +10 -0
  20. data/app/assets/javascripts/alchemy/alchemy.uploader.js.coffee +104 -73
  21. data/app/assets/stylesheets/alchemy/_defaults.scss +1 -4
  22. data/app/assets/stylesheets/alchemy/_extends.scss +13 -35
  23. data/app/assets/stylesheets/alchemy/_mixins.scss +82 -18
  24. data/app/assets/stylesheets/alchemy/_variables.scss +21 -8
  25. data/app/assets/stylesheets/alchemy/admin.scss +4 -0
  26. data/app/assets/stylesheets/alchemy/archive.scss +8 -12
  27. data/app/assets/stylesheets/alchemy/attachments.scss +39 -0
  28. data/app/assets/stylesheets/alchemy/base.scss +26 -15
  29. data/app/assets/stylesheets/alchemy/buttons.scss +59 -31
  30. data/app/assets/stylesheets/alchemy/dashboard.scss +3 -3
  31. data/app/assets/stylesheets/alchemy/dialogs.scss +10 -8
  32. data/app/assets/stylesheets/alchemy/elements.scss +65 -41
  33. data/app/assets/stylesheets/alchemy/errors.scss +7 -0
  34. data/app/assets/stylesheets/alchemy/flash.scss +1 -1
  35. data/app/assets/stylesheets/alchemy/form_fields.scss +0 -37
  36. data/app/assets/stylesheets/alchemy/forms.scss +18 -27
  37. data/app/assets/stylesheets/alchemy/frame.scss +104 -204
  38. data/app/assets/stylesheets/alchemy/hints.scss +62 -0
  39. data/app/assets/stylesheets/alchemy/icon-font.scss +2 -1
  40. data/app/assets/stylesheets/alchemy/icons.scss +9 -4
  41. data/app/assets/stylesheets/alchemy/image_library.scss +6 -6
  42. data/app/assets/stylesheets/alchemy/jquery-ui.scss +6 -4
  43. data/app/assets/stylesheets/alchemy/lists.scss +0 -1
  44. data/app/assets/stylesheets/alchemy/menubar.scss +3 -4
  45. data/app/assets/stylesheets/alchemy/modules.scss +0 -6
  46. data/app/assets/stylesheets/alchemy/navigation.scss +242 -0
  47. data/app/assets/stylesheets/alchemy/pagination.scss +3 -3
  48. data/app/assets/stylesheets/alchemy/print.scss +1 -0
  49. data/app/assets/stylesheets/alchemy/resource_info.scss +45 -0
  50. data/app/assets/stylesheets/alchemy/search.scss +72 -1
  51. data/app/assets/stylesheets/alchemy/selects.scss +38 -44
  52. data/app/assets/stylesheets/alchemy/sitemap.scss +89 -79
  53. data/app/assets/stylesheets/alchemy/tables.scss +6 -10
  54. data/app/assets/stylesheets/alchemy/toolbar.scss +7 -36
  55. data/app/assets/stylesheets/alchemy/upload.scss +12 -3
  56. data/app/assets/stylesheets/tinymce/skins/alchemy/content.min.css.scss +6 -3
  57. data/app/assets/stylesheets/tinymce/skins/alchemy/fonts/tinymce-small.svg +58 -170
  58. data/app/assets/stylesheets/tinymce/skins/alchemy/fonts/tinymce-small.ttf +0 -0
  59. data/app/assets/stylesheets/tinymce/skins/alchemy/fonts/tinymce-small.woff +0 -0
  60. data/app/assets/stylesheets/tinymce/skins/alchemy/fonts/tinymce.svg +124 -148
  61. data/app/assets/stylesheets/tinymce/skins/alchemy/fonts/tinymce.ttf +0 -0
  62. data/app/assets/stylesheets/tinymce/skins/alchemy/fonts/tinymce.woff +0 -0
  63. data/app/assets/stylesheets/tinymce/skins/alchemy/skin.min.css.scss +426 -144
  64. data/app/controllers/alchemy/admin/attachments_controller.rb +24 -16
  65. data/app/controllers/alchemy/admin/clipboard_controller.rb +1 -1
  66. data/app/controllers/alchemy/admin/essence_files_controller.rb +1 -1
  67. data/app/controllers/alchemy/admin/essence_pictures_controller.rb +9 -8
  68. data/app/controllers/alchemy/admin/layoutpages_controller.rb +1 -0
  69. data/app/controllers/alchemy/admin/pages_controller.rb +2 -2
  70. data/app/controllers/alchemy/admin/resources_controller.rb +2 -2
  71. data/app/controllers/alchemy/admin/tags_controller.rb +1 -1
  72. data/app/controllers/alchemy/api/pages_controller.rb +16 -0
  73. data/app/controllers/alchemy/messages_controller.rb +1 -1
  74. data/app/controllers/concerns/alchemy/admin/uploader_responses.rb +2 -2
  75. data/app/helpers/alchemy/admin/attachments_helper.rb +11 -0
  76. data/app/helpers/alchemy/admin/base_helper.rb +37 -4
  77. data/app/helpers/alchemy/admin/contents_helper.rb +11 -4
  78. data/app/helpers/alchemy/admin/elements_helper.rb +0 -19
  79. data/app/helpers/alchemy/admin/essences_helper.rb +7 -30
  80. data/app/helpers/alchemy/admin/navigation_helper.rb +13 -51
  81. data/app/helpers/alchemy/admin/pages_helper.rb +21 -16
  82. data/app/helpers/alchemy/admin/pictures_helper.rb +9 -0
  83. data/app/helpers/alchemy/deprecated_pages_helper.rb +54 -0
  84. data/app/helpers/alchemy/essences_helper.rb +1 -1
  85. data/app/helpers/alchemy/pages_helper.rb +8 -109
  86. data/app/helpers/alchemy/url_helper.rb +8 -13
  87. data/app/models/alchemy/attachment.rb +7 -4
  88. data/app/models/alchemy/cell.rb +2 -2
  89. data/app/models/alchemy/content.rb +2 -2
  90. data/app/models/alchemy/content/factory.rb +12 -9
  91. data/app/models/alchemy/element.rb +6 -3
  92. data/app/models/alchemy/essence_file.rb +1 -1
  93. data/app/models/alchemy/essence_picture.rb +37 -47
  94. data/app/models/alchemy/essence_picture_view.rb +8 -1
  95. data/app/models/alchemy/folded_page.rb +3 -2
  96. data/app/models/alchemy/legacy_page_url.rb +3 -3
  97. data/app/models/alchemy/page.rb +50 -5
  98. data/app/models/alchemy/page/fixed_attributes.rb +63 -0
  99. data/app/models/alchemy/page/page_elements.rb +10 -7
  100. data/app/models/alchemy/page/page_natures.rb +19 -0
  101. data/app/models/alchemy/picture.rb +1 -0
  102. data/app/models/alchemy/picture/transformations.rb +1 -1
  103. data/app/models/alchemy/picture/url.rb +82 -0
  104. data/app/serializers/alchemy/page_tree_serializer.rb +29 -8
  105. data/app/views/alchemy/_edit_mode.html.erb +2 -0
  106. data/app/views/alchemy/_menubar.html.erb +1 -1
  107. data/app/views/alchemy/_preview_mode_code.html.erb +6 -0
  108. data/app/views/alchemy/admin/attachments/_archive_overlay.html.erb +1 -1
  109. data/app/views/alchemy/admin/attachments/_attachment.html.erb +25 -5
  110. data/app/views/alchemy/admin/attachments/_replace_button.html.erb +26 -0
  111. data/app/views/alchemy/admin/attachments/index.html.erb +1 -1
  112. data/app/views/alchemy/admin/attachments/show.html.erb +52 -0
  113. data/app/views/alchemy/admin/elements/_element_header.html.erb +6 -3
  114. data/app/views/alchemy/admin/elements/create.js.erb +0 -2
  115. data/app/views/alchemy/admin/elements/trash.js.erb +0 -1
  116. data/app/views/alchemy/admin/elements/update.js.erb +0 -2
  117. data/app/views/alchemy/admin/essence_pictures/crop.html.erb +1 -4
  118. data/app/views/alchemy/admin/essence_pictures/edit.html.erb +1 -1
  119. data/app/views/alchemy/admin/languages/index.html.erb +1 -0
  120. data/app/views/alchemy/admin/layoutpages/_layoutpage.html.erb +26 -27
  121. data/app/views/alchemy/admin/layoutpages/edit.html.erb +1 -1
  122. data/app/views/alchemy/admin/pages/_form.html.erb +13 -40
  123. data/app/views/alchemy/admin/pages/_locked_page.html.erb +1 -1
  124. data/app/views/alchemy/admin/pages/_page.html.erb +119 -61
  125. data/app/views/alchemy/admin/pages/_page_for_links.html.erb +4 -2
  126. data/app/views/alchemy/admin/pages/_page_infos.html.erb +12 -12
  127. data/app/views/alchemy/admin/pages/_page_status.html.erb +1 -1
  128. data/app/views/alchemy/admin/pages/_publication_fields.html.erb +35 -0
  129. data/app/views/alchemy/admin/pages/edit.html.erb +13 -2
  130. data/app/views/alchemy/admin/pages/index.html.erb +3 -8
  131. data/app/views/alchemy/admin/pages/info.html.erb +15 -2
  132. data/app/views/alchemy/admin/pages/sort.js.erb +1 -1
  133. data/app/views/alchemy/admin/pages/update.js.erb +1 -14
  134. data/app/views/alchemy/admin/partials/_main_navigation_entry.html.erb +12 -8
  135. data/app/views/alchemy/admin/partials/_remote_search_form.html.erb +4 -4
  136. data/app/views/alchemy/admin/partials/_search_form.html.erb +1 -1
  137. data/app/views/alchemy/admin/partials/_sub_navigation.html.erb +9 -6
  138. data/app/views/alchemy/admin/pictures/_filter_and_size_bar.html.erb +1 -1
  139. data/app/views/alchemy/admin/pictures/_picture.html.erb +1 -6
  140. data/app/views/alchemy/admin/pictures/_picture_to_assign.html.erb +1 -6
  141. data/app/views/alchemy/admin/pictures/index.html.erb +1 -1
  142. data/app/views/alchemy/admin/pictures/show.html.erb +1 -6
  143. data/app/views/alchemy/admin/uploader/_button.html.erb +4 -4
  144. data/app/views/alchemy/base/500.html.erb +15 -1
  145. data/app/views/alchemy/essences/_essence_boolean_editor.html.erb +13 -15
  146. data/app/views/alchemy/essences/_essence_boolean_view.html.erb +1 -3
  147. data/app/views/alchemy/essences/_essence_date_editor.html.erb +0 -2
  148. data/app/views/alchemy/essences/_essence_date_view.html.erb +0 -2
  149. data/app/views/alchemy/essences/_essence_file_editor.html.erb +2 -7
  150. data/app/views/alchemy/essences/_essence_file_view.html.erb +1 -3
  151. data/app/views/alchemy/essences/_essence_html_editor.html.erb +0 -2
  152. data/app/views/alchemy/essences/_essence_html_view.html.erb +1 -3
  153. data/app/views/alchemy/essences/_essence_link_editor.html.erb +0 -2
  154. data/app/views/alchemy/essences/_essence_link_view.html.erb +0 -2
  155. data/app/views/alchemy/essences/_essence_picture_editor.html.erb +47 -49
  156. data/app/views/alchemy/essences/_essence_picture_view.html.erb +1 -3
  157. data/app/views/alchemy/essences/_essence_richtext_editor.html.erb +0 -2
  158. data/app/views/alchemy/essences/_essence_richtext_view.html.erb +1 -3
  159. data/app/views/alchemy/essences/_essence_select_editor.html.erb +27 -29
  160. data/app/views/alchemy/essences/_essence_select_view.html.erb +1 -3
  161. data/app/views/alchemy/essences/_essence_text_editor.html.erb +17 -19
  162. data/app/views/alchemy/essences/_essence_text_view.html.erb +0 -2
  163. data/app/views/alchemy/pages/_meta_data.html.erb +9 -0
  164. data/app/views/layouts/alchemy/admin.html.erb +9 -11
  165. data/bin/alchemy +1 -2
  166. data/config/alchemy/config.yml +1 -1
  167. data/config/alchemy/modules.yml +0 -16
  168. data/config/initializers/dragonfly.rb +0 -18
  169. data/config/initializers/mini_profiler.rb +6 -0
  170. data/config/locales/alchemy.de.yml +9 -1
  171. data/config/locales/alchemy.en.yml +7 -1
  172. data/config/locales/alchemy.es.yml +6 -0
  173. data/config/locales/alchemy.fr.yml +2 -0
  174. data/config/locales/alchemy.it.yml +3 -1
  175. data/config/locales/alchemy.nl.yml +2 -0
  176. data/config/locales/alchemy.ru.yml +2 -0
  177. data/config/routes.rb +3 -8
  178. data/db/migrate/20160912223112_add_index_to_alchemy_pages_rgt.rb +9 -0
  179. data/db/migrate/20160927205604_add_foreign_key_indices_and_null_constraints.rb +20 -0
  180. data/db/migrate/20160928080104_add_foreign_keys.rb +27 -0
  181. data/lib/alchemy/admin/locale.rb +4 -3
  182. data/lib/alchemy/engine.rb +2 -4
  183. data/lib/alchemy/errors.rb +9 -2
  184. data/lib/alchemy/forms/builder.rb +8 -0
  185. data/lib/alchemy/modules.rb +20 -19
  186. data/lib/alchemy/permissions.rb +15 -4
  187. data/lib/alchemy/resources_helper.rb +4 -2
  188. data/lib/alchemy/sass_support.rb +9 -0
  189. data/lib/alchemy/seeder.rb +89 -1
  190. data/lib/alchemy/test_support/essence_shared_examples.rb +2 -0
  191. data/lib/alchemy/test_support/factories/attachment_factory.rb +1 -1
  192. data/lib/alchemy/test_support/factories/content_factory.rb +1 -0
  193. data/lib/alchemy/test_support/factories/element_factory.rb +1 -0
  194. data/lib/alchemy/test_support/factories/picture_factory.rb +1 -1
  195. data/lib/alchemy/test_support/fixtures/image.png +0 -0
  196. data/lib/alchemy/tinymce.rb +2 -6
  197. data/lib/alchemy/upgrader.rb +4 -55
  198. data/lib/alchemy/upgrader/tasks/install_dragonfly_config.rb +14 -0
  199. data/lib/alchemy/upgrader/three_point_five.rb +32 -0
  200. data/lib/alchemy/upgrader/three_point_four.rb +2 -8
  201. data/lib/alchemy/upgrader/three_point_one.rb +30 -30
  202. data/lib/alchemy/upgrader/three_point_three.rb +31 -31
  203. data/lib/alchemy/upgrader/three_point_two.rb +25 -25
  204. data/lib/alchemy/upgrader/three_point_zero.rb +59 -59
  205. data/lib/alchemy/version.rb +1 -1
  206. data/lib/rails/generators/alchemy/elements/templates/view.html.erb +1 -1
  207. data/lib/rails/generators/alchemy/elements/templates/view.html.haml +1 -1
  208. data/lib/rails/generators/alchemy/elements/templates/view.html.slim +1 -1
  209. data/lib/rails/generators/alchemy/essence/templates/editor.html.erb +1 -3
  210. data/lib/rails/generators/alchemy/install/files/_article_view.html.erb +1 -1
  211. data/lib/rails/generators/alchemy/install/files/application.html.erb +3 -4
  212. data/lib/rails/generators/alchemy/install/install_generator.rb +4 -0
  213. data/lib/rails/generators/alchemy/install/templates/dragonfly.rb.tt +35 -0
  214. data/lib/rails/generators/alchemy/module/module_generator.rb +1 -1
  215. data/lib/tasks/alchemy/db.rake +6 -0
  216. data/lib/tasks/alchemy/tidy.rake +85 -0
  217. data/lib/tasks/alchemy/upgrade.rake +165 -16
  218. data/vendor/assets/javascripts/clipboard.min.js +7 -0
  219. data/vendor/assets/javascripts/fileupload/jquery.fileupload-process.js +4 -4
  220. data/vendor/assets/javascripts/fileupload/jquery.fileupload-validate.js +2 -2
  221. data/vendor/assets/javascripts/fileupload/jquery.fileupload.js +29 -14
  222. data/vendor/assets/javascripts/fileupload/jquery.iframe-transport.js +2 -2
  223. data/vendor/assets/javascripts/tinymce/langs/es.js +2 -2
  224. data/vendor/assets/javascripts/tinymce/langs/fr.js +1 -1
  225. data/vendor/assets/javascripts/tinymce/langs/it.js +1 -1
  226. data/vendor/assets/javascripts/tinymce/langs/nl.js +3 -3
  227. data/vendor/assets/javascripts/tinymce/tinymce.min.js +15 -12
  228. metadata +44 -88
  229. data/app/assets/stylesheets/tinymce/skins/alchemy/fonts/readme.md +0 -1
  230. data/app/assets/stylesheets/tinymce/skins/alchemy/fonts/tinymce-small.eot +0 -0
  231. data/app/assets/stylesheets/tinymce/skins/alchemy/fonts/tinymce.eot +0 -0
  232. data/app/assets/stylesheets/tinymce/skins/alchemy/img/wline.gif +0 -0
  233. data/app/assets/stylesheets/tinymce/skins/alchemy/skin.ie7.min.css +0 -1
  234. data/app/controllers/alchemy/pictures_controller.rb +0 -97
  235. data/app/views/alchemy/admin/elements/_refresh_editor.js.erb +0 -8
  236. data/vendor/assets/javascripts/tinymce/plugins/anchor/plugin.min.js +0 -1
  237. data/vendor/assets/javascripts/tinymce/plugins/autoresize/plugin.min.js +0 -1
  238. data/vendor/assets/javascripts/tinymce/plugins/charmap/plugin.min.js +0 -1
  239. data/vendor/assets/javascripts/tinymce/plugins/code/plugin.min.js +0 -1
  240. data/vendor/assets/javascripts/tinymce/plugins/directionality/plugin.min.js +0 -1
  241. data/vendor/assets/javascripts/tinymce/plugins/fullscreen/plugin.min.js +0 -1
  242. data/vendor/assets/javascripts/tinymce/plugins/hr/plugin.min.js +0 -1
  243. data/vendor/assets/javascripts/tinymce/plugins/link/plugin.min.js +0 -1
  244. data/vendor/assets/javascripts/tinymce/plugins/paste/plugin.min.js +0 -1
  245. data/vendor/assets/javascripts/tinymce/plugins/tabfocus/plugin.min.js +0 -1
  246. data/vendor/assets/javascripts/tinymce/plugins/table/plugin.min.js +0 -1
  247. data/vendor/assets/javascripts/tinymce/themes/modern/theme.min.js +0 -1
@@ -33,25 +33,25 @@ module Alchemy
33
33
  end
34
34
 
35
35
  def create
36
- @attachment = Attachment.new(attachment_attributes)
37
- if @attachment.save
38
- render succesful_uploader_response(file: @attachment)
39
- else
40
- render failed_uploader_response(file: @attachment)
41
- end
36
+ @attachment = Attachment.create(attachment_attributes)
37
+ handle_uploader_response(status: :created)
42
38
  end
43
39
 
44
40
  def update
45
- @attachment.update_attributes(attachment_attributes)
46
- render_errors_or_redirect(
47
- @attachment,
48
- admin_attachments_path(
49
- per_page: params[:per_page],
50
- page: params[:page],
51
- q: params[:q]
52
- ),
53
- Alchemy.t("File successfully updated")
54
- )
41
+ @attachment.update(attachment_attributes)
42
+ if attachment_attributes['file'].present?
43
+ handle_uploader_response(status: :accepted)
44
+ else
45
+ render_errors_or_redirect(
46
+ @attachment,
47
+ admin_attachments_path(
48
+ per_page: params[:per_page],
49
+ page: params[:page],
50
+ q: params[:q]
51
+ ),
52
+ Alchemy.t("File successfully updated")
53
+ )
54
+ end
55
55
  end
56
56
 
57
57
  def destroy
@@ -75,6 +75,14 @@ module Alchemy
75
75
 
76
76
  private
77
77
 
78
+ def handle_uploader_response(status:)
79
+ if @attachment.valid?
80
+ render succesful_uploader_response(file: @attachment, status: status)
81
+ else
82
+ render failed_uploader_response(file: @attachment)
83
+ end
84
+ end
85
+
78
86
  def in_overlay?
79
87
  params[:content_id].present?
80
88
  end
@@ -2,7 +2,7 @@ module Alchemy
2
2
  module Admin
3
3
  class ClipboardController < Alchemy::Admin::BaseController
4
4
  authorize_resource class: :alchemy_admin_clipboard
5
- before_filter :set_clipboard
5
+ before_action :set_clipboard
6
6
 
7
7
  def index
8
8
  @clipboard_items = model_class.all_from_clipboard(@clipboard)
@@ -3,7 +3,7 @@ module Alchemy
3
3
  class EssenceFilesController < Alchemy::Admin::BaseController
4
4
  authorize_resource class: Alchemy::EssenceFile
5
5
 
6
- before_filter :load_essence_file, only: [:edit, :update]
6
+ before_action :load_essence_file, only: [:edit, :update]
7
7
 
8
8
  helper "Alchemy::Admin::Contents"
9
9
 
@@ -3,9 +3,9 @@ module Alchemy
3
3
  class EssencePicturesController < Alchemy::Admin::BaseController
4
4
  authorize_resource class: Alchemy::EssencePicture
5
5
 
6
- before_filter :load_essence_picture, only: [:edit, :crop, :update]
7
- before_filter :load_content, only: [:edit, :update, :assign]
8
- before_filter :load_options
6
+ before_action :load_essence_picture, only: [:edit, :crop, :update]
7
+ before_action :load_content, only: [:edit, :update, :assign]
8
+ before_action :load_options
9
9
 
10
10
  helper 'alchemy/admin/contents'
11
11
  helper 'alchemy/admin/essences'
@@ -74,14 +74,15 @@ module Alchemy
74
74
  @content = Content.find(params[:content_id])
75
75
  end
76
76
 
77
- # Gets the minimum size of the image to be rendered. the database render_size
78
- # has preference over the image_size parameter.
77
+ # Gets the minimum size of the image to be rendered.
78
+ #
79
+ # The +render_size+ attribute has preference over the +size+ parameter.
79
80
  #
80
81
  def sizes_from_essence_or_params
81
- if @essence_picture.render_size? && !@essence_picture.render_size.blank?
82
+ if @essence_picture.render_size?
82
83
  @essence_picture.sizes_from_string(@essence_picture.render_size)
83
- elsif @options[:image_size]
84
- @essence_picture.sizes_from_string(@options[:image_size])
84
+ elsif @options[:size]
85
+ @essence_picture.sizes_from_string(@options[:size])
85
86
  else
86
87
  { width: 0, height: 0 }
87
88
  end
@@ -2,6 +2,7 @@ module Alchemy
2
2
  module Admin
3
3
  class LayoutpagesController < Alchemy::Admin::BaseController
4
4
  authorize_resource class: :alchemy_admin_layoutpages
5
+ helper Alchemy::Admin::PagesHelper
5
6
 
6
7
  def index
7
8
  @layout_root = Page.find_or_create_layout_root_for(Language.current.id)
@@ -81,7 +81,7 @@ module Alchemy
81
81
  def edit
82
82
  # fetching page via before filter
83
83
  if page_is_locked?
84
- flash[:notice] = Alchemy.t('This page is locked', name: @page.locker_name)
84
+ flash[:warning] = Alchemy.t('This page is locked', name: @page.locker_name)
85
85
  redirect_to admin_pages_path
86
86
  elsif page_needs_lock?
87
87
  @page.lock_to!(current_alchemy_user)
@@ -348,7 +348,7 @@ module Alchemy
348
348
  end
349
349
 
350
350
  def redirect_path_after_create_page
351
- if @page.redirects_to_external?
351
+ if @page.redirects_to_external? || !@page.editable_by?(current_alchemy_user)
352
352
  admin_pages_path
353
353
  else
354
354
  params[:redirect_to] || edit_admin_page_path(@page)
@@ -10,10 +10,10 @@ module Alchemy
10
10
  helper Alchemy::ResourcesHelper, TagsHelper
11
11
  helper_method :resource_handler
12
12
 
13
- before_filter :load_resource,
13
+ before_action :load_resource,
14
14
  only: [:show, :edit, :update, :destroy]
15
15
 
16
- before_filter do
16
+ before_action do
17
17
  authorize!(action_name.to_sym, resource_instance_variable || resource_handler.model)
18
18
  end
19
19
 
@@ -1,7 +1,7 @@
1
1
  module Alchemy
2
2
  module Admin
3
3
  class TagsController < ResourcesController
4
- before_filter :load_tag, only: [:edit, :update, :destroy]
4
+ before_action :load_tag, only: [:edit, :update, :destroy]
5
5
 
6
6
  def index
7
7
  @query = ActsAsTaggableOn::Tag.ransack(params[:q])
@@ -12,6 +12,22 @@ module Alchemy
12
12
  respond_with @pages
13
13
  end
14
14
 
15
+ # Returns all pages as nested json object for tree views
16
+ #
17
+ # Pass a page_id param to only load tree for this page
18
+ #
19
+ # Pass elements=true param to include elements for pages
20
+ #
21
+ def nested
22
+ @page = Page.find_by(id: params[:page_id]) || Language.current_root_page
23
+
24
+ render json: PageTreeSerializer.new(@page,
25
+ ability: current_ability,
26
+ user: current_alchemy_user,
27
+ elements: params[:elements],
28
+ full: true)
29
+ end
30
+
15
31
  # Returns a json object for page
16
32
  #
17
33
  # You can either load the page via id or its urlname
@@ -42,7 +42,7 @@ module Alchemy
42
42
  # Please have a look at the +alchemy/config/config.yml+ file for further Message settings.
43
43
  #
44
44
  class MessagesController < Alchemy::BaseController
45
- before_filter :get_page, except: :create
45
+ before_action :get_page, except: :create
46
46
 
47
47
  helper 'alchemy/pages'
48
48
 
@@ -3,7 +3,7 @@ module Alchemy
3
3
  module UploaderResponses
4
4
  extend ActiveSupport::Concern
5
5
 
6
- def succesful_uploader_response(file:)
6
+ def succesful_uploader_response(file:, status: :created)
7
7
  message = Alchemy.t(:upload_success,
8
8
  scope: [:uploader, file.class.model_name.i18n_key],
9
9
  name: file.name
@@ -11,7 +11,7 @@ module Alchemy
11
11
 
12
12
  {
13
13
  json: uploader_response(file: file, message: message),
14
- status: :created
14
+ status: status
15
15
  }
16
16
  end
17
17
 
@@ -6,6 +6,17 @@ module Alchemy
6
6
  def mime_to_human(mime)
7
7
  Alchemy.t(mime, scope: 'mime_types', default: Alchemy.t(:document))
8
8
  end
9
+
10
+ def attachment_preview_size(attachment)
11
+ case attachment.icon_css_class
12
+ when 'image' then '600x475'
13
+ when 'audio' then '600x190'
14
+ when 'video' then '600x485'
15
+ when 'pdf' then '600x500'
16
+ else
17
+ '600x145'
18
+ end
19
+ end
9
20
  end
10
21
  end
11
22
  end
@@ -58,7 +58,7 @@ module Alchemy
58
58
 
59
59
  # Used for translations selector in Alchemy cockpit user settings.
60
60
  def translations_for_select
61
- Alchemy::I18n.available_locales.map do |locale|
61
+ Alchemy::I18n.available_locales.sort.map do |locale|
62
62
  [Alchemy.t(locale, scope: :translations), locale]
63
63
  end
64
64
  end
@@ -397,16 +397,24 @@ module Alchemy
397
397
  current_params.merge(p).delete_if { |_k, v| v.blank? }
398
398
  end
399
399
 
400
+ # Render a hint icon with tooltip for given object.
401
+ # The model class needs to include the hints module
400
402
  def render_hint_for(element)
401
403
  return unless element.has_hint?
402
- link_to '#', class: 'hint' do
403
- render_icon(:hint) + content_tag(:span, element.hint.html_safe, class: 'bubble')
404
+ content_tag :span, class: 'hint-with-icon' do
405
+ render_icon(:questionmark) +
406
+ content_tag(:span, element.hint.html_safe, class: 'hint-bubble')
404
407
  end
405
408
  end
406
409
 
407
410
  # Appends the current controller and action to body as css class.
408
411
  def alchemy_body_class
409
- "#{controller_name} #{action_name}"
412
+ [
413
+ controller_name,
414
+ action_name,
415
+ content_for(:main_menu_style),
416
+ content_for(:alchemy_body_class)
417
+ ].compact
410
418
  end
411
419
 
412
420
  # (internal) Returns options for the clipboard select tag
@@ -426,6 +434,31 @@ module Alchemy
426
434
  Alchemy::Config.get(:format_matchers)['link_url'] || /^(mailto:|\/|[a-z]+:\/\/)/
427
435
  end
428
436
 
437
+ # Renders a hint with tooltip
438
+ #
439
+ # == Example
440
+ #
441
+ # <%= hint_with_tooltip('Page layout is missing', class: 'warning icon') %>
442
+ #
443
+ # @param text [String] - The text displayed in the tooltip
444
+ # @param html_options [Hash] - Options passed to the wrapper `content_tag`
445
+ #
446
+ def hint_with_tooltip(text, html_options = {})
447
+ css_class = "#{html_options[:class]} with-hint"
448
+ content_tag :span, html_options.merge(class: css_class) do
449
+ content_tag(:span, text, class: 'hint-bubble')
450
+ end
451
+ end
452
+
453
+ # Renders a warning icon with a hint
454
+ # that explains the user that the page layout is missing
455
+ def page_layout_missing_warning
456
+ hint_with_tooltip(
457
+ Alchemy.t(:page_definition_missing),
458
+ class: 'inline warning icon'
459
+ )
460
+ end
461
+
429
462
  private
430
463
 
431
464
  def permission_from_options(options)
@@ -13,14 +13,21 @@ module Alchemy
13
13
  if content.blank?
14
14
  warning('Content is nil')
15
15
  return
16
- else
17
- content_name = content.name_for_label
18
16
  end
17
+
18
+ content_name = content.name_for_label
19
+
19
20
  if content.definition.blank?
20
21
  warning("Content #{content.name} is missing its definition")
21
- title = Alchemy.t(:content_definition_missing)
22
- content_name = %(<span class="warning icon" title="#{title}"></span>&nbsp;#{content_name}).html_safe
22
+
23
+ icon = hint_with_tooltip(
24
+ Alchemy.t(:content_definition_missing),
25
+ class: 'inline warning icon'
26
+ )
27
+
28
+ content_name = "#{icon} #{content_name}".html_safe
23
29
  end
30
+
24
31
  if content.has_validations?
25
32
  "#{content_name}<span class='validation_indicator'>*</span>".html_safe
26
33
  else
@@ -94,25 +94,6 @@ module Alchemy
94
94
  end
95
95
  end
96
96
 
97
- # This helper loads all elements from page that have EssenceSelects in them.
98
- #
99
- # It returns a javascript function that replaces all editor partials of this elements.
100
- #
101
- # We need this while updating, creating or trashing an element,
102
- # because another element on the same page could have a element selector in it.
103
- #
104
- # In cases like this one wants Ember.js databinding!
105
- #
106
- def update_essence_select_elements(page, element)
107
- elements = page.elements.not_trashed.joins(:contents)
108
- .where(["#{Content.table_name}.element_id != ?", element.id])
109
- .where(Content.table_name => {essence_type: "Alchemy::EssenceSelect"})
110
- return if elements.blank?
111
- elements.collect do |el|
112
- render 'alchemy/admin/elements/refresh_editor', element: el
113
- end.join.html_safe
114
- end
115
-
116
97
  # CSS classes for the element editor partial.
117
98
  def element_editor_classes(element, local_assigns)
118
99
  [
@@ -56,41 +56,18 @@ module Alchemy
56
56
  render 'alchemy/admin/contents/missing', {element: element, name: name, options: options}
57
57
  end
58
58
 
59
- def essence_picture_thumbnail(content, options)
60
- ingredient = content.ingredient
59
+ # Renders a thumbnail for given EssencePicture content with correct cropping and size
60
+ def essence_picture_thumbnail(content, options = {})
61
+ picture = content.ingredient
61
62
  essence = content.essence
62
- return if ingredient.blank?
63
63
 
64
- crop = !(essence.crop_size.blank? && essence.crop_from.blank?) ||
65
- (
66
- content.settings_value(:crop, options) == true ||
67
- content.settings_value(:crop, options) == "true"
68
- )
69
-
70
- size = if essence.render_size.blank?
71
- content.settings_value(:size, options)
72
- else
73
- essence.render_size
74
- end
75
-
76
- image_options = {
77
- size: essence.thumbnail_size(size, crop),
78
- crop_from: essence.crop_from.blank? ? nil : essence.crop_from,
79
- crop_size: essence.crop_size.blank? ? nil : essence.crop_size,
80
- crop: crop ? 'crop' : nil,
81
- upsample: content.settings_value(:upsample, options)
82
- }
64
+ return if picture.nil?
83
65
 
84
66
  image_tag(
85
- alchemy.thumbnail_path({
86
- id: ingredient.id,
87
- name: ingredient.urlname,
88
- sh: ingredient.security_token(image_options),
89
- format: ingredient.image_file_format
90
- }.merge(image_options)),
91
- alt: ingredient.name,
67
+ essence.thumbnail_url(options),
68
+ alt: picture.name,
92
69
  class: 'img_paddingtop',
93
- title: Alchemy.t(:image_name) + ": #{ingredient.name}"
70
+ title: Alchemy.t(:image_name) + ": #{picture.name}"
94
71
  )
95
72
  end
96
73
 
@@ -11,24 +11,11 @@ module Alchemy
11
11
  def alchemy_main_navigation_entry(alchemy_module)
12
12
  render(
13
13
  'alchemy/admin/partials/main_navigation_entry',
14
- alchemy_module: alchemy_module.stringify_keys,
15
- navigation: module_main_navigation(alchemy_module)
14
+ alchemy_module: alchemy_module,
15
+ navigation: alchemy_module['navigation']
16
16
  )
17
17
  end
18
18
 
19
- # Renders the subnavigation from current module
20
- #
21
- # We find the module from current controller and index action.
22
- #
23
- def admin_subnavigation
24
- if current_alchemy_module.present?
25
- render(
26
- 'alchemy/admin/partials/sub_navigation',
27
- entries: current_sub_navigation
28
- )
29
- end
30
- end
31
-
32
19
  # Used for checking the main navi permissions
33
20
  #
34
21
  # To let your module be navigatable by the user you have to provide an Ability for it.
@@ -46,7 +33,6 @@ module Alchemy
46
33
  # can :index, :my_admin_posts
47
34
  #
48
35
  def navigate_module(navigation)
49
- navigation.stringify_keys!
50
36
  [
51
37
  navigation['action'].to_sym,
52
38
  navigation['controller'].to_s.gsub(/\A\//, '').gsub(/\//, '_').to_sym
@@ -58,8 +44,9 @@ module Alchemy
58
44
  def main_navigation_css_classes(navigation)
59
45
  [
60
46
  'main_navi_entry',
61
- admin_mainnavi_active?(navigation) ? 'active' : nil
62
- ].compact.join(' ')
47
+ admin_mainnavi_active?(navigation) ? 'active' : nil,
48
+ navigation.key?('sub_navigation') ? 'has_sub_navigation' : nil
49
+ ].compact
63
50
  end
64
51
 
65
52
  # Returns true if given navi entry is in params controller and action
@@ -148,7 +135,7 @@ module Alchemy
148
135
  # A Alchemy module definition
149
136
  #
150
137
  def url_options_for_module(alchemy_module)
151
- url_options_for_navigation_entry(module_main_navigation(alchemy_module))
138
+ url_options_for_navigation_entry(alchemy_module['navigation'] || {})
152
139
  end
153
140
 
154
141
  # Returns a url options hash for given navigation entry.
@@ -157,7 +144,6 @@ module Alchemy
157
144
  # A Alchemy module navigation entry
158
145
  #
159
146
  def url_options_for_navigation_entry(entry)
160
- entry.stringify_keys!
161
147
  {
162
148
  controller: entry['controller'],
163
149
  action: entry['action'],
@@ -172,40 +158,15 @@ module Alchemy
172
158
  module_definition_for(controller: params[:controller], action: 'index')
173
159
  end
174
160
 
175
- # Returns the sub navigation for current Alchemy module.
176
- #
177
- def current_sub_navigation
178
- module_sub_navigation(module_main_navigation(current_alchemy_module))
179
- end
180
-
181
- # Returns navigation entries from given module.
182
- #
183
- def module_main_navigation(alchemy_module)
184
- alchemy_module.fetch('navigation', {}).stringify_keys
185
- end
186
-
187
- # Returns sub navigation entries from given module.
188
- #
189
- def module_sub_navigation(alchemy_module)
190
- alchemy_module.fetch('sub_navigation', []).map(&:stringify_keys)
191
- end
192
-
193
- # Returns nested navigation entries for given module.
194
- #
195
- def module_nested_navigation(alchemy_module)
196
- alchemy_module.fetch('nested', []).map(&:stringify_keys)
197
- end
198
-
199
161
  # Returns true if the current controller and action is in a modules navigation definition.
200
162
  #
201
- def admin_mainnavi_active?(main_navigation)
202
- main_navigation.stringify_keys!
163
+ def admin_mainnavi_active?(navigation)
203
164
  # Has the given navigation entry a active sub navigation?
204
- has_active_entry?(module_sub_navigation(main_navigation)) ||
165
+ has_active_entry?(navigation['sub_navigation'] || []) ||
205
166
  # Has the given navigation entry a active nested navigation?
206
- has_active_entry?(module_nested_navigation(main_navigation)) ||
167
+ has_active_entry?(navigation['nested'] || []) ||
207
168
  # Is the navigation entry active?
208
- entry_active?(main_navigation)
169
+ entry_active?(navigation || {})
209
170
  end
210
171
 
211
172
  # Returns true if the given entry's controller is current controller
@@ -219,7 +180,8 @@ module Alchemy
219
180
  # Also checks if given entry has a +nested_actions+ key, if so it checks if one of them is current controller's action
220
181
  #
221
182
  def is_entry_action_active?(entry)
222
- entry['action'] == params[:action] || entry['nested_actions'].to_a.include?(params[:action])
183
+ entry['action'] == params[:action] ||
184
+ entry.fetch('nested_actions', []).include?(params[:action])
223
185
  end
224
186
 
225
187
  # Returns true if an entry of given entries is active.
@@ -228,7 +190,7 @@ module Alchemy
228
190
  # Alchemy module navigation entries.
229
191
  #
230
192
  def has_active_entry?(entries)
231
- !entries.detect { |entry| entry_active?(entry) }.nil?
193
+ entries.any? { |entry| entry_active?(entry) }
232
194
  end
233
195
  end
234
196
  end