alchemy_cms 7.2.6 → 7.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (184) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +97 -9
  3. data/Gemfile +4 -3
  4. data/Rakefile +1 -0
  5. data/alchemy_cms.gemspec +7 -7
  6. data/app/assets/builds/alchemy/admin/print.css +1 -0
  7. data/app/assets/builds/alchemy/admin/print.css.map +1 -0
  8. data/app/assets/builds/alchemy/admin.css +1 -0
  9. data/app/assets/builds/alchemy/admin.css.map +1 -0
  10. data/app/assets/builds/alchemy/welcome.css +1 -0
  11. data/app/assets/builds/alchemy/welcome.css.map +1 -0
  12. data/app/assets/builds/tinymce/skins/content/alchemy/content.css +1 -0
  13. data/app/assets/builds/tinymce/skins/content/alchemy/content.css.map +1 -0
  14. data/app/assets/builds/tinymce/skins/content/alchemy/content.min.css +1 -0
  15. data/app/assets/builds/tinymce/skins/content/alchemy/content.min.css.map +1 -0
  16. data/app/assets/builds/tinymce/skins/ui/alchemy/skin.css +1 -0
  17. data/app/assets/builds/tinymce/skins/ui/alchemy/skin.css.map +1 -0
  18. data/app/assets/builds/tinymce/skins/ui/alchemy/skin.min.css +1 -0
  19. data/app/assets/builds/tinymce/skins/ui/alchemy/skin.min.css.map +1 -0
  20. data/app/assets/config/alchemy_manifest.js +1 -5
  21. data/app/assets/javascripts/alchemy/alchemy.dialog.js.coffee +4 -0
  22. data/app/assets/stylesheets/alchemy/{_custom-properties.scss → _custom-properties.css} +28 -25
  23. data/app/assets/stylesheets/alchemy/_deprecated_variables.scss +41 -0
  24. data/app/assets/stylesheets/alchemy/_deprecation.scss +17 -0
  25. data/app/assets/stylesheets/alchemy/_extends.scss +1 -1
  26. data/app/assets/stylesheets/alchemy/_mixins.scss +20 -23
  27. data/app/assets/stylesheets/alchemy/_variables.scss +98 -94
  28. data/app/assets/stylesheets/alchemy/{archive.scss → admin/archive.scss} +23 -23
  29. data/app/assets/stylesheets/alchemy/{attachment-select.scss → admin/attachment-select.scss} +2 -2
  30. data/app/assets/stylesheets/alchemy/{attachments.scss → admin/attachments.scss} +4 -4
  31. data/app/assets/stylesheets/alchemy/{base.scss → admin/base.scss} +9 -9
  32. data/app/assets/stylesheets/alchemy/{buttons.scss → admin/buttons.scss} +3 -3
  33. data/app/assets/stylesheets/alchemy/{clipboard.scss → admin/clipboard.scss} +9 -6
  34. data/app/assets/stylesheets/alchemy/{dashboard.scss → admin/dashboard.scss} +8 -8
  35. data/app/assets/stylesheets/alchemy/{dialogs.scss → admin/dialogs.scss} +20 -20
  36. data/app/assets/stylesheets/alchemy/{elements.scss → admin/elements.scss} +128 -88
  37. data/app/assets/stylesheets/alchemy/{errors.scss → admin/errors.scss} +22 -6
  38. data/app/assets/stylesheets/alchemy/{flash.scss → admin/flash.scss} +3 -3
  39. data/app/assets/stylesheets/alchemy/{flatpickr.scss → admin/flatpickr.scss} +55 -35
  40. data/app/assets/stylesheets/alchemy/{form_fields.scss → admin/form_fields.scss} +8 -6
  41. data/app/assets/stylesheets/alchemy/{forms.scss → admin/forms.scss} +20 -16
  42. data/app/assets/stylesheets/alchemy/{frame.scss → admin/frame.scss} +9 -9
  43. data/app/assets/stylesheets/alchemy/{image_library.scss → admin/image_library.scss} +34 -33
  44. data/app/assets/stylesheets/alchemy/admin/labels.scss +3 -0
  45. data/app/assets/stylesheets/alchemy/{list_filter.scss → admin/list_filter.scss} +4 -4
  46. data/app/assets/stylesheets/alchemy/{lists.scss → admin/lists.scss} +9 -7
  47. data/app/assets/stylesheets/alchemy/{navigation.scss → admin/navigation.scss} +17 -17
  48. data/app/assets/stylesheets/alchemy/{node-select.scss → admin/node-select.scss} +5 -5
  49. data/app/assets/stylesheets/alchemy/{nodes.scss → admin/nodes.scss} +11 -11
  50. data/app/assets/stylesheets/alchemy/{notices.scss → admin/notices.scss} +11 -7
  51. data/app/assets/stylesheets/alchemy/{page-select.scss → admin/page-select.scss} +10 -10
  52. data/app/assets/stylesheets/alchemy/{pagination.scss → admin/pagination.scss} +10 -10
  53. data/app/assets/stylesheets/alchemy/{print.scss → admin/print.scss} +2 -6
  54. data/app/assets/stylesheets/alchemy/{resource_info.scss → admin/resource_info.scss} +6 -7
  55. data/app/assets/stylesheets/alchemy/{search.scss → admin/search.scss} +6 -6
  56. data/app/assets/stylesheets/alchemy/{selects.scss → admin/selects.scss} +46 -39
  57. data/app/assets/stylesheets/alchemy/{shoelace.scss → admin/shoelace.scss} +10 -10
  58. data/app/assets/stylesheets/alchemy/{sitemap.scss → admin/sitemap.scss} +18 -19
  59. data/app/assets/stylesheets/alchemy/{tables.scss → admin/tables.scss} +26 -22
  60. data/app/assets/stylesheets/alchemy/admin/tags.scss +158 -0
  61. data/app/assets/stylesheets/alchemy/{toolbar.scss → admin/toolbar.scss} +10 -10
  62. data/app/assets/stylesheets/alchemy/{typography.scss → admin/typography.scss} +3 -3
  63. data/app/assets/stylesheets/alchemy/{upload.scss → admin/upload.scss} +1 -1
  64. data/app/assets/stylesheets/alchemy/admin.scss +40 -45
  65. data/app/assets/stylesheets/alchemy/welcome.scss +57 -0
  66. data/app/assets/stylesheets/tinymce/skins/content/alchemy/{content.min.scss → content.scss} +5 -4
  67. data/app/assets/stylesheets/tinymce/skins/ui/alchemy/{skin.min.scss → skin.scss} +40 -40
  68. data/app/components/alchemy/admin/resource/action.rb +46 -0
  69. data/app/components/alchemy/admin/resource/cell.rb +34 -0
  70. data/app/components/alchemy/admin/resource/header.rb +46 -0
  71. data/app/components/alchemy/admin/resource/table.rb +153 -0
  72. data/app/components/alchemy/ingredients/datetime_view.rb +2 -2
  73. data/app/controllers/alchemy/admin/base_controller.rb +2 -1
  74. data/app/controllers/alchemy/admin/elements_controller.rb +7 -3
  75. data/app/controllers/alchemy/admin/legacy_page_urls_controller.rb +1 -1
  76. data/app/controllers/alchemy/admin/pages_controller.rb +1 -1
  77. data/app/controllers/alchemy/admin/pictures_controller.rb +2 -2
  78. data/app/controllers/alchemy/admin/resources_controller.rb +1 -1
  79. data/app/controllers/alchemy/base_controller.rb +2 -0
  80. data/app/controllers/concerns/alchemy/admin/uploader_responses.rb +2 -11
  81. data/app/decorators/alchemy/ingredient_editor.rb +17 -0
  82. data/app/helpers/alchemy/admin/pages_helper.rb +6 -10
  83. data/app/helpers/alchemy/base_helper.rb +2 -2
  84. data/app/helpers/alchemy/elements_block_helper.rb +13 -1
  85. data/app/helpers/alchemy/pages_helper.rb +2 -2
  86. data/app/javascript/alchemy_admin/components/element_editor.js +23 -31
  87. data/app/javascript/alchemy_admin/components/preview_window.js +2 -3
  88. data/app/javascript/alchemy_admin/picture_selector.js +38 -10
  89. data/app/models/alchemy/attachment.rb +0 -8
  90. data/app/models/alchemy/element/dom_id.rb +1 -0
  91. data/app/models/alchemy/element/element_ingredients.rb +0 -73
  92. data/app/models/alchemy/element/presenters.rb +4 -1
  93. data/app/models/alchemy/element.rb +6 -0
  94. data/app/models/alchemy/elements_repository.rb +2 -2
  95. data/app/models/alchemy/ingredient_validator.rb +10 -0
  96. data/app/models/alchemy/page/page_scopes.rb +1 -1
  97. data/app/models/alchemy/page.rb +3 -3
  98. data/app/models/alchemy/picture.rb +0 -10
  99. data/app/views/alchemy/admin/attachments/_files_list.html.erb +74 -16
  100. data/app/views/alchemy/admin/clipboard/index.html.erb +38 -33
  101. data/app/views/alchemy/admin/dashboard/_dashboard.html.erb +3 -0
  102. data/app/views/alchemy/admin/dashboard/_left_column.html.erb +4 -0
  103. data/app/views/alchemy/admin/dashboard/_right_column.html.erb +9 -0
  104. data/app/views/alchemy/admin/dashboard/_top.html.erb +12 -0
  105. data/app/views/alchemy/admin/dashboard/index.html.erb +1 -25
  106. data/app/views/alchemy/admin/elements/_element.html.erb +1 -2
  107. data/app/views/alchemy/admin/elements/_form.html.erb +1 -1
  108. data/app/views/alchemy/admin/ingredients/_picture_fields.html.erb +10 -3
  109. data/app/views/alchemy/admin/ingredients/update.turbo_stream.erb +7 -0
  110. data/app/views/alchemy/admin/languages/_table.html.erb +16 -42
  111. data/app/views/alchemy/admin/nodes/_form.html.erb +1 -1
  112. data/app/views/alchemy/admin/pages/_table.html.erb +92 -27
  113. data/app/views/alchemy/admin/pages/edit.html.erb +6 -8
  114. data/app/views/alchemy/admin/pages/index.html.erb +0 -4
  115. data/app/views/alchemy/admin/pictures/_form.html.erb +14 -12
  116. data/app/views/alchemy/admin/pictures/index.html.erb +1 -11
  117. data/app/views/alchemy/admin/pictures/update.turbo_stream.erb +6 -0
  118. data/app/views/alchemy/admin/resources/_resource_table.html.erb +3 -0
  119. data/app/views/alchemy/admin/resources/_table.html.erb +2 -0
  120. data/app/views/alchemy/admin/resources/index.html.erb +1 -1
  121. data/app/views/alchemy/admin/sites/index.html.erb +1 -1
  122. data/app/views/alchemy/admin/styleguide/index.html.erb +0 -4
  123. data/app/views/alchemy/admin/tags/index.html.erb +15 -14
  124. data/app/views/alchemy/base/403.html.erb +6 -0
  125. data/app/views/alchemy/base/500.html.erb +14 -12
  126. data/app/views/alchemy/ingredients/_datetime_editor.html.erb +13 -11
  127. data/app/views/alchemy/ingredients/_headline_editor.html.erb +29 -22
  128. data/app/views/alchemy/ingredients/_link_editor.html.erb +17 -11
  129. data/app/views/alchemy/ingredients/_page_editor.html.erb +1 -0
  130. data/app/views/alchemy/ingredients/_picture_editor.html.erb +3 -4
  131. data/app/views/alchemy/ingredients/_richtext_editor.html.erb +5 -1
  132. data/app/views/alchemy/ingredients/_select_editor.html.erb +2 -1
  133. data/app/views/alchemy/ingredients/_text_editor.html.erb +20 -14
  134. data/app/views/alchemy/ingredients/shared/_picture_css_class.html.erb +6 -0
  135. data/app/views/layouts/alchemy/admin.html.erb +4 -2
  136. data/bin/setup +2 -0
  137. data/bin/start +1 -1
  138. data/bun.lockb +0 -0
  139. data/config/alchemy/config.yml +9 -0
  140. data/config/locales/alchemy.en.yml +8 -29
  141. data/config/routes.rb +22 -22
  142. data/lib/alchemy/config.rb +3 -3
  143. data/lib/alchemy/install/tasks.rb +5 -2
  144. data/lib/alchemy/resources_helper.rb +3 -1
  145. data/lib/alchemy/test_support/capybara_helpers.rb +8 -5
  146. data/lib/alchemy/test_support/shared_uploader_examples.rb +0 -1
  147. data/lib/alchemy/upgrader/seven_point_three.rb +52 -0
  148. data/lib/alchemy/version.rb +1 -1
  149. data/lib/alchemy_cms.rb +1 -1
  150. data/lib/generators/alchemy/install/files/article.css +25 -0
  151. data/lib/generators/alchemy/install/files/custom.css +4 -0
  152. data/lib/generators/alchemy/install/install_generator.rb +6 -6
  153. data/lib/tasks/alchemy/upgrade.rake +29 -1
  154. data/vendor/assets/stylesheets/alchemy_admin/select2.css +1 -0
  155. data/vendor/assets/stylesheets/jquery.Jcrop.min.css +2 -0
  156. data/vendor/javascript/shoelace.min.js +62 -63
  157. data/vendor/javascript/tinymce.min.js +1 -1
  158. metadata +132 -105
  159. data/app/assets/images/alchemy/lupe.cur +0 -0
  160. data/app/assets/stylesheets/alchemy/labels.scss +0 -3
  161. data/app/assets/stylesheets/alchemy/tags.scss +0 -155
  162. data/app/assets/stylesheets/alchemy/welcome.sass +0 -49
  163. data/app/views/alchemy/admin/attachments/_attachment.html.erb +0 -81
  164. data/app/views/alchemy/admin/languages/_language.html.erb +0 -50
  165. data/app/views/alchemy/admin/pages/_table_row.html.erb +0 -111
  166. data/app/views/alchemy/admin/pages/list/_table.html.erb +0 -31
  167. data/app/views/alchemy/admin/pictures/update.js.erb +0 -6
  168. data/app/views/alchemy/admin/tags/_tag.html.erb +0 -32
  169. data/app/views/alchemy/base/update.js.erb +0 -5
  170. data/lib/generators/alchemy/install/files/all.css +0 -11
  171. data/lib/generators/alchemy/install/files/article.scss +0 -30
  172. data/package.json +0 -52
  173. data/vendor/assets/stylesheets/alchemy_admin/select2.scss +0 -741
  174. data/vendor/assets/stylesheets/jquery.Jcrop.min.scss +0 -2
  175. /data/app/assets/stylesheets/alchemy/{fonts.scss → _fonts.scss} +0 -0
  176. /data/app/assets/stylesheets/alchemy/{hints.scss → admin/hints.scss} +0 -0
  177. /data/app/assets/stylesheets/alchemy/{icons.scss → admin/icons.scss} +0 -0
  178. /data/app/assets/stylesheets/alchemy/{images.scss → admin/images.scss} +0 -0
  179. /data/app/assets/stylesheets/alchemy/{preview_window.scss → admin/preview_window.scss} +0 -0
  180. /data/app/assets/stylesheets/alchemy/{spinner.scss → admin/spinner.scss} +0 -0
  181. /data/app/views/alchemy/admin/dashboard/{_locked_pages.html.erb → widgets/_locked_pages.html.erb} +0 -0
  182. /data/app/views/alchemy/admin/dashboard/{_recent_pages.html.erb → widgets/_recent_pages.html.erb} +0 -0
  183. /data/app/views/alchemy/admin/dashboard/{_sites.html.erb → widgets/_sites.html.erb} +0 -0
  184. /data/app/views/alchemy/admin/dashboard/{_users.html.erb → widgets/_users.html.erb} +0 -0
