alchemy_cms 6.0.0.pre.rc6 → 6.0.0.pre.rc7

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.

Potentially problematic release.


This version of alchemy_cms might be problematic. Click here for more details.

Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +8 -8
  3. data/.github/workflows/stale.yml +21 -7
  4. data/.gitignore +0 -1
  5. data/.rspec +1 -0
  6. data/CHANGELOG.md +69 -0
  7. data/Gemfile +7 -6
  8. data/Rakefile +5 -1
  9. data/alchemy_cms.gemspec +2 -2
  10. data/app/assets/javascripts/alchemy/admin.js +0 -1
  11. data/app/assets/javascripts/alchemy/page_select.js +13 -8
  12. data/app/assets/javascripts/alchemy/templates/index.js +1 -0
  13. data/app/assets/javascripts/alchemy/templates/page.hbs +17 -7
  14. data/app/assets/javascripts/alchemy/templates/page_folder.hbs +3 -0
  15. data/app/assets/stylesheets/alchemy/archive.scss +4 -0
  16. data/app/assets/stylesheets/alchemy/page-select.scss +29 -4
  17. data/app/assets/stylesheets/alchemy/sitemap.scss +2 -6
  18. data/app/controllers/alchemy/admin/pages_controller.rb +9 -12
  19. data/app/controllers/alchemy/api/pages_controller.rb +14 -4
  20. data/app/models/alchemy/ingredient.rb +6 -1
  21. data/app/serializers/alchemy/page_serializer.rb +7 -1
  22. data/app/serializers/alchemy/page_tree_serializer.rb +3 -3
  23. data/app/views/alchemy/admin/pages/_form.html.erb +19 -0
  24. data/app/views/alchemy/admin/pages/_new_page_form.html.erb +16 -5
  25. data/app/views/alchemy/admin/pages/_page.html.erb +111 -133
  26. data/app/views/alchemy/admin/pages/_sitemap.html.erb +2 -8
  27. data/app/views/alchemy/admin/pages/_toolbar.html.erb +0 -12
  28. data/app/views/alchemy/admin/pages/index.html.erb +1 -1
  29. data/app/views/alchemy/admin/pages/update.js.erb +7 -0
  30. data/app/views/alchemy/admin/partials/_routes.html.erb +8 -1
  31. data/app/views/alchemy/essences/_essence_page_editor.html.erb +1 -1
  32. data/config/locales/alchemy.en.yml +0 -3
  33. data/config/routes.rb +4 -2
  34. data/lib/alchemy/permissions.rb +0 -1
  35. data/lib/alchemy/test_support/shared_ingredient_examples.rb +4 -2
  36. data/lib/alchemy/version.rb +1 -1
  37. data/lib/generators/alchemy/install/install_generator.rb +6 -1
  38. data/package/src/image_loader.js +4 -2
  39. data/package/src/node_tree.js +13 -6
  40. data/package/src/page_publication_fields.js +15 -14
  41. data/package/src/page_sorter.js +62 -0
  42. data/package/src/picture_editors.js +4 -4
  43. data/package/src/sitemap.js +51 -36
  44. data/package/src/utils/__tests__/ajax.spec.js +52 -16
  45. data/package/src/utils/ajax.js +12 -0
  46. data/package.json +1 -1
  47. metadata +21 -22
  48. data/app/assets/javascripts/alchemy/alchemy.page_sorter.js +0 -24
  49. data/app/views/alchemy/admin/pages/fold.js.erb +0 -2
  50. data/app/views/alchemy/admin/pages/sort.html.erb +0 -19
  51. data/vendor/assets/javascripts/jquery_plugins/jquery.ui.nestedSortable.js +0 -434
