alchemy_cms 3.3.3 → 3.4.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 (133) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -1
  3. data/CHANGELOG.md +42 -4
  4. data/README.md +7 -3
  5. data/alchemy_cms.gemspec +1 -0
  6. data/app/assets/javascripts/alchemy/{alchemy.js → admin.js} +1 -2
  7. data/app/assets/javascripts/alchemy/alchemy.datepicker.js.coffee +28 -25
  8. data/app/assets/javascripts/alchemy/alchemy.dialog.js.coffee +1 -0
  9. data/app/assets/javascripts/alchemy/alchemy.i18n.js.coffee +7 -1
  10. data/app/assets/javascripts/alchemy/alchemy.link_dialog.js.coffee +1 -1
  11. data/app/assets/javascripts/alchemy/alchemy.sitemap.js.coffee +26 -0
  12. data/app/assets/javascripts/alchemy/alchemy.translations.js.coffee +56 -1
  13. data/app/assets/stylesheets/alchemy/_variables.scss +1 -0
  14. data/app/assets/stylesheets/alchemy/admin.scss +2 -1
  15. data/app/assets/stylesheets/alchemy/archive.scss +7 -0
  16. data/app/assets/stylesheets/alchemy/base.scss +0 -42
  17. data/app/assets/stylesheets/alchemy/buttons.scss +2 -1
  18. data/app/assets/stylesheets/alchemy/form_fields.scss +9 -0
  19. data/app/assets/stylesheets/alchemy/forms.scss +36 -10
  20. data/app/assets/stylesheets/alchemy/frame.scss +12 -1
  21. data/app/assets/stylesheets/alchemy/icons.scss +1 -1
  22. data/app/assets/stylesheets/alchemy/jquery-ui.scss +0 -260
  23. data/app/assets/stylesheets/alchemy/jquery.datetimepicker.scss +507 -0
  24. data/app/assets/stylesheets/alchemy/lists.scss +62 -0
  25. data/app/assets/stylesheets/alchemy/selects.scss +9 -2
  26. data/app/assets/stylesheets/alchemy/sitemap.scss +28 -51
  27. data/app/assets/stylesheets/alchemy/toolbar.scss +0 -2
  28. data/app/controllers/alchemy/admin/attachments_controller.rb +4 -6
  29. data/app/controllers/alchemy/admin/base_controller.rb +2 -2
  30. data/app/controllers/alchemy/admin/dashboard_controller.rb +2 -2
  31. data/app/controllers/alchemy/admin/languages_controller.rb +5 -0
  32. data/app/controllers/alchemy/admin/pages_controller.rb +14 -5
  33. data/app/controllers/alchemy/admin/resources_controller.rb +17 -1
  34. data/app/controllers/alchemy/base_controller.rb +1 -0
  35. data/app/controllers/alchemy/messages_controller.rb +1 -1
  36. data/app/controllers/alchemy/pages_controller.rb +16 -26
  37. data/app/controllers/alchemy/pictures_controller.rb +23 -10
  38. data/app/controllers/concerns/alchemy/page_redirects.rb +7 -7
  39. data/app/helpers/alchemy/admin/base_helper.rb +22 -19
  40. data/app/helpers/alchemy/admin/essences_helper.rb +26 -11
  41. data/app/helpers/alchemy/admin/pages_helper.rb +2 -1
  42. data/app/helpers/alchemy/essences_helper.rb +0 -35
  43. data/app/helpers/alchemy/url_helper.rb +1 -1
  44. data/app/mailers/alchemy/base_mailer.rb +18 -0
  45. data/app/mailers/alchemy/{messages.rb → messages_mailer.rb} +1 -1
  46. data/app/models/alchemy/attachment.rb +9 -0
  47. data/app/models/alchemy/cell.rb +1 -1
  48. data/app/models/alchemy/essence_picture.rb +4 -1
  49. data/app/models/alchemy/essence_picture_view.rb +68 -0
  50. data/app/models/alchemy/language.rb +8 -10
  51. data/app/models/alchemy/language/code.rb +4 -1
  52. data/app/models/alchemy/page.rb +69 -26
  53. data/app/models/alchemy/page/page_natures.rb +22 -0
  54. data/app/models/alchemy/page/page_scopes.rb +20 -6
  55. data/app/models/alchemy/picture.rb +37 -4
  56. data/app/models/alchemy/site.rb +8 -0
  57. data/app/serializers/alchemy/page_tree_serializer.rb +1 -1
  58. data/app/views/alchemy/admin/attachments/_archive_overlay.html.erb +9 -6
  59. data/app/views/alchemy/admin/attachments/_file_to_assign.html.erb +11 -9
  60. data/app/views/alchemy/admin/attachments/_filter_bar.html.erb +32 -0
  61. data/app/views/alchemy/admin/attachments/_overlay_file_list.html.erb +14 -2
  62. data/app/views/alchemy/admin/attachments/index.html.erb +10 -9
  63. data/app/views/alchemy/admin/dashboard/_locked_pages.html.erb +20 -9
  64. data/app/views/alchemy/admin/dashboard/_recent_pages.html.erb +11 -1
  65. data/app/views/alchemy/admin/languages/_form.html.erb +1 -0
  66. data/app/views/alchemy/admin/languages/index.html.erb +7 -8
  67. data/app/views/alchemy/admin/layoutpages/_layoutpage.html.erb +1 -1
  68. data/app/views/alchemy/admin/layoutpages/index.html.erb +2 -2
  69. data/app/views/alchemy/admin/pages/_current_page.html.erb +4 -0
  70. data/app/views/alchemy/admin/pages/_form.html.erb +16 -1
  71. data/app/views/alchemy/admin/pages/_locked_page.html.erb +2 -12
  72. data/app/views/alchemy/admin/pages/_page.html.erb +1 -1
  73. data/app/views/alchemy/admin/pages/_page_for_links.html.erb +2 -2
  74. data/app/views/alchemy/admin/pages/_page_status.html.erb +23 -11
  75. data/app/views/alchemy/admin/pages/edit.html.erb +2 -1
  76. data/app/views/alchemy/admin/pages/index.html.erb +2 -2
  77. data/app/views/alchemy/admin/partials/_language_tree_select.html.erb +3 -0
  78. data/app/views/alchemy/admin/partials/_site_select.html.erb +9 -0
  79. data/app/views/alchemy/admin/pictures/_picture.html.erb +6 -1
  80. data/app/views/alchemy/admin/pictures/_picture_to_assign.html.erb +2 -1
  81. data/app/views/alchemy/admin/pictures/show.html.erb +1 -1
  82. data/app/views/alchemy/admin/resources/_filter_bar.html.erb +31 -0
  83. data/app/views/alchemy/admin/resources/_form.html.erb +6 -0
  84. data/app/views/alchemy/admin/resources/_tag_list.html.erb +16 -0
  85. data/app/views/alchemy/admin/resources/index.html.erb +13 -1
  86. data/app/views/alchemy/essences/_essence_file_view.html.erb +2 -5
  87. data/app/views/alchemy/essences/_essence_picture_view.html.erb +5 -3
  88. data/app/views/alchemy/{messages → messages_mailer}/contact_form_mail.de.text.erb +0 -0
  89. data/app/views/alchemy/{messages → messages_mailer}/contact_form_mail.en.text.erb +0 -0
  90. data/app/views/alchemy/{messages → messages_mailer}/contact_form_mail.es.text.erb +0 -0
  91. data/app/views/alchemy/{messages → messages_mailer}/new.html.erb +0 -0
  92. data/app/views/layouts/alchemy/admin.html.erb +3 -8
  93. data/config/alchemy/config.yml +4 -3
  94. data/config/initializers/assets.rb +2 -2
  95. data/config/initializers/dragonfly.rb +3 -0
  96. data/config/initializers/mime_types.rb +1 -0
  97. data/config/locales/alchemy.de.yml +10 -2
  98. data/config/locales/alchemy.en.yml +6 -2
  99. data/config/locales/alchemy.es.yml +6 -3
  100. data/config/locales/alchemy.fr.yml +6 -2
  101. data/config/locales/alchemy.it.yml +937 -0
  102. data/config/locales/alchemy.nl.yml +6 -2
  103. data/config/locales/alchemy.ru.yml +3 -2
  104. data/config/locales/simple_form.it.yml +25 -0
  105. data/db/migrate/20160108174834_add_timebased_publishing_columns_to_pages.rb +32 -0
  106. data/db/migrate/20160422195310_add_image_file_format_to_alchemy_pictures.rb +21 -0
  107. data/db/migrate/20160617224938_change_alchemy_pages_locked_to_locked_at.rb +22 -0
  108. data/lib/alchemy/ability_helper.rb +23 -0
  109. data/lib/alchemy/configuration_methods.rb +2 -2
  110. data/lib/alchemy/controller_actions.rb +4 -33
  111. data/lib/alchemy/engine.rb +1 -0
  112. data/lib/alchemy/resource.rb +30 -13
  113. data/lib/alchemy/resources_helper.rb +17 -0
  114. data/lib/alchemy/test_support/factories/page_factory.rb +7 -2
  115. data/lib/alchemy/upgrader.rb +1 -0
  116. data/lib/alchemy/upgrader/tasks/install_asset_manifests.rb +15 -0
  117. data/lib/alchemy/upgrader/three_point_four.rb +16 -0
  118. data/lib/alchemy/version.rb +1 -1
  119. data/lib/rails/generators/alchemy/elements/elements_generator.rb +8 -7
  120. data/lib/rails/generators/alchemy/essence/essence_generator.rb +2 -6
  121. data/lib/rails/generators/alchemy/install/files/all.css +11 -0
  122. data/lib/rails/generators/alchemy/install/files/all.js +11 -0
  123. data/lib/rails/generators/alchemy/install/files/{alchemy.elements.css.scss → article.scss} +0 -0
  124. data/lib/rails/generators/alchemy/install/install_generator.rb +20 -19
  125. data/lib/rails/generators/alchemy/module/module_generator.rb +3 -5
  126. data/lib/rails/generators/alchemy/page_layouts/page_layouts_generator.rb +7 -6
  127. data/lib/rails/generators/alchemy/site_layouts/site_layouts_generator.rb +7 -6
  128. data/vendor/assets/javascripts/date-formatter.js +161 -0
  129. data/vendor/assets/javascripts/jquery_plugins/jquery.datetimepicker.full.min.js +2 -0
  130. data/vendor/assets/javascripts/tinymce/langs/it.js +219 -0
  131. metadata +48 -13
  132. data/app/assets/javascripts/alchemy/alchemy.custom.js +0 -1
  133. data/app/assets/stylesheets/alchemy/custom.scss +0 -1
