alchemy_cms 7.3.5 → 7.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +56 -0
  3. data/Gemfile +3 -3
  4. data/README.md +2 -2
  5. data/alchemy_cms.gemspec +1 -4
  6. data/app/assets/builds/alchemy/admin.css +9 -1
  7. data/app/assets/builds/alchemy/admin.css.map +1 -1
  8. data/app/assets/builds/alchemy/custom-properties.css +1 -1
  9. data/app/assets/builds/alchemy/custom-properties.css.map +1 -1
  10. data/app/assets/builds/alchemy/preview.min.js +1 -0
  11. data/app/assets/builds/alchemy/welcome.css +1 -1
  12. data/app/assets/builds/alchemy/welcome.css.map +1 -1
  13. data/app/assets/builds/tinymce/skins/content/alchemy/content.min.css +1 -1
  14. data/app/assets/builds/tinymce/skins/content/alchemy/content.min.css.map +1 -1
  15. data/app/assets/config/alchemy_manifest.js +0 -4
  16. data/app/assets/javascripts/alchemy/admin.js +8 -6
  17. data/app/assets/stylesheets/alchemy/admin/elements.scss +43 -7
  18. data/app/assets/stylesheets/alchemy/admin/forms.scss +4 -0
  19. data/app/assets/stylesheets/alchemy/admin/navigation.scss +9 -1
  20. data/app/assets/stylesheets/alchemy/admin/preview_window.scss +22 -17
  21. data/app/assets/stylesheets/alchemy/admin.scss +1 -1
  22. data/app/assets/stylesheets/alchemy/custom-properties.css +2 -1
  23. data/app/components/alchemy/ingredients/link_view.rb +7 -1
  24. data/app/components/alchemy/ingredients/picture_view.rb +5 -2
  25. data/app/components/alchemy/ingredients/text_view.rb +4 -1
  26. data/app/components/concerns/alchemy/ingredients/link_target.rb +18 -0
  27. data/app/controllers/alchemy/admin/base_controller.rb +8 -3
  28. data/app/controllers/alchemy/admin/elements_controller.rb +2 -2
  29. data/app/controllers/alchemy/admin/layoutpages_controller.rb +1 -0
  30. data/app/controllers/alchemy/admin/pages_controller.rb +5 -1
  31. data/app/controllers/alchemy/elements_controller.rb +3 -0
  32. data/app/helpers/alchemy/admin/form_helper.rb +1 -1
  33. data/app/helpers/alchemy/admin/navigation_helper.rb +22 -1
  34. data/app/javascript/alchemy_admin/components/action.js +2 -1
  35. data/app/javascript/alchemy_admin/components/dialog_link.js +3 -18
  36. data/app/javascript/alchemy_admin/components/element_editor.js +9 -0
  37. data/app/javascript/alchemy_admin/components/elements_window.js +34 -0
  38. data/app/javascript/alchemy_admin/components/elements_window_handle.js +65 -0
  39. data/app/javascript/alchemy_admin/components/icon.js +2 -2
  40. data/app/javascript/alchemy_admin/components/index.js +1 -0
  41. data/app/javascript/alchemy_admin/components/preview_window.js +5 -5
  42. data/app/javascript/alchemy_admin/components/uploader/file_upload.js +1 -1
  43. data/app/javascript/alchemy_admin/confirm_dialog.js +9 -11
  44. data/app/javascript/alchemy_admin/dialog.js +329 -0
  45. data/app/javascript/alchemy_admin/hotkeys.js +3 -2
  46. data/app/javascript/alchemy_admin/image_cropper.js +57 -40
  47. data/app/javascript/alchemy_admin/image_overlay.js +73 -0
  48. data/app/javascript/alchemy_admin/initializer.js +51 -2
  49. data/app/javascript/alchemy_admin/link_dialog.js +2 -1
  50. data/app/javascript/alchemy_admin/node_tree.js +3 -1
  51. data/app/javascript/alchemy_admin/page_sorter.js +1 -1
  52. data/app/javascript/alchemy_admin/picture_selector.js +2 -1
  53. data/app/javascript/alchemy_admin/shoelace_theme.js +2 -2
  54. data/app/javascript/alchemy_admin/templates/compiled.js +1 -0
  55. data/app/javascript/alchemy_admin.js +10 -6
  56. data/app/javascript/preview.js +117 -0
  57. data/app/models/alchemy/image_cropper_settings.rb +3 -4
  58. data/app/views/alchemy/_preview_mode_code.html.erb +1 -1
  59. data/app/views/alchemy/admin/crop.html.erb +19 -16
  60. data/app/views/alchemy/admin/dashboard/info.html.erb +1 -1
  61. data/app/views/alchemy/admin/elements/_add_nested_element_form.html.erb +9 -8
  62. data/app/views/alchemy/admin/elements/_clipboard_button.html.erb +14 -0
  63. data/app/views/alchemy/admin/elements/_element.html.erb +2 -0
  64. data/app/views/alchemy/admin/elements/_form.html.erb +15 -13
  65. data/app/views/alchemy/admin/elements/create.turbo_stream.erb +34 -0
  66. data/app/views/alchemy/admin/elements/index.html.erb +3 -15
  67. data/app/views/alchemy/admin/ingredients/_picture_fields.html.erb +1 -1
  68. data/app/views/alchemy/admin/layoutpages/edit.html.erb +7 -5
  69. data/app/views/alchemy/admin/nodes/_form.html.erb +1 -1
  70. data/app/views/alchemy/admin/pages/_current_page.html.erb +1 -1
  71. data/app/views/alchemy/admin/pages/_form.html.erb +43 -40
  72. data/app/views/alchemy/admin/pages/_locked_page.html.erb +1 -1
  73. data/app/views/alchemy/admin/pages/_page_layout_filter.html.erb +1 -1
  74. data/app/views/alchemy/admin/pages/_sitemap.html.erb +1 -1
  75. data/app/views/alchemy/admin/pages/_table.html.erb +2 -2
  76. data/app/views/alchemy/admin/pages/edit.html.erb +1 -1
  77. data/app/views/alchemy/admin/pages/update.turbo_stream.erb +39 -0
  78. data/app/views/alchemy/admin/partials/_main_navigation_entry.html.erb +3 -4
  79. data/app/views/alchemy/admin/pictures/_picture_description_field.html.erb +7 -5
  80. data/app/views/alchemy/admin/pictures/index.html.erb +13 -9
  81. data/app/views/alchemy/admin/resources/_filter_bar.html.erb +1 -1
  82. data/app/views/layouts/alchemy/admin.html.erb +8 -4
  83. data/bun.lockb +0 -0
  84. data/bundles/tinymce.js +2 -0
  85. data/config/alchemy/config.yml +3 -3
  86. data/config/alchemy/modules.yml +7 -6
  87. data/config/importmap.rb +4 -0
  88. data/config/routes.rb +1 -1
  89. data/lib/alchemy/engine.rb +6 -0
  90. data/lib/alchemy/modules.rb +0 -27
  91. data/lib/alchemy/test_support/having_picture_thumbnails_examples.rb +10 -10
  92. data/lib/alchemy/tinymce.rb +2 -1
  93. data/lib/alchemy/upgrader/seven_point_four.rb +26 -0
  94. data/lib/alchemy/version.rb +1 -1
  95. data/lib/alchemy.rb +14 -0
  96. data/lib/alchemy_cms.rb +0 -2
  97. data/lib/generators/alchemy/ingredient/ingredient_generator.rb +5 -0
  98. data/lib/generators/alchemy/ingredient/templates/view.html.erb +1 -1
  99. data/lib/generators/alchemy/ingredient/templates/view_component.rb.tt +10 -0
  100. data/lib/generators/alchemy/install/install_generator.rb +0 -1
  101. data/lib/generators/alchemy/install/templates/elements.yml.tt +1 -1
  102. data/lib/tasks/alchemy/upgrade.rake +19 -20
  103. data/rollup.config.mjs +44 -1
  104. data/vendor/javascript/cropperjs.min.js +10 -0
  105. data/vendor/javascript/handlebars.min.js +29 -0
  106. data/vendor/javascript/jquery.min.js +2 -0
  107. data/vendor/javascript/select2.min.js +23 -0
  108. data/vendor/javascript/tinymce.min.js +1 -1
  109. metadata +39 -91
  110. data/app/assets/javascripts/alchemy/alchemy.dialog.js.coffee +0 -271
  111. data/app/assets/javascripts/alchemy/alchemy.image_overlay.coffee +0 -54
  112. data/app/assets/javascripts/alchemy/alchemy.preview.js.coffee +0 -97
  113. data/app/assets/javascripts/alchemy/preview.js +0 -1
  114. data/app/assets/javascripts/alchemy/templates/index.js +0 -2
  115. data/app/javascript/alchemy_admin/gui.js +0 -12
  116. data/app/views/alchemy/admin/elements/create.js.erb +0 -35
  117. data/app/views/alchemy/admin/pages/update.js.erb +0 -43
  118. data/lib/alchemy/upgrader/seven_point_zero.rb +0 -36
  119. data/vendor/assets/images/Jcrop.gif +0 -0
  120. data/vendor/assets/javascripts/jquery_plugins/jquery.Jcrop.min.js +0 -7
  121. data/vendor/assets/javascripts/jquery_plugins/select2.js +0 -3729
  122. data/vendor/assets/stylesheets/jquery.Jcrop.min.css +0 -2
  123. data/vendor/assets/stylesheets/tinymce/skins/content/default/content.min.css +0 -1
  124. /data/app/{assets/javascripts/alchemy → javascript/alchemy_admin}/templates/node_folder.hbs +0 -0
  125. /data/app/{assets/javascripts/alchemy → javascript/alchemy_admin}/templates/page_folder.hbs +0 -0
  126. /data/app/{assets/javascripts/tinymce/icons/remixicons/icons.js → javascript/tinymce/icons/remixicons/index.js} +0 -0
  127. /data/app/{assets/javascripts/tinymce/plugins/alchemy_link/plugin.min.js → javascript/tinymce/plugins/alchemy_link/index.js} +0 -0
  128. /data/vendor/assets/{fonts → images}/remixicon.symbol.svg +0 -0