@@ -95,79 +95,6 @@ module Alchemy
95
95
  value_for(role).present?
96
96
  end
97
97
 
98
- # Ingredient validation error messages
99
- #
100
- # == Error messages are translated via I18n
101
- #
102
- # Inside your translation file add translations like:
103
- #
104
- # alchemy:
105
- # ingredient_validations:
106
- # name_of_the_element:
107
- # role_of_the_ingredient:
108
- # validation_error_type: Error Message
109
- #
110
- # NOTE: +validation_error_type+ has to be one of:
111
- #
112
- # * blank
113
- # * taken
114
- # * invalid
115
- #
116
- # === Example:
117
- #
118
- # de:
119
- # alchemy:
120
- # ingredient_validations:
121
- # contactform:
122
- # email:
123
- # invalid: 'Die Email hat nicht das richtige Format'
124
- #
125
- #
126
- # == Error message translation fallbacks
127
- #
128
- # In order to not translate every single ingredient for every element
129
- # you can provide default error messages per ingredient role:
130
- #
131
- # === Example
132
- #
133
- # en:
134
- # alchemy:
135
- # ingredient_validations:
136
- # fields:
137
- # email:
138
- # invalid: E-Mail has wrong format
139
- # blank: E-Mail can't be blank
140
- #
141
- # And even further you can provide general field agnostic error messages:
142
- #
143
- # === Example
144
- #
145
- # en:
146
- # alchemy:
147
- # ingredient_validations:
148
- # errors:
149
- # invalid: %{field} has wrong format
150
- # blank: %{field} can't be blank
151
- #
152
- def ingredient_error_messages
153
- messages = []
154
- ingredients_with_errors.map { |i| [i.role, i.errors.details] }.each do |role, error_details|
155
- error_details[:value].each do |error_detail|
156
- error = error_detail[:error]
157
- messages << Alchemy.t(
158
- "#{name}.#{role}.#{error}",
159
- scope: "ingredient_validations",
160
- default: [
161
- :"fields.#{role}.#{error}",
162
- :"errors.#{error}"
163
- ],
164
- field: Alchemy::Ingredient.translated_label_for(role, name)
165
- )
166
- end
167
- end
168
- messages
169
- end
170
-
171
98
  private