@@ -68,7 +68,7 @@ module Alchemy
68
68
  @page = @element.page
69
69
  @root_page = @page.get_language_root
70
70
  if @message.valid?
71
- Messages.contact_form_mail(@message, mail_to, mail_from, subject).deliver
71
+ MessagesMailer.contact_form_mail(@message, mail_to, mail_from, subject).deliver
72
72
  redirect_to_success_page
73
73
  else
74
74
  render template: 'alchemy/pages/show'
@@ -26,6 +26,8 @@ module Alchemy
26
26
  if: :run_on_page_layout_callbacks?,
27
27
  only: [:index, :show]
28
28
 
29
+ before_action :set_expiration_headers, only: [:index, :show], if: -> { @page }
30
+
29
31
  rescue_from ActionController::UnknownFormat, with: :page_not_found!
30
32
 
31
33
  # == The index action gets invoked if one requests '/' or '/:locale'
@@ -35,7 +37,7 @@ module Alchemy
35
37
  # Loads the current language root page. The current language is either loaded via :locale
36
38
  # parameter or, if that's missing, the default language is used.
37
39
  #
38
- # If this page is not published then it loads the first published descendant it finds.
40
+ # If this page is not published then it redirects to the first published descendant it finds.
39
41
  #
40
42
  # If no public page can be found it renders a 404 error.