@@ -27,7 +27,7 @@
27
27
  <%= f.submit button_label %>
28
28
  <% end %>
29
29
 
30
- <script>
30
+ <script type="module">
31
31
  const nodeName = document.getElementById("node_name")
32
32
  const nodeUrl = document.getElementById("node_url")
33
33
  const form = document.getElementById("node_form")
@@ -1,4 +1,4 @@
1
- <div class="page_status_and_name" id="page_<%= current_page.id %>_status">
1
+ <div class="page_status_and_name" id="locked_page_<%= current_page.id %>">
2
2
  <%= render 'alchemy/admin/pages/page_infos', page: current_page %>
3
3
  <%= render 'alchemy/admin/pages/page_status', page: current_page %>
4
4
  </div>
@@ -1,55 +1,58 @@
1
- <%= alchemy_form_for [:admin, @page], class: 'edit_page' do |f| %>
2
- <% unless @page.language_root? || @page.layoutpage %>
3
- <%= render Alchemy::Admin::PageSelect.new(@page.parent) do %>
4
- <%= f.input :parent_id, required: true %>
1
+ <%= turbo_frame_tag @page do %>
2
+ <%= alchemy_form_for [:admin, @page], class: 'edit_page', remote: false do |f| %>
3
+ <% unless @page.language_root? || @page.layoutpage %>
4
+ <%= render Alchemy::Admin::PageSelect.new(@page.parent) do %>
5
+ <%= f.input :parent_id, required: true %>
6
+ <% end %>
5
7
  <% end %>