172
99
 
173
100
  # Builds ingredients for this element as described in the +elements.yml+
@@ -79,8 +79,11 @@ module Alchemy
79
79
  end
80
80
 
81
81
  # Returns a dom id used for elements html id tag.
82
- #
82
+ # @deprecated
83
83
  def dom_id
84
+ if caller.none? { |l| l =~ Regexp.new("alchemy/elements_block_helper.rb:117:in `element_view_for'") }
85
+ Alchemy::Deprecation.warn("dom_id is deprecated and will be removed from Alchemy 8.0. Please pass an id to the element_view_for helper instead.")
86
+ end
84
87
  self.class.dom_id_class.new(self).call
85
88
  end
86
89
 
@@ -136,15 +136,21 @@ module Alchemy
136
136
 
137
137
  # The class responsible for the +dom_id+ of elements.
138
138
  # Defaults to +Alchemy::Element::DomId+.
139
+ # @deprecated
139
140
  def dom_id_class
141
+ if caller.none? { |l| l =~ Regexp.new("alchemy/element/presenters.rb:87:in `dom_id'") }
142
+ Alchemy::Deprecation.warn("dom_id_class is deprecated and will be removed from Alchemy 8.0. Please pass an id to the element_view_for helper instead.")
143
+ end
140
144
  @_dom_id_class || DomId