41
43
  #
@@ -45,8 +47,7 @@ module Alchemy
45
47
  raise "Remove deprecated `redirect_index` configuration!" if Alchemy.version == "4.0.0.rc1"
46
48
  redirect_permanently_to page_redirect_url
47
49
  else
48
- authorize! :index, @page
49
- render_page if render_fresh_page?
50
+ show
50
51
  end
51
52
  end
52
53
 
@@ -84,13 +85,13 @@ module Alchemy
84
85
  #
85
86
  # Loads the current public language root page.
86
87
  #
87
- # If the root page is not public it loads the first published child.
88
+ # If the root page is not public it redirects to the first published child.
88
89
  # This can be configured via +redirect_to_public_child+ [default: true]
89
90
  #
90
91
  # If no index page and no admin users are present we show the "Welcome to Alchemy" page.
91
92
  #
92
93
  def load_index_page
93
- @page ||= public_root_page || first_public_child
94
+ @page ||= Language.current_root_page
94
95
  render template: 'alchemy/welcome', layout: false if signup_required?
95
96
  end
96
97
 
@@ -110,26 +111,6 @@ module Alchemy
110
111
  )
111
112
  end
112
113
 
113
- # Returns the current language root page, if it's published.
114
- #
115
- # Otherwise it returns nil.
116
- #
117
- def public_root_page
118
- @root_page ||= Language.current_root_page
119
- @root_page if @root_page && @root_page.public?
120
- end
121
-
122
- # Returns the first public child of the current language root page.
123
- #
124
- # If +redirect_to_public_child+ is configured to +false+ it returns +nil+.
125
- #
126
- def first_public_child
127
- if Alchemy::Config.get(:redirect_to_public_child)
128
- return unless @root_page
129
- @root_page.descendants.published.first
130
- end
131
- end
132
-
133
114
  # Redirects to given url with 301 status