@@ -1,24 +1,7 @@
1
- <li id="page_{{id}}" class="page_level_{{level}} {{page_layout}}" data-slug="{{slug}}" data-restricted="{{restricted}}">
1
+ <li id="page_{{id}}" class="sitemap-item {{page_layout}}" data-slug="{{slug}}" data-restricted="{{restricted}}" data-page-id="{{id}}" data-folded="{{folded}}">
2
2
  <div class="sitemap_page{{#if locked}} locked{{/if}}" name="{{name}}">
3
- <div class="sitemap_left_images<% if @sorting %>{{#unless root}} handle{{/unless}}<% end %>">
4
- <% unless @sorting %>
5
- {{#unless root_or_leaf}}
6
- <%= link_to(
7
- alchemy.fold_admin_page_path(page),
8
- remote: true,
9
- method: :post,
10
- class: "page_folder",
11
- title: "{{#if folded}}#{Alchemy.t('Show childpages')}{{else}}#{Alchemy.t('Hide childpages')}{{/if}}",
12
- id: "fold_button_{{id}}"
13
- ) do %>
14
- {{#if folded}}
15
- <i class="far fa-plus-square fa-fw"></i>
16
- {{else}}
17
- <i class="far fa-minus-square fa-fw"></i>
18
- {{/if}}
19
- <% end %>
20
- {{/unless}}
21
- <% end %>
3
+ <div class="sitemap_left_images">
4
+ <span class="page_folder"></span>
22
5
  {{#if definition_missing}}
23
6
  <%= page_layout_missing_warning %>
24
7
  {{else}}
@@ -31,121 +14,121 @@
31
14
  </span>
32
15
  </span>
33
16
  {{else}}
17
+ <span class="{{#unless root}}handle{{/unless}}">
34
18
  <i class="icon far fa-file fa-lg"></i>
19
+ </span>
35
20
  {{/if}}
36
21
  {{else}}
37
22
  <span class="with-hint">
38
23
  <i class="icon fas fa-ban fa-fw"></i>
39
24
  <span class="hint-bubble">
40
- <%= Alchemy.t('Your user role does not allow you to edit this page') %>
25
+ <%= Alchemy.t("Your user role does not allow you to edit this page") %>
41
26
  </span>
42
27
  </span>
43
28
  {{/if}}
44
29
  {{/if}}
45
30
  </div>
46
31
  <div class="sitemap_right_tools">
47
- <%- unless @sorting -%>
48
- {{#if permissions.info}}
49
- <div class="button_with_label sitemap_tool">
50
- <%= link_to_dialog(
51
- render_icon('info-circle'),
52
- alchemy.info_admin_page_path(page),
53
- {
54
- title: Alchemy.t(:page_infos),
55
- size: '520x290'
56
- }
57
- ) %>
58
- <label class="center"><%= Alchemy.t(:page_infos) %></label>
59
- {{else}}
60
- <div class="sitemap_tool disabled with-hint">
61
- <%= render_icon('info-circle') %>
62
- <span class="hint-bubble">
63
- <%= Alchemy.t('Your user role does not allow you to edit this page') %>
64
- </span>
65
- {{/if}}
66
- </div>
67
- {{#if permissions.configure}}
68
- <div class="button_with_label sitemap_tool">
69
- <%= link_to_dialog(
70
- render_icon(:cog),
71
- alchemy.configure_admin_page_path(page),
72
- {
73
- title: Alchemy.t(:edit_page_properties),
74
- size: '450x680'
75
- }
76
- ) -%>
77
- <label class="center"><%= Alchemy.t(:edit_page_properties) %></label>
78
- {{else}}
79
- <div class="sitemap_tool disabled with-hint">
80
- <%= render_icon(:cog) %>
81
- <span class="hint-bubble">
82
- <%= Alchemy.t('Your user role does not allow you to edit this page') %>
83
- </span>
84
- {{/if}}
85
- </div>
86
- {{#if permissions.copy}}
87
- <div class="button_with_label sitemap_tool">
88
- <%= link_to(
89
- render_icon(:copy),
90
- alchemy.insert_admin_clipboard_path(
91
- remarkable_type: page.class.name.demodulize.underscore.pluralize,
92
- remarkable_id: '__ID__',
93
- ).gsub('__ID__', '{{id}}'),
94
- remote: true,
95
- method: 'post'
96
- ) %>
97
- <label class="center"><%= Alchemy.t(:copy_page) %></label>
98
- {{else}}
99
- <div class="sitemap_tool disabled with-hint">
100
- <%= render_icon(:copy) %>
101
- <span class="hint-bubble">
102
- <%= Alchemy.t('Your user role does not allow you to edit this page') %>
103
- </span>
104
- {{/if}}
105
- </div>
106
- {{#if permissions.destroy}}
107
- <div class="button_with_label sitemap_tool">
108
- <%= link_to_confirm_dialog(
109
- render_icon(:minus),
110
- Alchemy.t(:confirm_to_delete_page),
111
- url_for(
112
- controller: 'pages',
113
- action: 'destroy',
114
- id: '__ID__'
115
- ).gsub('__ID__', '{{id}}')
116
- ) -%>
117
- <label class="center"><%= Alchemy.t(:delete_page) %></label>
118
- {{else}}
119
- <div class="sitemap_tool disabled with-hint">
120
- <%= render_icon(:minus) %>
121
- <span class="hint-bubble">
122
- <%= Alchemy.t('Your user role does not allow you to edit this page') %>
123
- </span>
124
- {{/if}}
125
- </div>
126
- {{#if permissions.create}}
127
- <div class="button_with_label sitemap_tool">
128
- <%= link_to_dialog(
129
- render_icon(:plus),
130
- alchemy.new_admin_page_path(parent_id: '__ID__').gsub('__ID__', '{{id}}'),
131
- {
132
- title: Alchemy.t(:create_page),
133
- size: '340x165',
134
- overflow: true
135
- }
136
- ) -%>
137
- <label class="left"><%= Alchemy.t(:create_page) %></label>
138
- {{else}}
139
- <div class="sitemap_tool disabled with-hint">
140
- <%= render_icon(:plus) %>
141
- <span class="hint-bubble">
142
- <%= Alchemy.t('Your user role does not allow you to edit this page') %>
143
- </span>
144
- {{/if}}
145
- </div>
146
- <%- end -%>
32
+ {{#if permissions.info}}
33
+ <div class="button_with_label sitemap_tool">
34
+ <%= link_to_dialog(
35
+ render_icon("info-circle"),
36
+ alchemy.info_admin_page_path(id: "__ID__"),
37
+ {
38
+ title: Alchemy.t(:page_infos),
39
+ size: "520x290"
40
+ }
41
+ ) %>
42
+ <label class="center"><%= Alchemy.t(:page_infos) %></label>
43
+ {{else}}
44
+ <div class="sitemap_tool disabled with-hint">
45
+ <%= render_icon("info-circle") %>
46
+ <span class="hint-bubble">
47
+ <%= Alchemy.t("Your user role does not allow you to edit this page") %>
48
+ </span>
49
+ {{/if}}
50
+ </div>
51
+ {{#if permissions.configure}}
52
+ <div class="button_with_label sitemap_tool">
53
+ <%= link_to_dialog(
54
+ render_icon(:cog),
55
+ alchemy.configure_admin_page_path(id: "__ID__"),
56
+ {
57
+ title: Alchemy.t(:edit_page_properties),
58
+ size: "450x680"
59
+ }
60
+ ) -%>
61
+ <label class="center"><%= Alchemy.t(:edit_page_properties) %></label>
62
+ {{else}}
63
+ <div class="sitemap_tool disabled with-hint">
64
+ <%= render_icon(:cog) %>
65
+ <span class="hint-bubble">
66
+ <%= Alchemy.t("Your user role does not allow you to edit this page") %>
67
+ </span>
68
+ {{/if}}
69
+ </div>
70
+ {{#if permissions.copy}}
71
+ <div class="button_with_label sitemap_tool">
72
+ <%= link_to(
73
+ render_icon(:copy),
74
+ alchemy.insert_admin_clipboard_path(
75
+ remarkable_type: :pages,
76
+ remarkable_id: "__ID__",
77
+ ),
78
+ remote: true,
79
+ method: :post
80
+ ) %>
81
+ <label class="center"><%= Alchemy.t(:copy_page) %></label>
82
+ {{else}}
83
+ <div class="sitemap_tool disabled with-hint">
84
+ <%= render_icon(:copy) %>
85
+ <span class="hint-bubble">
86
+ <%= Alchemy.t("Your user role does not allow you to edit this page") %>
87
+ </span>
88
+ {{/if}}
89
+ </div>
90
+ {{#if permissions.destroy}}
91
+ <div class="button_with_label sitemap_tool">
92
+ <%= link_to_confirm_dialog(
93
+ render_icon(:minus),
94
+ Alchemy.t(:confirm_to_delete_page),
95
+ url_for(
96
+ controller: "pages",
97
+ action: "destroy",
98
+ id: "__ID__"
99
+ )
100
+ ) -%>
101
+ <label class="center"><%= Alchemy.t(:delete_page) %></label>
102
+ {{else}}
103
+ <div class="sitemap_tool disabled with-hint">
104
+ <%= render_icon(:minus) %>
105
+ <span class="hint-bubble">
106
+ <%= Alchemy.t("Your user role does not allow you to edit this page") %>
107
+ </span>
108
+ {{/if}}
109
+ </div>
110
+ {{#if permissions.create}}
111
+ <div class="button_with_label sitemap_tool">
112
+ <%= link_to_dialog(
113
+ render_icon(:plus),
114
+ alchemy.new_admin_page_path(parent_id: "__ID__"),
115
+ {
116
+ title: Alchemy.t(:create_page),
117
+ size: "340x165",
118
+ overflow: true
119
+ }
120
+ ) -%>
121
+ <label class="left"><%= Alchemy.t(:create_page) %></label>
122
+ {{else}}
123
+ <div class="sitemap_tool disabled with-hint">
124
+ <%= render_icon(:plus) %>
125
+ <span class="hint-bubble">
126
+ <%= Alchemy.t("Your user role does not allow you to edit this page") %>
127
+ </span>
128
+ {{/if}}
129
+ </div>
147
130
  </div>
148
- <div class="page_infos" id="page_<%= page.id %>_infos">
131
+ <div class="page_infos">
149
132
  <span class="page_status with-hint">
150
133
  <i class="icon fas fa-fw fa-compass {{#unless public}}disabled{{/unless}}" data-fa-transform="shrink-2"></i>
151
134
  <span class="hint-bubble">{{status_titles.public}}</span>
@@ -160,23 +143,18 @@
160
143
  </div>
161
144
  <div class="sitemap_sitename">
162
145
  {{#if permissions.edit_content}}
163
- <%= link_to_unless(
164
- @sorting,
165
- '{{name}}',
166
- alchemy.edit_admin_page_path(page),
146
+ <%= link_to(
147
+ "{{name}}",
148
+ alchemy.edit_admin_page_path(id: "__ID__"),
167
149
  title: Alchemy.t(:edit_page),
168
150
  class: "sitemap_pagename_link"
169
- ) { content_tag('span', '{{name}}', class: "sitemap_pagename_link") } -%>
151
+ ) -%>
170
152
  {{else}}
171
- <%= content_tag('span', '{{name}}', class: "sitemap_pagename_link") %>
153
+ <%= content_tag("span", "{{name}}", class: "sitemap_pagename_link") %>
172
154
  {{/if}}
173
155
  </div>
174
156
  </div>
175
- {{#if children}}
176
- <% unless @sorting %>{{#unless folded}}<% end %>
177
- <ul id="page_{{id}}_children" class="level_{{level}}_children">
157
+ <ul id="page_{{id}}_children" class="children" data-parent-id="{{id}}">
178
158
  {{> list}}
179
159
  </ul>
180
- <% unless @sorting %>{{/unless}}<% end %>
181
- {{/if}}
182
160
  </li>
@@ -8,7 +8,7 @@
8
8
  </div>
9
9
 
10
10
  <script id="sitemap-template" type="text/x-handlebars-template">
11
- <ul id="sitemap" class="list<%= @sorting ? ' sorting' : nil %>">
11
+ <ul id="sitemap" class="list">
12
12
  {{> list}}
13
13
  </ul>
14
14
  </script>
@@ -23,13 +23,7 @@
23
23
  $(function() {
24
24
  Alchemy.currentSitemap = new Alchemy.Sitemap({
25
25
  url: '<%= alchemy.tree_admin_pages_path %>',
26
- page_root_id: <%= @page_root.id %>,
27
- full: <%= full %>
28
- <% if @sorting %>
29
- ,ready: function () {
30
- Alchemy.PageSorter();
31
- }
32
- <% end %>
26
+ page_root_id: <%= @page_root.id %>
33
27
  });
34
28
  Alchemy.PagePublicationFields();
35
29
  });
@@ -28,18 +28,6 @@
28
28
  <label><%= Alchemy.t("Flush page cache") %></label>
29
29
  </div>
30
30
  <% end %>
31
- <% if can?(:sort, Alchemy::Page) %>
32
- <div class="button_with_label">
33
- <%= link_to(
34
- render_icon(:random),
35
- alchemy.sort_admin_pages_path,
36
- method: :get,
37
- class: "icon_button",
38
- title: Alchemy.t("Sort pages")
39
- ) %>
40
- <label><%= Alchemy.t("Sort pages") %></label>
41
- </div>
42
- <% end %>
43
31
  <div class="button_with_label" id="clipboard_button">
44
32
  <%= link_to_dialog(
45
33
  render_icon(clipboard_empty?("pages") ? :clipboard : :paste),
@@ -30,7 +30,7 @@
30
30
  <% else %>
31
31
  <% if @page_root %>
32
32
  <h2 id="page_filter_result"></h2>
33
- <%= render "sitemap", page_partial: "page", full: !!@sorting %>
33
+ <%= render "sitemap", page_partial: "page" %>
34
34
  <% elsif can?(:create, Alchemy::Page) %>
35
35
  <%= render partial: "create_language_form" %>
36
36
  <% else %>
@@ -8,6 +8,13 @@
8
8
  Alchemy.growl("<%= j @notice %>");
9
9
  Alchemy.closeCurrentDialog();
10
10
 
11
+ <% elsif @page.parent_id != @old_parent_id -%>
12
+
13
+ Alchemy.closeCurrentDialog(function() {
14
+ Alchemy.growl("<%= j @notice %>");
15
+ Alchemy.currentSitemap.load(<%= @page.get_language_root.id %>);
16
+ });
17
+
11
18
  <% else -%>
12
19
 
13
20
  if (page) {
@@ -19,8 +19,15 @@
19
19
  },
20
20
  },
21
21
 
22
+ move_admin_page_path: function(id) {
23
+ return '<%= alchemy.move_api_page_path(id: 1) %>'.replace(/1/, id);
24
+ },
25
+
26
+ fold_admin_page_path: function(id) {
27
+ return '<%= alchemy.fold_admin_page_path(id: 1) %>'.replace(/1/, id);
28
+ },
29
+
22
30
  order_admin_elements_path: '<%= alchemy.order_admin_elements_path %>',
23
- order_admin_pages_path: '<%= alchemy.order_admin_pages_path %>',
24
31
  link_admin_pages_path: '<%= alchemy.link_admin_pages_path %>',
25
32
  api_pages_path: '<%= alchemy.api_pages_path %>',
26
33
  api_elements_path: '<%= alchemy.api_elements_path %>'
@@ -14,7 +14,7 @@
14
14
  <script>
15
15
  $('#<%= essence_page_editor.form_field_id %>').alchemyPageSelect({
16
16
  placeholder: "<%= Alchemy.t(:search_page) %>",
17
- url: "<%= alchemy.api_pages_path %>",
17
+ url: "<%= alchemy.api_pages_path language_id: essence_page_editor.page&.language_id %>",
18
18
  query_params: <%== essence_page_editor.settings[:query_params].to_json %>,
19
19
  <% if essence_page_editor.essence.page %>
20
20
  initialSelection: {
@@ -334,7 +334,6 @@ en:
334
334
  "Site successfully removed": "Website successfully removed."
335
335
  "Site successfully updated": "Website successfully updated."
336
336
  "Size": "Size"
337
- "Sort pages": "Reorder pages"
338
337
  "Successfully added content": "Successfully added %{content}"
339
338
  "Successfully deleted content": "Successfully deleted %{content}"
340
339
  "Successfully deleted element": "Successfully deleted %{element}"
@@ -437,7 +436,6 @@ en:
437
436
  enter_external_link: "Please enter the URL you want to link with"
438
437
  explain_cropping: "<p>Move the frame and change its size with the mouse or arrow keys to adjust the image mask. Click on \"apply\" when you are satisfied with your selection.</p><p>If you want to return to the original centered image mask like it was defined in the layout, click \"reset\" and \"apply\" afterwards.</p>"
439
438
  explain_publishing: "Publish current page content"
440
- explain_sitemap_dragndrop_sorting: "Tip: Drag the pages at the icon in order to sort them."
441
439
  explain_unlocking: "Leave page and unlock it for other users."
442
440
  external_link_notice_1: "Please enter the complete url with http:// or a similar protocol."
443
441
  external_link_notice_2: "To refer a path from your website url, start with a /."
@@ -592,7 +590,6 @@ en:
592
590
  robot_follow: "robot may follow links."
593
591
  robot_index: "allow robot to index."
594
592
  save: "Save"
595
- "save order": "Save order"
596
593
  saved_link: "Link saved."
597
594
  search: "search"
598
595
  search_engines: "Search engines"
data/config/routes.rb CHANGED
@@ -28,13 +28,12 @@ Alchemy::Engine.routes.draw do
28
28
  post :copy_language_tree
29
29
  get :create_language
30
30
  get :link
31
- get :sort
32
31
  get :tree
33
32
  end
34
33
  member do
35
34
  post :unlock
36
35
  post :publish
37
- post :fold
36
+ patch :fold
38
37
  get :configure
39
38
  get :preview
40
39
  get :info
@@ -139,6 +138,9 @@ Alchemy::Engine.routes.draw do
139
138
  collection do
140
139
  get :nested
141
140
  end
141
+ member do
142
+ patch :move
143
+ end
142
144
  end
143
145
 
144
146
  get "/pages/*urlname(.:format)" => "pages#show", as: "page"
@@ -147,7 +147,6 @@ module Alchemy
147
147
  :copy_language_tree,
148
148
  :flush,
149
149
  :order,
150
- :sort,
151
150
  :switch_language,
152
151
  ], Alchemy::Page
153
152
 
@@ -28,7 +28,7 @@ RSpec.shared_examples_for "an alchemy ingredient" do
28
28
 
29
29
  context "with element" do
30
30
  before do
31
- expect(element).to receive(:ingredient_definition_for) do
31
+ expect(element).to receive(:ingredient_definition_for).at_least(:once) do
32
32
  {
33
33
  settings: {
34
34
  linkable: true,
@@ -63,7 +63,9 @@ RSpec.shared_examples_for "an alchemy ingredient" do
63
63
  end
64
64
 
65
65
  before do
66
- expect(element).to receive(:ingredient_definition_for) { definition }
66
+ expect(element).to receive(:ingredient_definition_for).at_least(:once) do
67
+ definition
68
+ end
67
69
  end
68
70
 
69
71
  it "returns ingredient definition" do
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Alchemy
4
- VERSION = "6.0.0-rc6"
4
+ VERSION = "6.0.0-rc7"
5
5
 
6
6
  def self.version
7
7
  VERSION
@@ -23,6 +23,11 @@ module Alchemy
23
23
  default: false,
24
24
  desc: "Skip running the webpacker installer."
25
25
 
26
+ class_option :skip_db_create,
27
+ type: :boolean,
28
+ default: false,
29
+ desc: "Skip creting the database during install."
30
+
26
31
  source_root File.expand_path("files", __dir__)
27
32
 
28
33
  def setup
@@ -104,7 +109,7 @@ module Alchemy
104
109
  end
105
110
 
106
111
  def setup_database
107
- rake("db:create", abort_on_failure: true)
112
+ rake("db:create", abort_on_failure: true) unless options[:skip_db_create]
108
113
  # We can't invoke this rake task, because Rails will use wrong engine names otherwise
109
114
  rake("railties:install:migrations", abort_on_failure: true)
110
115
  rake("db:migrate", abort_on_failure: true)
@@ -39,9 +39,11 @@ export default class ImageLoader {
39
39
  this.unbind()
40
40
  }
41
41
 
42
- onError() {
42
+ onError(evt) {
43
+ const message = `Could not load ${this.image.src}`
43
44
  this.removeSpinner()
44
- this.parent.innerHtml = '<span class="icon warn"></span>'
45
+ this.parent.innerHTML = `<span class="icon fas fa-exclamation-triangle" title="${message}" />`
46
+ console.error(message, evt)
45
47
  this.unbind()
46
48
  }
47
49
 
@@ -1,12 +1,16 @@
1
1
  import Sortable from "sortablejs"
2
- import ajax from "./utils/ajax"
2
+ import { patch } from "./utils/ajax"
3
3
  import { on } from "./utils/events"
4
4
 
5
5
  function displayNodeFolders() {
6
6
  document.querySelectorAll("li.menu-item").forEach((el) => {
7
7
  const leftIconArea = el.querySelector(".nodes_tree-left_images")
8
8
  const list = el.querySelector(".children")
9
- const node = { folded: el.dataset.folded === "true", id: el.dataset.id, type: el.dataset.type }
9
+ const node = {
10
+ folded: el.dataset.folded === "true",
11
+ id: el.dataset.id,
12
+ type: el.dataset.type
13
+ }
10
14
 
11
15
  if (list.children.length > 0 || node.folded) {
12
16
  leftIconArea.innerHTML = HandlebarsTemplates.node_folder({ node: node })
@@ -17,13 +21,15 @@ function displayNodeFolders() {
17
21
  }
18
22
 
19
23
  function onFinishDragging(evt) {
20
- const url = Alchemy.routes[evt.item.dataset.type].move_api_path(evt.item.dataset.id)
24
+ const url = Alchemy.routes[evt.item.dataset.type].move_api_path(
25
+ evt.item.dataset.id
26
+ )
21
27
  const data = {
22
28
  target_parent_id: evt.to.dataset.recordId,
23
29
  new_position: evt.newIndex
24
30
  }
25
31
 
26
- ajax("PATCH", url, data)
32
+ patch(url, data)
27
33
  .then(() => {
28
34
  const message = Alchemy.t("Successfully moved menu item")
29
35
  Alchemy.growl(message)
@@ -38,10 +44,11 @@ function handleNodeFolders() {
38
44
  on("click", ".nodes_tree", ".node_folder", function () {
39
45
  const nodeId = this.dataset.recordId
40
46
  const menu_item = this.closest("li.menu-item")
41
- const url = Alchemy.routes[this.dataset.recordType].toggle_folded_api_path(nodeId)
47
+ const url =
48
+ Alchemy.routes[this.dataset.recordType].toggle_folded_api_path(nodeId)
42
49
  const list = menu_item.querySelector(".children")
43
50
 
44
- ajax("PATCH", url)
51
+ patch(url)
45
52
  .then(() => {
46
53
  list.classList.toggle("folded")
47
54
  menu_item.dataset.folded =
@@ -7,21 +7,22 @@ export default function () {
7
7
  const publication_date_fields = dialog.querySelector(
8
8
  ".page-publication-date-fields"
9
9
  )
10
+ const public_field = dialog.querySelector("#page_public")
10
11
 
11
- dialog
12
- .querySelector("#page_public")
13
- .addEventListener("click", function (evt) {
14
- const checkbox = evt.target
15
- const now = new Date()
12
+ if(!public_field) return
16
13
 
17
- if (checkbox.checked) {
18
- publication_date_fields.classList.remove("hidden")
19
- public_on_field._flatpickr.setDate(now)
20
- } else {
21
- publication_date_fields.classList.add("hidden")
22
- public_on_field.value = ""
23
- }
24
- public_until_field.value = ""
25
- })
14
+ public_field.addEventListener("click", function (evt) {
15
+ const checkbox = evt.target
16
+ const now = new Date()
17
+
18
+ if (checkbox.checked) {
19
+ publication_date_fields.classList.remove("hidden")
20
+ public_on_field._flatpickr.setDate(now)
21
+ } else {
22
+ publication_date_fields.classList.add("hidden")
23
+ public_on_field.value = ""
24
+ }
25
+ public_until_field.value = ""
26
+ })
26
27
  })
27
28
  }
@@ -0,0 +1,62 @@
1
+ import Sortable from "sortablejs"
2
+ import { patch } from "./utils/ajax"
3
+
4
+ function onFinishDragging(evt) {
5
+ const pageId = evt.item.dataset.pageId
6
+ const url = Alchemy.routes.move_admin_page_path(pageId)
7
+ const data = {
8
+ target_parent_id: evt.to.dataset.parentId,
9
+ new_position: evt.newIndex
10
+ }
11
+
12
+ patch(url, data)
13
+ .then(async (response) => {
14
+ const pageData = await response.data
15
+ const pageEl = document.getElementById(`page_${pageId}`)
16
+ const urlPathEl = pageEl.querySelector(".sitemap_url")
17
+
18
+ Alchemy.growl(Alchemy.t("Successfully moved page"))
19
+ urlPathEl.textContent = pageData.url_path
20
+ displayPageFolders()
21
+ })
22
+ .catch((error) => {
23
+ Alchemy.growl(error.message || error, "error")
24
+ })
25
+ }
26
+
27
+ export function displayPageFolders() {
28
+ document.querySelectorAll("li.sitemap-item").forEach((el) => {
29
+ const pageFolderEl = el.querySelector(".page_folder")
30
+ const list = el.querySelector(".children")
31
+ const page = {
32
+ folded: el.dataset.folded === "true",
33
+ id: el.dataset.pageId,
34
+ type: el.dataset.type
35
+ }
36
+
37
+ if (list.children.length > 0 || page.folded) {
38
+ pageFolderEl.outerHTML = HandlebarsTemplates.page_folder({ page })
39
+ } else {
40
+ pageFolderEl.innerHTML = ""
41
+ }
42
+ })
43
+ }
44
+
45
+ export function createSortables(sortables) {
46
+ sortables.forEach((el) => {
47
+ new Sortable(el, {
48
+ group: "pages",
49
+ animation: 150,
50
+ fallbackOnBody: true,
51
+ swapThreshold: 0.65,
52
+ handle: ".handle",
53
+ onEnd: onFinishDragging
54
+ })
55
+ })
56
+ }
57
+
58
+ export default function () {
59
+ const sortables = document.querySelectorAll("ul.children")
60
+ displayPageFolders()
61
+ createSortables(sortables)
62
+ }