141
145
  end
142
146
 
143
147
  # Register a custom +DomId+ class responsible for the +dom_id+ of elements.
144
148
  # Defaults to +Alchemy::Element::DomId+.
149
+ # @deprecated
145
150
  def dom_id_class=(klass)
146
151
  @_dom_id_class = klass
147
152
  end
153
+ deprecate :dom_id_class=, deprecator: Alchemy::Deprecation
148
154
 
149
155
  # This methods does a copy of source and all its ingredients.
150
156
  #
@@ -115,8 +115,8 @@ module Alchemy
115
115
  self.class.new(select { |e| e.parent_element_id == parent.id })
116
116
  end
117
117
 
118
- def each(&blk)
119
- elements.each(&blk)
118
+ def each(&)
119
+ elements.each(&)
120
120
  end
121
121
 
122
122
  private
@@ -86,6 +86,16 @@ module Alchemy
86
86
  end
87
87
  end
88
88
 
89
+ def validate_length(opts = {})
90
+ value_length = ingredient.value.to_s.length
91
+ if value_length < opts[:minimum]
92
+ ingredient.errors.add(:value, :too_short, count: opts[:minimum])
93
+ end
94
+ if value_length > opts[:maximum]
95
+ ingredient.errors.add(:value, :too_long, count: opts[:maximum])
96
+ end
97
+ end
98
+
89
99
  def duplicates