134
115
  def redirect_permanently_to(url)
135
116
  redirect_to url, status: :moved_permanently
@@ -170,6 +151,14 @@ module Alchemy
170
151
  end
171
152
  end
172
153
 
154
+ def set_expiration_headers
155
+ if @page.cache_page?
156
+ expires_in @page.expiration_time, public: !@page.restricted
157
+ else
158
+ expires_now
159
+ end
160
+ end
161
+
173
162
  def set_root_page
174
163
  @root_page ||= Language.current_root_page
175
164
  end
@@ -200,7 +189,8 @@ module Alchemy
200
189
  def render_fresh_page?
201
190
  !@page.cache_page? || stale?(etag: page_etag,
202
191
  last_modified: @page.published_at,
203
- public: !@page.restricted)
192
+ public: !@page.restricted,
193
+ template: 'pages/show')
204
194
  end
205
195
 
206
196
  def page_not_found!
@@ -1,6 +1,6 @@
1
1
  module Alchemy
2
2
  class PicturesController < Alchemy::BaseController
3
- ALLOWED_IMAGE_TYPES = %w(png jpeg gif)
3
+ ALLOWED_IMAGE_TYPES = %w(png jpeg gif svg)
4
4
 
5
5
  caches_page :show, :thumbnail, :zoom
6
6
 
@@ -25,7 +25,7 @@ module Alchemy
25
25
  @size = params[:size]
26
26
  end
27
27
 
28
- respond_to { |format| send_image(processed_image, format) }
28
+ respond_to { |format| send_image(processed_image, format, flatten: true) }
29
29
  end
30
30
 
31
31
  def zoom
@@ -45,20 +45,29 @@ module Alchemy
45
45
  false
46
46
  end
47
47
 
48
- def send_image(image, format)
48
+ def send_image(image, format, opts = {})
49
49
  request.session_options[:skip] = true
50
50
  ALLOWED_IMAGE_TYPES.each do |type|
51
+ # Flatten animated gifs, only if converting to a different format.
52
+ # Can be overwritten via +options[:flatten]+.
53
+ options = {
54
+ flatten: type != "gif" && image.ext == 'gif'
55
+ }.merge(opts)
56
+
51
57
  format.send(type) do
52
- options = []
58
+ encoding_options = []
53
59
  if type == 'jpeg'
54
60
  quality = params[:quality] || Config.get(:output_image_jpg_quality)
55
- options << "-quality #{quality}"
61
+ encoding_options << "-quality #{quality}"
62
+ end
63
+ if options[:flatten]
64
+ encoding_options << "-flatten"
56
65
  end
57
- # Flatten animated gifs, only if converting to a different format.
58
- if type != "gif" && image.ext == 'gif'
59
- options << "-flatten"
66
+ if @picture.has_convertible_format?
67
+ render text: image.encode(type, encoding_options.join(' ')).data
68
+ else
69
+ render text: image.data
60
70
  end