6
- <% end %>
7
8
 
8
- <div class="input check_boxes">
9
- <label class="control-label"><%= Alchemy.t(:page_status) %></label>
10
- <div class="control_group">
11
- <%= render 'alchemy/admin/pages/publication_fields' %>
12
- <%= page_status_checkbox(@page, :restricted) %>
13
- <% if configuration(:sitemap)['show_flag'] %>
14
- <%= page_status_checkbox(@page, :sitemap) %>
15
- <% end %>
9
+ <div class="input check_boxes">
10
+ <label class="control-label"><%= Alchemy.t(:page_status) %></label>
11
+ <div class="control_group">
12
+ <%= render 'alchemy/admin/pages/publication_fields' %>
13
+ <%= page_status_checkbox(@page, :restricted) %>
14
+ <% if configuration(:sitemap)['show_flag'] %>
15
+ <%= page_status_checkbox(@page, :sitemap) %>
16
+ <% end %>
17
+ </div>
16
18
  </div>
17
- </div>
18
19
 
19
- <%= f.input :name, autofocus: true %>
20
- <%= f.input :urlname, as: 'string', input_html: {value: @page.slug}, label: Alchemy::Page.human_attribute_name(:slug) %>
21
- <alchemy-char-counter max-chars="60">
22
- <%= f.input :title %>
23
- </alchemy-char-counter>
20
+ <%= f.input :name, autofocus: true %>
21
+ <%= f.input :urlname, as: 'string', input_html: {value: @page.slug}, label: Alchemy::Page.human_attribute_name(:slug) %>
22
+ <alchemy-char-counter max-chars="60">
23
+ <%= f.input :title %>
24
+ </alchemy-char-counter>
25
+
26
+ <% if Alchemy.enable_searchable %>
27
+ <div class="input check_boxes">
28
+ <label class="control-label"><%= Alchemy.t(:fulltext_search) %></label>
29
+ <div class="control_group">
30
+ <%= page_status_checkbox(@page, :searchable) %>
31
+ </div>
32
+ </div>
33
+ <% end %>
24
34
 
25
- <% if Alchemy.enable_searchable %>
26
35
  <div class="input check_boxes">
27
- <label class="control-label"><%= Alchemy.t(:fulltext_search) %></label>
36
+ <label class="control-label"><%= Alchemy.t(:search_engines) %></label>
28
37
  <div class="control_group">
29
- <%= page_status_checkbox(@page, :searchable) %>
38
+ <%= page_status_checkbox(@page, :robot_index) %>
39
+ <%= page_status_checkbox(@page, :robot_follow) %>
30
40
  </div>
31
41
  </div>