90
100
  ingredient.class
91
101
  .joins(:element).merge(Alchemy::Element.published)
@@ -124,7 +124,7 @@ module Alchemy
124
124
  end
125
125
 
126
126
  def ransackable_scopes(_auth_object)
127
- [:published, :from_current_site, :searchables, :layoutpages]
127
+ [:published, :contentpages, :from_current_site, :searchables, :layoutpages]
128
128
  end
129
129
  end
130
130
  end
@@ -491,7 +491,7 @@ module Alchemy
491
491
  # does not respond to +#name+ it returns +'unknown'+
492
492
  #
493
493
  def creator_name
494
- creator.try(:name) || Alchemy.t("unknown")
494
+ creator.try(:alchemy_display_name) || Alchemy.t("unknown")
495
495
  end
496
496
 
497
497
  # Returns the name of the last updater of this page.
@@ -500,7 +500,7 @@ module Alchemy
500
500
  # does not respond to +#name+ it returns +'unknown'+
501
501
  #
502
502
  def updater_name
503
- updater.try(:name) || Alchemy.t("unknown")
503
+ updater.try(:alchemy_display_name) || Alchemy.t("unknown")
504
504
  end
505
505
 
506
506
  # Returns the name of the user currently editing this page.
@@ -509,7 +509,7 @@ module Alchemy
509
509
  # does not respond to +#name+ it returns +'unknown'+
510
510
  #
511
511
  def locker_name
512
- locker.try(:name) || Alchemy.t("unknown")
512
+ locker.try(:alchemy_display_name) || Alchemy.t("unknown")
513
513
  end
514
514
 
515
515
  # Key hint translations by page layout, rather than the default name.
@@ -224,16 +224,6 @@ module Alchemy
224
224
  save!
225
225
  end
226
226
 
227
- # Returns a Hash suitable for jquery fileupload json.
228
- #
229
- def to_jq_upload
230
- {
231
- name: image_file_name,
232
- size: image_file_size,
233
- error: errors[:image_file].join
234
- }
235
- end
236
-
237
227
  # Returns the picture description for a given language.
238
228
  def description_for(language)
239
229
  descriptions.find_by(language: language)&.text
@@ -7,22 +7,80 @@
7
7
  <% end %>
8
8
  <% end %>
9
9
  <% else %>