61
- render text: image.encode(type, options.join(' ')).data
62
71
  end
63
72
  end
64
73
  end
@@ -70,7 +79,7 @@ module Alchemy
70
79
  if @image.nil?
71
80
  raise MissingImageFileError, "Missing image file for #{@picture.inspect}"
72
81
  end
73
- if @size.present?
82
+ if resizable?
74
83
  if params[:crop_size].present? && params[:crop_from].present? || params[:crop].present?
75
84
  @picture.crop(@size, params[:crop_from], params[:crop_size], @upsample)
76
85
  else
@@ -80,5 +89,9 @@ module Alchemy
80
89
  @image
81
90
  end
82
91
  end
92
+
93
+ def resizable?
94
+ @size.present? && @picture.has_convertible_format?
95
+ end
83
96
  end
84
97
  end
@@ -36,10 +36,14 @@ module Alchemy
36
36
  end
37
37
 
38
38
  def public_child_redirect_url
39
- return unless redirect_to_public_child?
39
+ return if @page.public?
40
40
 
41
- @page = @page.self_and_descendants.published.not_restricted.first
42
- @page ? page_redirect_url : page_not_found!
41
+ if configuration(:redirect_to_public_child)
42
+ @page = @page.descendants.published.not_restricted.first
43
+ @page ? page_redirect_url : page_not_found!
44
+ else
45
+ page_not_found!
46
+ end
43
47
  end
44
48
 
45
49
  def controller_and_action_url
@@ -65,9 +69,5 @@ module Alchemy
65
69
  def locale_prefix_missing?
66
70
  multi_language? && params[:locale].blank? && !default_locale?
67
71
  end
68
-
69
- def redirect_to_public_child?
70
- configuration(:redirect_to_public_child) && !@page.public?
71
- end
72
72
  end
73
73
  end
@@ -332,38 +332,41 @@ module Alchemy
332
332
 
333
333
  # Renders a textfield ready to display a datepicker
334
334
  #
335
- # Uses a HTML5 <tt><input type="date"></tt> field.
335
+ # Uses a HTML5 +<input type="date">+ field.
336
+ # A Javascript observer converts this into a fancy Datepicker.
337
+ # If you pass +'datetime'+ as +:type+ the datepicker will also have a Time select.
336
338
  #
337
- # === Example
339
+ # The date value gets localized via +I18n.l+. The format on Time and Date is +datepicker+
340
+ # or +datetimepicker+, if you pass another +type+.
341
+ #
342
+ # === Date Example
338
343
  #
339
344
  # <%= alchemy_datepicker(@person, :birthday) %>
340
345
  #
346
+ # === Datetime Example
347
+ #
348
+ # <%= alchemy_datepicker(@page, :public_on, type: 'datetime') %>
349
+ #
341
350
  # @param [ActiveModel::Base] object
342
351
  # An instance of a model
343
352
  # @param [String or Symbol] method
344
353
  # The attribute method to be called for the date value
345
354
  #
346
- # @option html_options [String] :type ('date')
355
+ # @option html_options [String] :type (date)
347
356
  # The type of text field
348
- # @option html_options [String] :class ('thin_border date')
357
+ # @option html_options [String] :class (type)
349
358
  # CSS classes of the input field
350
- # @option html_options [String] :value (object.send(method.to_sym).nil? ? nil : l(object.send(method.to_sym), :format => :datepicker))
351
- # The value the input displays
359
+ # @option html_options [String] :value (value of method on object)
360
+ # The value the input displays. If you pass a String its parsed with +Time.parse+
352
361
  #
353
362
  def alchemy_datepicker(object, method, html_options = {})