32
- <% end %>
33
42
 
34
- <div class="input check_boxes">
35
- <label class="control-label"><%= Alchemy.t(:search_engines) %></label>
36
- <div class="control_group">
37
- <%= page_status_checkbox(@page, :robot_index) %>
38
- <%= page_status_checkbox(@page, :robot_follow) %>
39
- </div>
40
- </div>
43
+ <alchemy-char-counter max-chars="160">
44
+ <%= f.input :meta_description, as: 'text' %>
45
+ </alchemy-char-counter>
41
46
 
42
- <alchemy-char-counter max-chars="160">
43
- <%= f.input :meta_description, as: 'text' %>
44
- </alchemy-char-counter>
47
+ <%= f.input :meta_keywords,
48
+ as: 'text',
49
+ hint: Alchemy.t('pages.update.comma_seperated') %>
45
50
 
46
- <%= f.input :meta_keywords,
47
- as: 'text',
48
- hint: Alchemy.t('pages.update.comma_seperated') %>
51
+ <%= render Alchemy::Admin::TagsAutocomplete.new do %>
52
+ <%= f.input :tag_list, input_html: { value: f.object.tag_list.join(",") } %>
53
+ <% end %>
49
54
 
50
- <%= render Alchemy::Admin::TagsAutocomplete.new do %>
51
- <%= f.input :tag_list, input_html: { value: f.object.tag_list.join(",") } %>
55
+ <%= hidden_field_tag :view, params[:view] %>
56
+ <%= f.submit Alchemy.t(:save) %>
52
57
  <% end %>
53
-
54
- <%= f.submit Alchemy.t(:save) %>
55
58
  <% end %>
@@ -1,4 +1,4 @@
1
- <% if @page == locked_page %>
1
+ <% if action_name == "edit" && @page == locked_page %>
2
2
  <%= render 'alchemy/admin/pages/current_page', current_page: @page %>
3
3
  <% else %>
4
4
  <div class="locked_page wide" id="locked_page_<%= locked_page.id %>">
@@ -19,7 +19,7 @@
19
19
  </label>
20
20
  </div>
21
21
 