10
- <table id="all_files" class="list">
11
- <thead>
12
- <tr>
13
- <th class="icon"></th>
14
- <th class="name"><%= sort_link(@query, :name) %></th>
15
- <th class="file_name"><%= sort_link(@query, :file_name) %></th>
16
- <th class="file_type"><%= Alchemy::Attachment.human_attribute_name('file_mime_type') %></th>
17
- <th class="file_size"><%= sort_link(@query, :file_size) %></th>
18
- <th class="date"><%= sort_link(@query, :created_at, default_order: 'desc') %></th>
19
- <th class="tools"></th>
20
- </tr>
21
- </thead>
22
- <tbody>
23
- <%= render partial: 'alchemy/admin/attachments/attachment', collection: @attachments %>
24
- </tbody>
25
- </table>
10
+ <%= render Alchemy::Admin::Resource::Table.new(@attachments, query: @query) do |table| %>
11
+ <% table.icon_column { |attachment| attachment.icon_css_class } %>
12
+ <% table.column :name, sortable: true do |attachment| %>
13
+ <% if can?(:show, attachment) %>
14
+ <%= link_to_dialog(
15
+ attachment.name,
16
+ alchemy.admin_attachment_path(attachment),
17
+ {
18
+ title: attachment.name,
19
+ size: attachment_preview_size(attachment)
20
+ },
21
+ {
22
+ title: Alchemy.t('Attachment Preview')
23
+ }
24
+ ) %>
25
+ <% else %>
26
+ <%= attachment.name %>
27
+ <% end %>
28
+ <% end %>
29
+ <% table.column :file_name, sortable: true %>
30
+ <% table.column :file_mime_type do |attachment| %>
31
+ <%= mime_to_human(attachment.file_mime_type) %>
32
+ <% end %>
33
+ <% table.column :file_size, sortable: true do |attachment| %>
34
+ <%= number_to_human_size(attachment.file_size) %>
35
+ <% end %>
36
+ <% table.column :created_at, sortable: true %>
37
+
38
+ <% table.with_action(:show, Alchemy.t('Attachment Preview')) do |attachment| %>
39
+ <%= link_to_dialog(
40
+ render_icon(:information),
41
+ alchemy.admin_attachment_path(attachment),
42
+ {
43
+ title: attachment.name,
44
+ size: attachment_preview_size(attachment)
45
+ },
46
+ class: "icon_button"
47
+ ) %>
48
+ <% end %>
49
+ <% table.with_action(:download) do |attachment| %>
50
+ <sl-tooltip content="<%= Alchemy.t("download_file", filename: attachment.file_name) %>">
51
+ <%= link_to render_icon(:download),
52
+ alchemy.download_admin_attachment_path(attachment),
53
+ target: "_blank",
54
+ class: "icon_button" %>
55
+ </sl-tooltip>
56
+ <% end %>
57
+ <% table.with_action(:edit, Alchemy.t(:replace_file)) do |attachment| %>
58
+ <%= render 'alchemy/admin/attachments/replace_button',
59
+ redirect_url: alchemy.admin_attachments_path,
60
+ object: attachment,
61
+ file_attribute: 'file' %>
62
+ <% end %>
63
+ <% table.with_action(:destroy, Alchemy.t(:delete_file)) do |attachment| %>
64
+ <%= link_to_confirm_dialog render_icon(:minus),
65
+ Alchemy.t(:confirm_to_delete_file),
66
+ alchemy.admin_attachment_path(
67
+ id: attachment,
68
+ q: search_filter_params[:q],
69
+ page: params[:page],
70
+ per_page: params[:per_page]
71
+ ),
72
+ class: "icon_button" %>
73
+ <% end %>
74
+ <% table.with_action(:edit, Alchemy.t(:rename_file)) do |attachment| %>
75
+ <%= link_to_dialog render_icon(:edit),
76
+ alchemy.edit_admin_attachment_path(attachment, q: search_filter_params[:q], page: params[:page]),
77
+ {
78
+ title: Alchemy.t(:rename_file),
79
+ size: '500x250'
80
+ },
81
+ class: "icon_button" %>
82
+ <% end %>
83
+ <% end %>
26
84
 
27
85
  <%= paginate @attachments, theme: 'alchemy' %>
28
86
  <% end %>
@@ -1,34 +1,39 @@
1
- <%- if @clipboard_items.blank? -%>
2
- <%= render_message do %>
3
- <%= Alchemy.t('No items in your clipboard') %>
4
- <% end %>
5
- <%- else -%>
6
- <div id="clipboard_items">
7
- <ul>
8
- <%- @clipboard_items.each do |item| -%>
9
- <% item_class = item.class.name.demodulize.underscore.pluralize %>
10
- <li id="clipboard_item_<%= item.id -%>" class="<%= item_class -%>">
11
- <% if item_class == 'pages' %>
12
- <%= render_icon(:file) %>
13
- <%= truncate(item.name, length: 50) %>
14
- <% else %>
15
- <%= render_icon(:draggable, style: false) %>
16
- <%= truncate(item.display_name_with_preview_text(50), length: 50) %>
1
+ <% if @clipboard_items.blank? %>
2
+ <%= render_message do %>
3
+ <%= Alchemy.t('No items in your clipboard') %>
4
+ <% end %>
5
+ <% else %>
6
+ <%= render_message do %>
7
+ <%= Alchemy.t('Add items from clipboard via "Add Element" button') %>
8
+ <% end %>
9
+
10
+ <div id="clipboard_items">
11
+ <ul>
12
+ <% @clipboard_items.each do |item| %>
13
+ <% item_class = item.class.name.demodulize.underscore.pluralize %>
14
+ <li id="clipboard_item_<%= item.id %>" class="<%= item_class %>">
15
+ <% if item_class == 'pages' %>
16
+ <%= render_icon(:file) %>
17
+ <%= truncate(item.name, length: 50) %>
18
+ <% else %>
19
+ <%= render_icon(:draggable, style: false) %>
20
+ <%= truncate(item.display_name_with_preview_text(50), length: 50) %>
21
+ <% end %>
22
+ <sl-tooltip content="<%= Alchemy.t('Remove item from clipboard') %>">
23
+ <%= link_to render_icon(:close, size: '1x'),
24
+ alchemy.remove_admin_clipboard_path(remarkable_type: item_class, remarkable_id: item.id),
25
+ remote: true, method: 'delete',
26
+ class: "icon_button small"
27
+ %>
28
+ </sl-tooltip>
29
+ </li>
17
30
  <% end %>