354
- value = nil
355
- if object.send(method.to_sym).present?
356
- value = l(object.send(method.to_sym), format: :datepicker)
357
- elsif html_options[:value].present?
358
- date = html_options.delete(:value)
359
- date = Time.parse(date) if date.is_a?(String)
360
- value = l(date, format: :datepicker)
361
- end
362
- text_field object.class.name.underscore.to_sym, method.to_sym, html_options.merge({
363
- type: 'date',
364
- class: 'date',
365
- value: value
366
- })
363
+ type = html_options.delete(:type) || 'date'
364
+ date = html_options.delete(:value) || object.send(method.to_sym).presence
365
+ date = Time.zone.parse(date) if date.is_a?(String)
366
+ value = date ? l(date, format: "#{type}picker".to_sym) : nil
367
+
368
+ text_field object.class.name.demodulize.underscore.to_sym,
369
+ method.to_sym, {type: type, class: type, value: value}.merge(html_options)
367
370
  end
368
371
 
369
372
  # Merges the params-hash with the given hash
@@ -57,25 +57,40 @@ module Alchemy
57
57
  end
58
58
 
59
59
  def essence_picture_thumbnail(content, options)
60
- return if content.ingredient.blank?
61
- crop = !(content.essence.crop_size.blank? && content.essence.crop_from.blank?) ||
62
- (content.settings_value(:crop, options) == true || content.settings_value(:crop, options) == "true")
60
+ ingredient = content.ingredient
61
+ essence = content.essence
62
+ return if ingredient.blank?
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
+
63
76
  image_options = {
64
- size: content.essence.thumbnail_size(content.essence.render_size.blank? ? content.settings_value(:size, options) : content.essence.render_size, crop),
65
- crop_from: content.essence.crop_from.blank? ? nil : content.essence.crop_from,
66
- crop_size: content.essence.crop_size.blank? ? nil : content.essence.crop_size,
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,
67
80
  crop: crop ? 'crop' : nil,
68
81
  upsample: content.settings_value(:upsample, options)
69
82
  }
83
+
70
84
  image_tag(
71
85
  alchemy.thumbnail_path({
72
- id: content.ingredient.id,
73
- name: content.ingredient.urlname,
74
- sh: content.ingredient.security_token(image_options)
86
+ id: ingredient.id,
87
+ name: ingredient.urlname,
88
+ sh: ingredient.security_token(image_options),
89
+ format: ingredient.image_file_format
75
90
  }.merge(image_options)),
76
- alt: content.ingredient.name,
91
+ alt: ingredient.name,
77
92
  class: 'img_paddingtop',
78
- title: Alchemy.t(:image_name) + ": #{content.ingredient.name}"
93
+ title: Alchemy.t(:image_name) + ": #{ingredient.name}"
79
94
  )
80
95
  end
81
96
 
@@ -22,7 +22,8 @@ module Alchemy
22
22
  def combined_page_status(page)
23
23
  page.status.map do |state, _value|
24
24
  next if state == :locked
25
- val = content_tag(:span, '', class: page.send(state) ? "page_status #{state}" : "page_status not_#{state}")
25
+ css_class = page.send("#{state}?") ? "page_status #{state}" : "page_status not_#{state}"
26
+ val = content_tag(:span, '', class: css_class)
26
27
  val + page.status_title(state)
27
28
  end.delete_if(&:blank?).join("<br>").html_safe
28
29
  end
@@ -86,40 +86,5 @@ module Alchemy
86
86
  def render_essence_view(content, options = {}, html_options = {})
87
87
  render_essence(content, :view, {for_view: options}, html_options)
88
88
  end
89
-
90
- # Renders a essence picture
91
- #
92
- def render_essence_picture_view(content, options, html_options)
93
- options = {
94
- show_caption: true,
95
- disable_link: false
96
- }.update(content.settings).update(options)
97
- return if content.ingredient.blank?
98
- if content.essence.caption.present? && options[:show_caption]
99
- caption = content_tag(:figcaption, content.essence.caption, id: "#{dom_id(content.ingredient)}_caption", class: "image_caption")
100
- end
101
- img_tag = image_tag(
102
- content.essence.picture_url(options), {
103
- alt: (content.essence.alt_tag.blank? ? nil : content.essence.alt_tag),
104
- title: (content.essence.title.blank? ? nil : content.essence.title),
105
- class: (caption || content.essence.css_class.blank? ? nil : content.essence.css_class)
106
- }.merge(caption ? {} : html_options)
107
- )
108
- output = caption ? img_tag + caption : img_tag
109
- if content.essence.link.present? && !options[:disable_link]
110
- output = link_to(url_for(content.essence.link), {
111
- title: content.essence.link_title.blank? ? nil : content.essence.link_title,
112
- target: (content.essence.link_target == "blank" ? "_blank" : nil),
113
- 'data-link-target' => content.essence.link_target.blank? ? nil : content.essence.link_target
114
- }) do
115
- output
116
- end
117
- end
118
- if caption
119
- content_tag(:figure, output, {class: content.essence.css_class.blank? ? nil : content.essence.css_class}.merge(html_options))
120
- else
121
- output
122
- end
123
- end
124
89
  end
