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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +56 -0
- data/Gemfile +3 -3
- data/README.md +2 -2
- data/alchemy_cms.gemspec +1 -4
- data/app/assets/builds/alchemy/admin.css +9 -1
- data/app/assets/builds/alchemy/admin.css.map +1 -1
- data/app/assets/builds/alchemy/custom-properties.css +1 -1
- data/app/assets/builds/alchemy/custom-properties.css.map +1 -1
- data/app/assets/builds/alchemy/preview.min.js +1 -0
- data/app/assets/builds/alchemy/welcome.css +1 -1
- data/app/assets/builds/alchemy/welcome.css.map +1 -1
- data/app/assets/builds/tinymce/skins/content/alchemy/content.min.css +1 -1
- data/app/assets/builds/tinymce/skins/content/alchemy/content.min.css.map +1 -1
- data/app/assets/config/alchemy_manifest.js +0 -4
- data/app/assets/javascripts/alchemy/admin.js +8 -6
- data/app/assets/stylesheets/alchemy/admin/elements.scss +43 -7
- data/app/assets/stylesheets/alchemy/admin/forms.scss +4 -0
- data/app/assets/stylesheets/alchemy/admin/navigation.scss +9 -1
- data/app/assets/stylesheets/alchemy/admin/preview_window.scss +22 -17
- data/app/assets/stylesheets/alchemy/admin.scss +1 -1
- data/app/assets/stylesheets/alchemy/custom-properties.css +2 -1
- data/app/components/alchemy/ingredients/link_view.rb +7 -1
- data/app/components/alchemy/ingredients/picture_view.rb +5 -2
- data/app/components/alchemy/ingredients/text_view.rb +4 -1
- data/app/components/concerns/alchemy/ingredients/link_target.rb +18 -0
- data/app/controllers/alchemy/admin/base_controller.rb +8 -3
- data/app/controllers/alchemy/admin/elements_controller.rb +2 -2
- data/app/controllers/alchemy/admin/layoutpages_controller.rb +1 -0
- data/app/controllers/alchemy/admin/pages_controller.rb +5 -1
- data/app/controllers/alchemy/elements_controller.rb +3 -0
- data/app/helpers/alchemy/admin/form_helper.rb +1 -1
- data/app/helpers/alchemy/admin/navigation_helper.rb +22 -1
- data/app/javascript/alchemy_admin/components/action.js +2 -1
- data/app/javascript/alchemy_admin/components/dialog_link.js +3 -18
- data/app/javascript/alchemy_admin/components/element_editor.js +9 -0
- data/app/javascript/alchemy_admin/components/elements_window.js +34 -0
- data/app/javascript/alchemy_admin/components/elements_window_handle.js +65 -0
- data/app/javascript/alchemy_admin/components/icon.js +2 -2
- data/app/javascript/alchemy_admin/components/index.js +1 -0
- data/app/javascript/alchemy_admin/components/preview_window.js +5 -5
- data/app/javascript/alchemy_admin/components/uploader/file_upload.js +1 -1
- data/app/javascript/alchemy_admin/confirm_dialog.js +9 -11
- data/app/javascript/alchemy_admin/dialog.js +329 -0
- data/app/javascript/alchemy_admin/hotkeys.js +3 -2
- data/app/javascript/alchemy_admin/image_cropper.js +57 -40
- data/app/javascript/alchemy_admin/image_overlay.js +73 -0
- data/app/javascript/alchemy_admin/initializer.js +51 -2
- data/app/javascript/alchemy_admin/link_dialog.js +2 -1
- data/app/javascript/alchemy_admin/node_tree.js +3 -1
- data/app/javascript/alchemy_admin/page_sorter.js +1 -1
- data/app/javascript/alchemy_admin/picture_selector.js +2 -1
- data/app/javascript/alchemy_admin/shoelace_theme.js +2 -2
- data/app/javascript/alchemy_admin/templates/compiled.js +1 -0
- data/app/javascript/alchemy_admin.js +10 -6
- data/app/javascript/preview.js +117 -0
- data/app/models/alchemy/image_cropper_settings.rb +3 -4
- data/app/views/alchemy/_preview_mode_code.html.erb +1 -1
- data/app/views/alchemy/admin/crop.html.erb +19 -16
- data/app/views/alchemy/admin/dashboard/info.html.erb +1 -1
- data/app/views/alchemy/admin/elements/_add_nested_element_form.html.erb +9 -8
- data/app/views/alchemy/admin/elements/_clipboard_button.html.erb +14 -0
- data/app/views/alchemy/admin/elements/_element.html.erb +2 -0
- data/app/views/alchemy/admin/elements/_form.html.erb +15 -13
- data/app/views/alchemy/admin/elements/create.turbo_stream.erb +34 -0
- data/app/views/alchemy/admin/elements/index.html.erb +3 -15
- data/app/views/alchemy/admin/ingredients/_picture_fields.html.erb +1 -1
- data/app/views/alchemy/admin/layoutpages/edit.html.erb +7 -5
- data/app/views/alchemy/admin/nodes/_form.html.erb +1 -1
- data/app/views/alchemy/admin/pages/_current_page.html.erb +1 -1
- data/app/views/alchemy/admin/pages/_form.html.erb +43 -40
- data/app/views/alchemy/admin/pages/_locked_page.html.erb +1 -1
- data/app/views/alchemy/admin/pages/_page_layout_filter.html.erb +1 -1
- data/app/views/alchemy/admin/pages/_sitemap.html.erb +1 -1
- data/app/views/alchemy/admin/pages/_table.html.erb +2 -2
- data/app/views/alchemy/admin/pages/edit.html.erb +1 -1
- data/app/views/alchemy/admin/pages/update.turbo_stream.erb +39 -0
- data/app/views/alchemy/admin/partials/_main_navigation_entry.html.erb +3 -4
- data/app/views/alchemy/admin/pictures/_picture_description_field.html.erb +7 -5
- data/app/views/alchemy/admin/pictures/index.html.erb +13 -9
- data/app/views/alchemy/admin/resources/_filter_bar.html.erb +1 -1
- data/app/views/layouts/alchemy/admin.html.erb +8 -4
- data/bun.lockb +0 -0
- data/bundles/tinymce.js +2 -0
- data/config/alchemy/config.yml +3 -3
- data/config/alchemy/modules.yml +7 -6
- data/config/importmap.rb +4 -0
- data/config/routes.rb +1 -1
- data/lib/alchemy/engine.rb +6 -0
- data/lib/alchemy/modules.rb +0 -27
- data/lib/alchemy/test_support/having_picture_thumbnails_examples.rb +10 -10
- data/lib/alchemy/tinymce.rb +2 -1
- data/lib/alchemy/upgrader/seven_point_four.rb +26 -0
- data/lib/alchemy/version.rb +1 -1
- data/lib/alchemy.rb +14 -0
- data/lib/alchemy_cms.rb +0 -2
- data/lib/generators/alchemy/ingredient/ingredient_generator.rb +5 -0
- data/lib/generators/alchemy/ingredient/templates/view.html.erb +1 -1
- data/lib/generators/alchemy/ingredient/templates/view_component.rb.tt +10 -0
- data/lib/generators/alchemy/install/install_generator.rb +0 -1
- data/lib/generators/alchemy/install/templates/elements.yml.tt +1 -1
- data/lib/tasks/alchemy/upgrade.rake +19 -20
- data/rollup.config.mjs +44 -1
- data/vendor/javascript/cropperjs.min.js +10 -0
- data/vendor/javascript/handlebars.min.js +29 -0
- data/vendor/javascript/jquery.min.js +2 -0
- data/vendor/javascript/select2.min.js +23 -0
- data/vendor/javascript/tinymce.min.js +1 -1
- metadata +39 -91
- data/app/assets/javascripts/alchemy/alchemy.dialog.js.coffee +0 -271
- data/app/assets/javascripts/alchemy/alchemy.image_overlay.coffee +0 -54
- data/app/assets/javascripts/alchemy/alchemy.preview.js.coffee +0 -97
- data/app/assets/javascripts/alchemy/preview.js +0 -1
- data/app/assets/javascripts/alchemy/templates/index.js +0 -2
- data/app/javascript/alchemy_admin/gui.js +0 -12
- data/app/views/alchemy/admin/elements/create.js.erb +0 -35
- data/app/views/alchemy/admin/pages/update.js.erb +0 -43
- data/lib/alchemy/upgrader/seven_point_zero.rb +0 -36
- data/vendor/assets/images/Jcrop.gif +0 -0
- data/vendor/assets/javascripts/jquery_plugins/jquery.Jcrop.min.js +0 -7
- data/vendor/assets/javascripts/jquery_plugins/select2.js +0 -3729
- data/vendor/assets/stylesheets/jquery.Jcrop.min.css +0 -2
- data/vendor/assets/stylesheets/tinymce/skins/content/default/content.min.css +0 -1
- /data/app/{assets/javascripts/alchemy → javascript/alchemy_admin}/templates/node_folder.hbs +0 -0
- /data/app/{assets/javascripts/alchemy → javascript/alchemy_admin}/templates/page_folder.hbs +0 -0
- /data/app/{assets/javascripts/tinymce/icons/remixicons/icons.js → javascript/tinymce/icons/remixicons/index.js} +0 -0
- /data/app/{assets/javascripts/tinymce/plugins/alchemy_link/plugin.min.js → javascript/tinymce/plugins/alchemy_link/index.js} +0 -0
- /data/vendor/assets/{fonts → images}/remixicon.symbol.svg +0 -0
@@ -1,4 +1,4 @@
|
|
1
|
-
<div class="page_status_and_name" id="
|
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
|
-
<%=
|
2
|
-
|
3
|
-
|
4
|
-
<%=
|
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
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
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
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
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(:
|
36
|
+
<label class="control-label"><%= Alchemy.t(:search_engines) %></label>
|
28
37
|
<div class="control_group">
|
29
|
-
<%= page_status_checkbox(@page, :
|
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
|
-
|
35
|
-
|
36
|
-
|
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
|
-
|
43
|
-
|
44
|
-
|
47
|
+
<%= f.input :meta_keywords,
|
48
|
+
as: 'text',
|
49
|
+
hint: Alchemy.t('pages.update.comma_seperated') %>
|
45
50
|
|
46
|
-
|
47
|
-
|
48
|
-
|
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
|
-
|
51
|
-
<%= f.
|
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 %>
|
@@ -19,7 +19,7 @@
|
|
19
19
|
</label>
|
20
20
|
</div>
|
21
21
|
|
22
|
-
<script type="
|
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")) %>";
|
@@ -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="
|
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="
|
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
|
-
|
10
|
-
|
11
|
-
|
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
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
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="
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
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 %>
|
@@ -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
|
-
|
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',
|
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
|
data/config/alchemy/config.yml
CHANGED
@@ -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
|
203
|
-
url: !ruby/regexp
|
204
|
-
link_url: !ruby/regexp
|
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
|
data/config/alchemy/modules.yml
CHANGED
@@ -7,7 +7,7 @@
|
|
7
7
|
name: Home
|
8
8
|
controller: "/alchemy/admin/dashboard"
|
9
9
|
action: index
|
10
|
-
icon: home-2
|
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
|
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
|
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
|
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
|
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
|
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
data/lib/alchemy/engine.rb
CHANGED
@@ -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
|
|
data/lib/alchemy/modules.rb
CHANGED
@@ -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,
|
566
|
-
expect(subject[:default_box]).to eq([0, 25, 200,
|
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:
|
582
|
-
expect(subject[:default_box]).to eq([75, 0,
|
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:
|
590
|
-
expect(subject[:default_box]).to eq([50, 0,
|
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:
|
606
|
-
expect(subject[:default_box]).to eq([0, 25, 200,
|
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:
|
614
|
-
expect(subject[:default_box]).to eq([50, 0,
|
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
|
data/lib/alchemy/tinymce.rb
CHANGED
@@ -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
|
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
|
data/lib/alchemy/version.rb
CHANGED
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"
|