18
- <span class="float_right">
19
- <%= link_to render_icon(:close, size: '1x'),
20
- alchemy.remove_admin_clipboard_path(remarkable_type: item_class, remarkable_id: item.id),
21
- remote: true, method: 'delete',
22
- title: Alchemy.t('Remove item from clipboard') %>
23
- </span>
24
- </li>
25
- <%- end -%>
26
- </ul>
27
- <p>
28
- <%= link_to_confirm_dialog Alchemy.t('clear clipboard'),
29
- Alchemy.t('Do you really want to clear the clipboard?'),
30
- alchemy.clear_admin_clipboard_path(remarkable_type: params[:remarkable_type]),
31
- class: 'button' %>
32
- </p>
33
- </div>
34
- <%- end -%>
31
+ </ul>
32
+ <p>
33
+ <%= link_to_confirm_dialog Alchemy.t('clear clipboard'),
34
+ Alchemy.t('Do you really want to clear the clipboard?'),
35
+ alchemy.clear_admin_clipboard_path(remarkable_type: params[:remarkable_type]),
36
+ class: 'button' %>
37
+ </p>
38
+ </div>
39
+ <% end %>
@@ -0,0 +1,3 @@
1
+ <%= render "top" %>
2
+ <%= render "left_column" %>
3
+ <%= render "right_column" %>
@@ -0,0 +1,4 @@
1
+ <div class="column left">
2
+ <%= render 'alchemy/admin/dashboard/widgets/locked_pages' %>
3
+ <%= render 'alchemy/admin/dashboard/widgets/recent_pages' %>
4
+ </div>
@@ -0,0 +1,9 @@
1
+ <div class="column right">
2
+ <% if @online_users.try(:any?) %>
3
+ <%= render 'alchemy/admin/dashboard/widgets/users' %>
4
+ <% end %>
5
+
6
+ <% if multi_site? %>
7
+ <%= render 'alchemy/admin/dashboard/widgets/sites' %>
8
+ <% end %>
9
+ </div>
@@ -0,0 +1,12 @@
1
+ <h1>
2
+ <% if @first_time -%>
3
+ <%= Alchemy.t(:welcome_note, name: current_alchemy_user.try(:name)) %>
4
+ <% else -%>
5
+ <%= Alchemy.t(:welcome_back_note, name: current_alchemy_user.try(:name)) %>
6
+ <% end -%>
7
+ </h1>
8
+ <% if @last_sign_at %>
9
+ <p>
10
+ <small><%= Alchemy.t('Your last login was on', time: l(@last_sign_at, format: :'alchemy.default')) %></small>
11
+ </p>
12
+ <% end %>
@@ -16,29 +16,5 @@
16
16
  <% end %>
17
17
 
18
18
  <div id="dashboard">
19
- <h1>
20
- <% if @first_time -%>
21
- <%= Alchemy.t(:welcome_note, name: current_alchemy_user.try(:name)) %>
22
- <% else -%>
23
- <%= Alchemy.t(:welcome_back_note, name: current_alchemy_user.try(:name)) %>
24
- <% end -%>
25
- </h1>
26
- <% if @last_sign_at %>
27
- <p>
28
- <small><%= Alchemy.t('Your last login was on', time: l(@last_sign_at, format: :'alchemy.default')) %></small>
29
- </p>
30
- <% end %>
31
- <div class="column left">
32
- <%= render 'locked_pages' %>
33
- <%= render 'recent_pages' %>
34
- </div>
35
- <div class="column right">
36
- <% if @online_users.try(:any?) %>
37
- <%= render 'users' %>
38
- <% end %>
39
-
40
- <% if multi_site? %>
41
- <%= render 'sites' %>
42
- <% end %>
43
- </div>
19
+ <%= render "dashboard" %>
44
20
  </div>
@@ -29,9 +29,8 @@
29
29
  html: {id: "element_#{element.id}_form".html_safe, class: 'element-body'} do |f| %>
30
30
 
31
31
  <div id="element_<%= element.id %>_errors" class="element_errors hidden">
32
- <h2><%= Alchemy.t("Validation failed") %></h2>
32
+ <alchemy-icon name="alert"></alchemy-icon>
33
33
  <p><%= Alchemy.t(:ingredient_validations_headline) %></p>
34
- <ul class="error-messages"></ul>
35
34
  </div>
36
35
 
37
36
  <!-- Ingredients -->
@@ -10,7 +10,7 @@
10
10
  collection: elements_for_select(@elements),
11
11
  prompt: Alchemy.t(:select_element),
12
12
  selected: (@elements.first if @elements.count == 1),
13
- input_html: {is: 'alchemy-select', autofocus: true, disabled: @elements.count == 1} %>
13
+ input_html: {is: 'alchemy-select', autofocus: true} %>
14
14
  <% if @elements.count == 1 %>
15
15
  <%= form.hidden_field :name, value: @elements.first[:name] %>
16
16
  <% end %>
@@ -9,9 +9,16 @@
9
9
  include_blank: false %>