125
90
  end
@@ -43,7 +43,7 @@ module Alchemy
43
43
  url_params = {
44
44
  id: picture.id,
45
45
  name: picture.urlname,
46
- format: configuration(:image_output_format),
46
+ format: picture.default_render_format,
47
47
  sh: picture.security_token(optional_params)
48
48
  }
49
49
  url_params.update(optional_params.update(crop: optional_params[:crop] ? 'crop' : nil))
@@ -0,0 +1,18 @@
1
+ module Alchemy
2
+ begin
3
+ base_class = Object.const_get('::ApplicationMailer')
4
+ rescue NameError
5
+ base_class = ActionMailer::Base
6
+ end
7
+
8
+ # The +BaseMailer+ is the class all Alchemy mailers inherit from.
9
+ #
10
+ # Itself inherits from +ApplicationMailer+ when it is defined, or
11
+ # as a fallback from +ActionMailer::Base+.
12
+ #
13
+ # +ApplicationMailer+ is the Rails standard for registering helpers and
14
+ # setting the default layout. It is only generated though, when you
15
+ # +rails generate+ a mailer.
16
+ #
17
+ class BaseMailer < base_class; end
18
+ end
@@ -1,5 +1,5 @@
1
1
  module Alchemy
2
- class Messages < ActionMailer::Base
2
+ class MessagesMailer < BaseMailer
3
3
  def contact_form_mail(message, mail_to, mail_from, subject)
4
4
  @message = message
5
5
  mail(
@@ -39,6 +39,13 @@ module Alchemy
39
39
  def allowed_filetypes
40
40
  Config.get(:uploader).fetch('allowed_filetypes', {}).fetch('alchemy/attachments', [])
41
41
  end
42
+
43
+ def file_types_for_select
44
+ file_types = Alchemy::Attachment.pluck(:file_mime_type).uniq.map do |type|
45
+ [Alchemy.t(type, scope: 'mime_types'), type]
46
+ end
47
+ file_types.sort_by(&:first)
48
+ end
42
49
  end
43
50
 
44
51
  validates_presence_of :file
@@ -56,6 +63,8 @@ module Alchemy
56
63
 
57
64
  after_update :touch_contents
58
65
 
66
+ scope :with_file_type, ->(file_type) { where(file_mime_type: file_type) }
67
+
59
68
  # Instance methods
60
69
 
61
70
  def to_jq_upload
@@ -28,7 +28,7 @@ module Alchemy
28
28
  belongs_to :page
29
29
  validates_uniqueness_of :name, scope: 'page_id'
30
30
  validates_format_of :name, with: /\A[a-z0-9_-]+\z/
31
- has_many :elements, -> { where(parent_element_id: nil).order(:position) }, dependent: :destroy
31
+ has_many :elements, -> { order(:position) }, dependent: :destroy
32
32
 
33
33
  class << self
34
34
  def definitions
@@ -126,11 +126,13 @@ module Alchemy
126
126
  #
127
127
  def picture_params(options = {})
128
128
  return {} if picture.nil?
129
+
129
130
  params = {
130
131
  id: picture.id,
131
132
  name: picture.urlname,
132
- format: Config.get(:image_output_format)
133
+ format: picture.default_render_format
133
134
  }.merge(options)
135
+
134
136
  if options[:crop] && crop_from.present? && crop_size.present?
135
137
  params = {
136
138
  crop: true,
@@ -138,6 +140,7 @@ module Alchemy
138
140
  crop_size: crop_size
139
141
  }.merge(params)
140
142
  end
143
+
141
144
  params = clean_picture_params(params)
142
145
  params.merge(sh: picture.security_token(params))
143
146
  end