22
- <script type="text/javascript">
22
+ <script type="module">
23
23
  $(function() {
24
24
  $("#page_layout").on("change", function(e) {
25
25
  var url = "<%= alchemy.admin_pages_path(search_filter_params.except(:page_layout, :page).merge(view: "list")) %>";
@@ -19,7 +19,7 @@
19
19
  {{/each}}
20
20
  </script>
21
21
 
22
- <script type="text/javascript">
22
+ <script type="module">
23
23
  $(function() {
24
24
  Alchemy.currentSitemap = new Alchemy.Sitemap({
25
25
  url: '<%= alchemy.tree_admin_pages_path %>',
@@ -67,7 +67,7 @@
67
67
  <% table.with_action :configure, Alchemy.t(:edit_page_properties) do |page| %>
68
68
  <%= link_to_dialog(
69
69
  render_icon(:cog),
70
- alchemy.configure_admin_page_path(page),
70
+ alchemy.configure_admin_page_path(page, view: "list"),
71
71
  {
72
72
  title: Alchemy.t(:edit_page_properties),
73
73
  size: '450x680'
@@ -91,7 +91,7 @@
91
91
  <% end %>
92
92
 
93
93
 
94
- <script type="text/javascript">
94
+ <script type="module">
95
95
  $(function() {
96
96
  Alchemy.PagePublicationFields();
97
97
  });
@@ -144,7 +144,7 @@
144
144
  <% end %>
145
145
 
146
146
  <% content_for :javascripts do %>
147
- <script type="text/javascript" charset="utf-8">
147
+ <script type="module">
148
148
  $(document).one('turbo:load', function() {
149
149
  $('#unlock_page_form, #publish_page_form').on('submit', function(event) {
150
150
  var not_dirty = Alchemy.checkPageDirtyness(this);
@@ -0,0 +1,39 @@
1
+ <alchemy-growl><%= @notice %></alchemy-action>
2
+ <alchemy-action name="closeCurrentDialog"></alchemy-action>
3
+
4
+ <% if @while_page_edit -%>
5
+ <%= turbo_stream.replace "locked_page_#{@page.id}" do %>
6
+ <%= render("alchemy/admin/pages/current_page", current_page: @page) %>
7
+ <% end %>
8
+ <alchemy-action name="reloadPreview"></alchemy-action>
9
+ <% else %>
10
+ <%= turbo_stream.replace "locked_page_#{@page.id}" do %>
11
+ <%= render("alchemy/admin/pages/locked_page", locked_page: @page) %>
12
+ <% end %>
13
+
14
+ <% if @view == "list" %>
15
+ <turbo-stream action="refresh"></turbo-stream>
16
+ <% elsif @page.parent_id != @old_parent_id -%>
17
+ <%= turbo_stream.append "sitemap" do %>
18
+ <script type="module">
19
+ Alchemy.currentSitemap.load(<%= @page.get_language_root.id %>);
20
+ </script>
21
+ <% end %>
22
+ <% else -%>
23
+ <% if @page.layoutpage %>
24
+ <%= turbo_stream.replace "page_#{@page.id}" do %>
25
+ <%= render("alchemy/admin/layoutpages/layoutpage", layoutpage: @page) %>
26
+ <% end %>
27
+ <% else %>
28
+ <%= turbo_stream.append "sitemap" do %>
29
+ <script type="module">
30
+ const page = document.getElementById('page_<%= @page.id %>');
31
+ const page_html = "<%= j render('page', page: @page) %>".replace(/__ID__/g, "<%= @page.id %>");
32
+ const compiler = Handlebars.compile(page_html);
33
+ const tree = <%== @tree.to_json %>;
34
+ page.outerHTML = compiler(tree.pages[0]);
35
+ </script>
36
+ <% end %>
37
+ <% end %>
38
+ <% end -%>
39
+ <% end %>
@@ -6,10 +6,9 @@
6
6
  <% elsif navigation["inline_image"] %>
7
7
  <%== navigation["inline_image"] %>
8
8
  <% elsif navigation["icon"] %>
9
- <%# Cannot use the render_icon helper, because the navigation["icon"] includes the style %>
10
- <svg class="icon">
11
- <use href="<%= asset_path("remixicon.symbol.svg") %>#ri-<%= navigation["icon"] %>" />
12
- </svg>
9
+ <%= content_tag :"alchemy-icon", nil,
10
+ name: navigation["icon"],
11
+ "icon-style": navigation["icon-style"] %>
13
12
  <% else %>
14
13
  <%= render_icon :table %>
15
14
  <% end %>
@@ -21,9 +21,11 @@
21
21
  <script type="module">
22
22
  const select = document.querySelector("#language_id")
23
23
 
24
- select.addEventListener("change", () => {
25
- const url = new URL(select.dataset.url)
26
- url.searchParams.set("language_id", select.value)
27
- Turbo.visit(url, { frame: "picture_descriptions" })
28
- })
24
+ if (select) {
25
+ select.addEventListener("change", () => {
26
+ const url = new URL(select.dataset.url)
27
+ url.searchParams.set("language_id", select.value)
28
+ Turbo.visit(url, { frame: "picture_descriptions" })
29
+ })
30
+ }
29
31
  </script>
@@ -86,16 +86,20 @@
86
86
  </div>
87
87
 
88
88
  <% content_for :javascripts do %>
89
- <script type="text/javascript" charset="utf-8">
90
- $(function() {
91
- Alchemy.pictureSelector();
92
- $('#picture_archive').on("click", ".thumbnail_background", function(event) {
93
- var url = $(this).attr('href');
94
- var overlay = new Alchemy.ImageOverlay(url);
95
- overlay.open();
96
- event.preventDefault();
97
- return false;
89
+ <script type="module">
90
+ import ImageOverlay from "alchemy_admin/image_overlay";
91
+ import pictureSelector from "alchemy_admin/picture_selector";
92
+ import { on } from "alchemy_admin/utils/events";
93
+
94
+ pictureSelector();
95
+ on("click", "#picture_archive", ".thumbnail_background", (event) => {
96
+ const url = event.target.closest("a")?.href;
97
+ const overlay = new ImageOverlay(url, {
98
+ size: `${window.innerWidth}x${window.innerHeight}`,
99
+ padding: false
98
100
  });
101
+ overlay.open();
102
+ event.preventDefault();
99
103
  });
100
104
  </script>
101
105
  <% end %>
@@ -2,7 +2,7 @@
2
2
  <%= render partial: "filter", collection: resource_filters_for_select %>
3
3
  </div>
4
4
 
5
- <script type="text/javascript">
5
+ <script type="module">
6
6
  $(function() {
7
7
  $('select', '#filter_bar').on('change', function(e) {
8
8
  var $this = $(this);
@@ -5,15 +5,17 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
6
6
  <title><%= render_alchemy_title %></title>
7
7
  <link rel="shortcut icon" href="<%= asset_path('alchemy/favicon.ico') %>">
8
+ <link rel="preload" href="<%= asset_path("remixicon.symbol.svg") %>" as="image" type="<%= Mime::Type.lookup_by_extension(:svg) %>" crossorigin>
8
9
  <%= csrf_meta_tag %>
9
10
  <meta name="robots" content="noindex">
10
- <meta name="alchemy-icon-sprite" content="<%= asset_path("remixicon.symbol.svg") %>">
11
11
  <meta name="turbo-prefetch" content="false">
12
12
  <meta name="turbo-cache-control" content="no-cache">
13
13
  <%= stylesheet_link_tag('alchemy/custom-properties', media: 'screen', 'data-turbo-track' => true) %>
14
14
  <%= stylesheet_link_tag('alchemy/admin', media: 'screen', 'data-turbo-track' => true) %>
15
15
  <%= stylesheet_link_tag('alchemy/admin/print', media: 'print', 'data-turbo-track' => true) %>
16
- <%= stylesheet_link_tag('alchemy/admin/custom', 'data-turbo-track' => true) %>
16
+ <% Alchemy.admin_stylesheets.each do |stylesheet| %>
17
+ <%= stylesheet_link_tag(stylesheet, 'data-turbo-track' => true) %>
18
+ <% end %>
17
19
  <%= yield :stylesheets %>
18
20
  <script>
19
21
  // Global Alchemy JavaScript object.
@@ -32,7 +34,9 @@
32
34
  <% end %>
33
35
  <%= yield :javascript_includes %>
34
36
  </head>
35
- <%= content_tag :body, id: 'alchemy', class: alchemy_body_class + ["alchemy-light"] do %>
37
+ <%= content_tag :body, id: 'alchemy',
38
+ class: alchemy_body_class + ["alchemy-light"],
39
+ style: cookies["alchemy-elements-window-width"] && "--elements-window-width: #{cookies["alchemy-elements-window-width"]}px" do %>
36
40
  <noscript>
37
41
  <h1><%= Alchemy.t(:javascript_disabled_headline) %></h1>
38
42
  <p><%= Alchemy.t(:javascript_disabled_text) %></p>
@@ -89,7 +93,7 @@
89
93
  <div id="main_content">
90
94
  <%= yield %>
91
95
  </div>
92
- <script>
96
+ <script type="module">
93
97
  // Setting the correct locale for select2 dropdown replacement.
94
98
  $.extend($.fn.select2.defaults, $.fn.select2.locales['<%= ::I18n.locale %>']);
95
99
  </script>
data/bun.lockb CHANGED
Binary file
data/bundles/tinymce.js CHANGED
@@ -3,6 +3,7 @@ import tinymce from "tinymce"
3
3
 
4
4
  /* Default icons are required. After that, import custom icons if applicable */
5
5
  import "tinymce/icons/default"
6
+ import "tinymce/icons/remixicons"
6
7
 
7
8
  /* Required TinyMCE components */
8
9
  import "tinymce/themes/silver"
@@ -16,5 +17,6 @@ import "tinymce/plugins/directionality"
16
17
  import "tinymce/plugins/fullscreen"
17
18
  import "tinymce/plugins/link"
18
19
  import "tinymce/plugins/lists"
20
+ import "tinymce/plugins/alchemy_link"
19
21
 
20
22
  export default tinymce
@@ -199,9 +199,9 @@ link_target_options: [blank]
199
199
  # validates_format_of :url, with: Alchemy::Config.get('format_matchers')['url']
200
200
  #
201
201
  format_matchers:
202
- email: !ruby/regexp '/\A[^@\s]+@([^@\s]+\.)+[^@\s]+\z/'
203
- url: !ruby/regexp '/\A[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?\z/ix'
204
- link_url: !ruby/regexp '/^(tel:|mailto:|\/|[a-z]+:\/\/)/'
202
+ email: !ruby/regexp /\A[^@\s]+@([^@\s]+\.)+[^@\s]+\z/
203
+ url: !ruby/regexp /\A[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?\z/ix
204
+ link_url: !ruby/regexp /^(tel:|mailto:|\/|[a-z]+:\/\/)/
205
205
 
206
206
  # The layout used for rendering the +alchemy/admin/pages#show+ action.
207
207
  admin_page_preview_layout: application
@@ -7,7 +7,7 @@
7
7
  name: Home
8
8
  controller: "/alchemy/admin/dashboard"
9
9
  action: index
10
- icon: home-2-line
10
+ icon: home-2
11
11
 
12
12
  - name: pages
13
13
  engine_name: alchemy
@@ -16,7 +16,7 @@
16
16
  name: "modules.pages"
17
17
  controller: "/alchemy/admin/pages"
18
18
  action: index
19
- icon: pages-line
19
+ icon: pages
20
20
  sub_navigation:
21
21
  - name: "modules.pages"
22
22
  controller: "/alchemy/admin/pages"
@@ -35,7 +35,7 @@
35
35
  name: "modules.menus"
36
36
  controller: "/alchemy/admin/nodes"
37
37
  action: index
38
- icon: menu-2-line
38
+ icon: menu-2
39
39
 
40
40
  - name: languages
41
41
  engine_name: alchemy
@@ -45,6 +45,7 @@
45
45
  controller: "/alchemy/admin/languages"
46
46
  action: index
47
47
  icon: translate-2
48
+ icon-style: none
48
49
 
49
50
  - name: sites
50
51
  engine_name: alchemy
@@ -53,7 +54,7 @@
53
54
  name: "modules.sites"
54
55
  controller: "/alchemy/admin/sites"
55
56
  action: index
56
- icon: global-line
57
+ icon: global
57
58
 
58
59
  - name: tags
59
60
  engine_name: alchemy
@@ -62,7 +63,7 @@
62
63
  name: "modules.tags"
63
64
  controller: "/alchemy/admin/tags"
64
65
  action: index
65
- icon: price-tag-3-line
66
+ icon: price-tag-3
66
67
 
67
68
  - name: archive
68
69
  engine_name: alchemy
@@ -71,7 +72,7 @@
71
72
  controller: "/alchemy/admin/pictures"
72
73
  action: index
73
74
  name: "modules.library"
74
- icon: archive-drawer-line
75
+ icon: archive-drawer
75
76
  sub_navigation:
76
77
  - name: "modules.pictures"
77
78
  controller: "/alchemy/admin/pictures"
data/config/importmap.rb CHANGED
@@ -1,7 +1,11 @@
1
1
  pin "@ungap/custom-elements", to: "ungap-custom-elements.min.js", preload: true # @1.3.0
2
2
  pin "clipboard", to: "clipboard.min.js", preload: true
3
+ pin "cropperjs", to: "cropperjs.min.js", preload: true
3
4
  pin "flatpickr", to: "flatpickr.min.js", preload: true # @4.6.13
5
+ pin "handlebars", to: "handlebars.min.js", preload: true # @4.7.8
6
+ pin "jquery", to: "jquery.min.js", preload: true
4
7
  pin "keymaster", to: "keymaster.min.js", preload: true
8
+ pin "select2", to: "select2.min.js", preload: true
5
9
  pin "sortablejs", to: "sortable.min.js", preload: true # @1.15.1
6
10
  pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true
7
11
  pin "shoelace", to: "shoelace.min.js", preload: true
data/config/routes.rb CHANGED
@@ -88,7 +88,7 @@ Alchemy::Engine.routes.draw do
88
88
  end
89
89
  end
90
90
 
91
- resource :clipboard, only: :index, controller: "clipboard" do
91
+ resource :clipboard, only: [], controller: "clipboard" do
92
92
  collection do
93
93
  get :index
94
94
  delete :clear
@@ -20,6 +20,12 @@ module Alchemy
20
20
  NonStupidDigestAssets.whitelist += [/^tinymce\//]
21
21
  end
22
22
 
23
+ initializer "alchemy.admin_stylesheets" do |app|
24
+ Alchemy.admin_stylesheets.each do |stylesheet|
25
+ app.config.assets.precompile << stylesheet
26
+ end
27
+ end
28
+
23
29
  initializer "alchemy.importmap" do |app|
24
30
  watch_paths = []
25
31
 
@@ -27,35 +27,8 @@ module Alchemy
27
27
  def register_module(module_definition)
28
28
  definition_hash = module_definition.deep_stringify_keys
29
29
 
30
- ### Validate controller(s) existence
31
- if definition_hash["navigation"].is_a?(Hash)
32
- defined_controllers = [definition_hash["navigation"]["controller"]]
33
-
34
- if definition_hash["navigation"]["sub_navigation"].is_a?(Array)
35
- defined_controllers.concat(definition_hash["navigation"]["sub_navigation"].map { |x| x["controller"] })
36
- end
37
-
38
- validate_controllers_existence(defined_controllers, definition_hash)
39
- end
40
-
41
30
  @@alchemy_modules |= [definition_hash]
42
31
  end
43
-
44
- private
45
-
46
- def validate_controllers_existence(controllers, definition_hash)
47
- controllers.each do |controller_val|
48
- next if controller_val.blank?
49
-
50
- controller_name = "#{controller_val.camelize}Controller"
51
-
52
- begin
53
- controller_name.constantize
54
- rescue NameError
55
- raise "Error in AlchemyCMS module definition: '#{definition_hash["name"]}'. Could not find the matching controller class #{controller_name.sub(/^::/, "")} for the specified controller: '#{controller_val}'"
56
- end
57
- end
58
- end
59
32
  end
60
33
 
61
34
  # Get the module definition for given module name
@@ -562,8 +562,8 @@ RSpec.shared_examples_for "having picture thumbnails" do
562
562
  context "size 200x50" do
563
563
  let(:size) { "200x50" }
564
564
 
565
- it "default box should be [0, 25, 200, 75]" do
566
- expect(subject[:default_box]).to eq([0, 25, 200, 75])
565
+ it "default box should be [0, 25, 200, 50]" do
566
+ expect(subject[:default_box]).to eq([0, 25, 200, 50])
567
567
  end
568
568
  end
569
569
 
@@ -578,16 +578,16 @@ RSpec.shared_examples_for "having picture thumbnails" do
578
578
  context "size 50x100" do
579
579
  let(:size) { "50x100" }
580
580
 
581
- it "the hash should be {x1: 75, y1: 0, x2: 125, y2: 100}" do
582
- expect(subject[:default_box]).to eq([75, 0, 125, 100])
581
+ it "the hash should be {x1: 75, y1: 0, x2: 50, y2: 100}" do
582
+ expect(subject[:default_box]).to eq([75, 0, 50, 100])
583
583
  end
584
584
  end
585
585
 
586
586
  context "size 50x50" do
587
587
  let(:size) { "50x50" }
588
588
 
589
- it "the hash should be {x1: 50, y1: 0, x2: 150, y2: 100}" do
590
- expect(subject[:default_box]).to eq([50, 0, 150, 100])
589
+ it "the hash should be {x1: 50, y1: 0, x2: 100, y2: 100}" do
590
+ expect(subject[:default_box]).to eq([50, 0, 100, 100])
591
591
  end
592
592
  end
593
593
 
@@ -602,16 +602,16 @@ RSpec.shared_examples_for "having picture thumbnails" do
602
602
  context "size 400x100" do
603
603
  let(:size) { "400x100" }
604
604
 
605
- it "the hash should be {x1: 0, y1: 25, x2: 200, y2: 75}" do
606
- expect(subject[:default_box]).to eq([0, 25, 200, 75])
605
+ it "the hash should be {x1: 0, y1: 25, x2: 200, y2: 50}" do
606
+ expect(subject[:default_box]).to eq([0, 25, 200, 50])
607
607
  end
608
608
  end
609
609
 
610
610
  context "size 200x200" do
611
611
  let(:size) { "200x200" }
612
612
 
613
- it "the hash should be {x1: 50, y1: 0, x2: 150, y2: 100}" do
614
- expect(subject[:default_box]).to eq([50, 0, 150, 100])
613
+ it "the hash should be {x1: 50, y1: 0, x2: 100, y2: 100}" do
614
+ expect(subject[:default_box]).to eq([50, 0, 100, 100])
615
615
  end
616
616
  end
617
617
  end
@@ -5,6 +5,7 @@ module Alchemy
5
5
  mattr_accessor :languages, :plugins
6
6
 
7
7
  DEFAULT_PLUGINS = %w[
8
+ alchemy_link
8
9
  anchor
9
10
  charmap
10
11
  code
@@ -14,7 +15,7 @@ module Alchemy
14
15
  lists
15
16
  ]
16
17
 
17
- @@plugins = DEFAULT_PLUGINS + %w[alchemy_link]
18
+ @@plugins = DEFAULT_PLUGINS
18
19
  @@init = {
19
20
  skin: "alchemy",
20
21
  content_css: "/assets/tinymce/skins/content/alchemy/content.min.css",
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+ require "thor"
5
+
6
+ module Alchemy
7
+ class Upgrader::SevenPointFour < Upgrader
8
+ include Thor::Base
9
+ include Thor::Actions
10
+
11
+ class << self
12
+ def update_custom_css_config
13
+ if File.exist? "app/assets/config/manifest.js"
14
+ log "Removing alchemy/admin/custom.css from assets config file."
15
+ task.gsub_file "app/assets/config/manifest.js", %r{//= link alchemy/admin/custom.css\n}, ""
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def task
22
+ @_task || new
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Alchemy
4
- VERSION = "7.3.5"
4
+ VERSION = "7.4.0"
5
5
 
6
6
  def self.version
7
7
  VERSION
data/lib/alchemy.rb CHANGED
@@ -98,6 +98,20 @@ module Alchemy
98
98
  }])
99
99
  end
100
100
 
101
+ # Additional stylesheets to be included in the Alchemy admin UI
102
+ #
103
+ # == Example
104
+ #
105
+ # # lib/alchemy/devise/engine.rb
106
+ # initializer "alchemy.devise.stylesheets", before: "alchemy.admin_stylesheets" do
107
+ # Alchemy.admin_stylesheets << "alchemy/devise/admin.css"
108
+ # end
109
+ #
110
+ # @return [Set<String>]
111
+ def self.admin_stylesheets
112
+ @_admin_stylesheets ||= Set.new(["alchemy/admin/custom.css"])
113
+ end
114
+
101
115
  # Define page publish targets
102
116
  #
103
117
  # A publish target is a ActiveJob that gets performed
data/lib/alchemy_cms.rb CHANGED
@@ -11,9 +11,7 @@ require "awesome_nested_set"
11
11
  require "cancan"
12
12
  require "dragonfly"
13
13
  require "gutentag"
14
- require "handlebars_assets"
15
14
  require "importmap-rails"
16
- require "jquery-rails"
17
15
  require "kaminari"
18
16
  require "non_stupid_digest_assets"
19
17
  require "ransack"