10
10
  <%- end -%>
11
11
  <%- if ingredient.settings[:css_classes].present? -%>
12
- <%= f.input :css_class,
13
- collection: ingredient.settings[:css_classes],
14
- include_blank: Alchemy.t('None') %>
12
+ <% css_classes = ingredient.settings[:css_classes] %>
13
+ <% css_classes_collection = case css_classes.first
14
+ when Array
15
+ then css_classes
16
+ else
17
+ css_classes.map do |klass|
18
+ [Alchemy.t(klass, scope: "picture_ingredients.css_classes", default: picture_editor.css_class.camelcase), klass]
19
+ end
20
+ end %>
21
+ <%= f.input :css_class, collection: css_classes_collection, include_blank: false %>
15
22
  <%- else -%>
16
23
  <% Alchemy::Deprecation.warn %(Float positioning in Picture ingredients is deprecated. If you rely on them, please use `css_classes` in your "#{ingredient.role}" settings instead.) %>
17
24
  <%= f.input :css_class,
@@ -3,3 +3,10 @@
3
3
  <% if @ingredient.settings[:anchor] %>
4
4
  <alchemy-action name="updateAnchorIcon" params="<%= [@ingredient.id, @ingredient.dom_id.present?].to_json %>"></alchemy-action>
5
5
  <% end %>
6
+ <% if @ingredient.type == "Alchemy::Ingredients::Picture" && @ingredient.css_class.present? %>
7
+ <%= turbo_stream.replace_all "[data-ingredient-id='#{@ingredient.id}'] .picture_ingredient_css_class",
8
+ partial: "alchemy/ingredients/shared/picture_css_class",
9
+ locals: {
10
+ css_class: Alchemy::IngredientEditor.new(@ingredient).css_class
11
+ } %>
12
+ <% end %>
@@ -1,44 +1,18 @@
1
- <%- if @languages.any? -%>
2
- <table class="list" id="languages_list">
3
- <thead>
4
- <tr>
5
- <th class="icon"></th>
6
- <th>
7
- <%= sort_link @query, :name %>
8
- </th>
9
- <th>
10
- <%= sort_link @query, :language_code %>
11
- </th>
12
- <th>
13
- <%= sort_link @query, :country_code %>
14
- </th>
15
- <th>
16
- <%= Alchemy::Language.human_attribute_name(:code) %>
17
- </th>
18
- <th>
19
- <%= Alchemy::Language.human_attribute_name(:locale) %>
20
- </th>
21
- <th>
22
- <%= Alchemy::Language.human_attribute_name(:frontpage_name) %>
23
- </th>
24
- <th>
25
- <%= Alchemy::Language.human_attribute_name(:page_layout) %>
26
- </th>
27
- <th class="center">
28
- <%= Alchemy::Language.human_attribute_name(:public) %>
29
- </th>
30
- <th class="center">
31
- <%= Alchemy::Language.human_attribute_name(:default) %>
32
- </th>
33
- <th class="tools"></th>
34
- </tr>
35
- </thead>
36
- <tbody>
37
- <%= render_resources %>
38
- </tbody>
39
- </table>
40
- <%- elsif search_filter_params[:q].present? -%>
41
- <p><%= Alchemy.t('Nothing found') %></p>
42
- <%- end -%>
1
+ <%= render Alchemy::Admin::Resource::Table.new(@languages, query: @query, search_filter_params: search_filter_params) do |table| %>
2
+ <% table.icon_column "translate-2", style: false %>
3
+ <% table.column :name, sortable: true %>
4
+ <% table.column :language_code, sortable: true %>
5
+ <% table.column :country_code %>
6
+ <% table.column :code %>
7
+ <% table.column :locale %>
8
+ <% table.column :frontpage_name %>
9
+ <% table.column :page_layout do |row| %>
10
+ <%= Alchemy::Page.human_layout_name(row.page_layout) %>
11
+ <% end %>
12
+ <% table.column :public %>
13
+ <% table.column :default %>
14
+ <% table.delete_button tooltip: Alchemy.t(:delete_language) %>
15
+ <% table.edit_button tooltip: Alchemy.t(:edit_language), dialog_size: "430x415" %>
16
+ <% end %>
43
17
 
44
18
  <%= paginate @languages, theme: 'alchemy' %>
@@ -13,7 +13,7 @@
13
13
  value: node.page && node.read_attribute(:name).blank? ? nil : node.name,
14
14
  placeholder: node.page ? node.page.name : nil
15
15
  } %>
16
- <%= render Alchemy::Admin::PageSelect.new(node.page, allow_clear: true) do %>
16
+ <%= render Alchemy::Admin::PageSelect.new(node.page, allow_clear: true, query_params: {contentpages: true}) do %>
17
17
  <%= f.input :page_id, label: Alchemy::Page.model_name.human %>
18
18
  <% end %>
19
19
  <%= f.input :url, input_html: { disabled: node.page }, hint: Alchemy.t(:node_url_hint) %>