alchemy_cms 5.3.0 → 5.3.1

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 (30) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +14 -0
  3. data/app/assets/javascripts/alchemy/admin.js +0 -1
  4. data/app/assets/javascripts/alchemy/templates/index.js +1 -0
  5. data/app/assets/javascripts/alchemy/templates/page.hbs +17 -7
  6. data/app/assets/javascripts/alchemy/templates/page_folder.hbs +3 -0
  7. data/app/assets/stylesheets/alchemy/page-select.scss +29 -4
  8. data/app/assets/stylesheets/alchemy/sitemap.scss +2 -6
  9. data/app/controllers/alchemy/admin/pages_controller.rb +8 -12
  10. data/app/controllers/alchemy/api/pages_controller.rb +14 -4
  11. data/app/serializers/alchemy/page_serializer.rb +7 -1
  12. data/app/serializers/alchemy/page_tree_serializer.rb +3 -3
  13. data/app/views/alchemy/admin/pages/_page.html.erb +111 -133
  14. data/app/views/alchemy/admin/pages/_sitemap.html.erb +2 -8
  15. data/app/views/alchemy/admin/pages/_toolbar.html.erb +0 -12
  16. data/app/views/alchemy/admin/pages/index.html.erb +1 -1
  17. data/app/views/alchemy/admin/partials/_routes.html.erb +8 -1
  18. data/app/views/alchemy/essences/_essence_page_editor.html.erb +1 -1
  19. data/config/locales/alchemy.en.yml +0 -3
  20. data/config/routes.rb +4 -2
  21. data/lib/alchemy/permissions.rb +0 -1
  22. data/lib/alchemy/version.rb +1 -1
  23. data/package/src/page_sorter.js +68 -0
  24. data/package/src/sitemap.js +55 -36
  25. data/package.json +1 -1
  26. metadata +4 -6
  27. data/app/assets/javascripts/alchemy/alchemy.page_sorter.js +0 -24
  28. data/app/views/alchemy/admin/pages/fold.js.erb +0 -2
  29. data/app/views/alchemy/admin/pages/sort.html.erb +0 -19
  30. data/vendor/assets/javascripts/jquery_plugins/jquery.ui.nestedSortable.js +0 -434
@@ -292,7 +292,6 @@ en:
292
292
  "Site successfully removed": "Website successfully removed."
293
293
  "Site successfully updated": "Website successfully updated."
294
294
  "Size": "Size"
295
- "Sort pages": "Reorder pages"
296
295
  "Successfully added content": "Successfully added %{content}"
297
296
  "Successfully deleted content": "Successfully deleted %{content}"
298
297
  "Tags": "Tags"
@@ -394,7 +393,6 @@ en:
394
393
  enter_external_link: "Please enter the URL you want to link with"
395
394
  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>"
396
395
  explain_publishing: "Publish the page and remove the cached version from the server."
397
- explain_sitemap_dragndrop_sorting: "Tip: Drag the pages at the icon in order to sort them."
398
396
  explain_unlocking: "Leave page and unlock it for other users."
399
397
  external_link_notice_1: "Please enter the complete url with http:// or a similar protocol."
400
398
  external_link_notice_2: "To refer a path from your website url, start with a /."
@@ -553,7 +551,6 @@ en:
553
551
  robot_follow: "robot may follow links."
554
552
  robot_index: "allow robot to index."
555
553
  save: "Save"
556
- "save order": "Save order"
557
554
  saved_link: "Link saved."
558
555
  search: "search"
559
556
  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
  post :visit
39
38
  get :configure
40
39
  get :preview
@@ -145,6 +144,9 @@ Alchemy::Engine.routes.draw do
145
144
  collection do
146
145
  get :nested
147
146
  end
147
+ member do
148
+ patch :move
149
+ end
148
150
  end
149
151
 
150
152
  get "/pages/*urlname(.:format)" => "pages#show", as: "page"
@@ -149,7 +149,6 @@ module Alchemy
149
149
  :copy_language_tree,
150
150
  :flush,
151
151
  :order,
152
- :sort,
153
152
  :switch_language,
154
153
  ], Alchemy::Page
155
154
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Alchemy
4
- VERSION = "5.3.0"
4
+ VERSION = "5.3.1"
5
5
 
6
6
  def self.version
7
7
  VERSION
@@ -0,0 +1,68 @@
1
+ import Sortable from "sortablejs"
2
+
3
+ function onFinishDragging(evt) {
4
+ const pageId = evt.item.dataset.pageId
5
+ const url = Alchemy.routes.move_admin_page_path(pageId)
6
+ const data = {
7
+ target_parent_id: evt.to.dataset.parentId,
8
+ new_position: evt.newIndex
9
+ }
10
+
11
+ fetch(url, {
12
+ method: "PATCH",
13
+ headers: {
14
+ "Content-Type": "application/json",
15
+ Accept: "application/json"
16
+ },
17
+ body: JSON.stringify(data)
18
+ })
19
+ .then(async (response) => {
20
+ const pageData = await response.json()
21
+ const pageEl = document.getElementById(`page_${pageId}`)
22
+ const urlPathEl = pageEl.querySelector(".sitemap_url")
23
+
24
+ Alchemy.growl(Alchemy.t("Successfully moved page"))
25
+ urlPathEl.textContent = pageData.url_path
26
+ displayPageFolders()
27
+ })
28
+ .catch((error) => {
29
+ Alchemy.growl(error.message || error, "error")
30
+ })
31
+ }
32
+
33
+ export function displayPageFolders() {
34
+ document.querySelectorAll("li.sitemap-item").forEach((el) => {
35
+ const pageFolderEl = el.querySelector(".page_folder")
36
+ const list = el.querySelector(".children")
37
+ const page = {
38
+ folded: el.dataset.folded === "true",
39
+ id: el.dataset.pageId,
40
+ type: el.dataset.type
41
+ }
42
+
43
+ if (list.children.length > 0 || page.folded) {
44
+ pageFolderEl.outerHTML = HandlebarsTemplates.page_folder({ page })
45
+ } else {
46
+ pageFolderEl.innerHTML = ""
47
+ }
48
+ })
49
+ }
50
+
51
+ export function createSortables(sortables) {
52
+ sortables.forEach((el) => {
53
+ new Sortable(el, {
54
+ group: "pages",
55
+ animation: 150,
56
+ fallbackOnBody: true,
57
+ swapThreshold: 0.65,
58
+ handle: ".handle",
59
+ onEnd: onFinishDragging
60
+ })
61
+ })
62
+ }
63
+
64
+ export default function () {
65
+ const sortables = document.querySelectorAll("ul.children")
66
+ displayPageFolders()
67
+ createSortables(sortables)
68
+ }
@@ -1,12 +1,14 @@
1
1
  // The admin sitemap Alchemy class
2
+ import PageSorter from "./page_sorter"
3
+ import { on } from "./utils/events"
4
+ import { createSortables, displayPageFolders } from "./page_sorter"
2
5
 
3
6
  export default class Sitemap {
4
7
  // Storing some objects.
5
8
  constructor(options) {
6
- const list_template_regexp = new RegExp("/" + options.page_root_id, "g")
7
9
  const list_template_html = document
8
10
  .getElementById("sitemap-list")
9
- .innerHTML.replace(list_template_regexp, "/{{id}}")
11
+ .innerHTML.replace(/__ID__/g, "{{id}}")
10
12
  this.search_field = document.querySelector(".search_input_field")
11
13
  this.filter_field_clear = document.querySelector(".search_field_clear")
12
14
  this.filter_field_clear.removeAttribute("href")
@@ -24,56 +26,68 @@ export default class Sitemap {
24
26
 
25
27
  // Loads the sitemap
26
28
  load(pageId) {
27
- const spinner = this.options.spinner || new Alchemy.Spinner("medium")
29
+ const spinner = new Alchemy.Spinner("medium")
28
30
  const spinTarget = this.sitemap_wrapper
29
31
  spinTarget.innerHTML = ""
30
32
  spinner.spin(spinTarget)
31
- this.fetch(
32
- `${this.options.url}?id=${pageId}&full=${this.options.full}`
33
- ).then(async (response) => {
34
- this.render(await response.json())
35
- spinner.stop()
36
- })
33
+ fetch(`${this.options.url}?id=${pageId}`)
34
+ .then(async (response) => {
35
+ this.render(await response.json())
36
+ this.handlePageFolders()
37
+ spinner.stop()
38
+ })
39
+ .catch(this.errorHandler)
37
40
  }
38
41
 
39
- // Reload the sitemap for a specific branch
40
- reload(pageId) {
41
- const spinner = new Alchemy.Spinner("small")
42
- const spinTarget = document.getElementById(`fold_button_${pageId}`)
43
- spinTarget.querySelector(".far").remove()
44
- spinner.spin(spinTarget)
45
- this.fetch(`${this.options.url}?id=${pageId}`).then(async (response) => {
46
- this.render(await response.json(), pageId)
47
- spinner.stop()
48
- })
49
- }
42
+ // Watch page folder clicks and re-render the page branch
43
+ handlePageFolders() {
44
+ on(
45
+ "click",
46
+ "#sitemap",
47
+ ".page_folder",
48
+ function (evt) {
49
+ const spinner = new Alchemy.Spinner("small")
50
+ const pageFolder = evt.target.closest(".page_folder")
51
+ const pageId = pageFolder.dataset.pageId
52
+ pageFolder.innerHTML = ""
53
+ spinner.spin(pageFolder)
50
54
 
51
- fetch(url) {
52
- return fetch(url).catch((error) => console.warn(`Request failed: ${error}`))
55
+ fetch(Alchemy.routes.fold_admin_page_path(pageId), {
56
+ method: "PATCH",
57
+ headers: {
58
+ Accept: "application/json"
59
+ }
60
+ })
61
+ .then(async (response) => {
62
+ this.reRender(pageId, await response.json())
63
+ spinner.stop()
64
+ })
65
+ .catch(this.errorHandler)
66
+ }.bind(this)
67
+ )
53
68
  }
54
69
 
55
70
  // Renders the sitemap
56
- render(data, foldingId) {
57
- let renderTarget, renderTemplate
71
+ render(data) {
72
+ const renderTarget = this.sitemap_wrapper
73
+ const renderTemplate = this.template
58
74
 
59
- if (foldingId) {
60
- renderTarget = document.getElementById(`page_${foldingId}`)
61
- renderTemplate = this.list_template
62
- renderTarget.outerHTML = renderTemplate({ children: data.pages })
63
- } else {
64
- renderTarget = this.sitemap_wrapper
65
- renderTemplate = this.template
66
- renderTarget.innerHTML = renderTemplate({ children: data.pages })
67
- }
75
+ renderTarget.innerHTML = renderTemplate({ children: data.pages })
68
76
  this.items = document
69
77
  .getElementById("sitemap")
70
78
  .querySelectorAll(".sitemap_page")
71
79
  this.sitemap_wrapper = document.getElementById("sitemap-wrapper")
72
80
  this._observe()
81
+ PageSorter()
82
+ }
73
83
 
74
- if (this.options.ready) {
75
- this.options.ready()
76
- }
84
+ reRender(pageId, data) {
85
+ let pageEl = document.getElementById(`page_${pageId}`)
86
+ pageEl.outerHTML = this.list_template({ children: data.pages })
87
+ pageEl = document.getElementById(`page_${pageId}`)
88
+ const sortables = pageEl.querySelectorAll("ul.children")
89
+ createSortables(sortables)
90
+ displayPageFolders()
77
91
  }
78
92
 
79
93
  // Filters the sitemap
@@ -130,4 +144,9 @@ export default class Sitemap {
130
144
  return false
131
145
  })
132
146
  }
147
+
148
+ errorHandler(error) {
149
+ Alchemy.growl(error.message || error, "error")
150
+ console.error(error)
151
+ }
133
152
  }
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alchemy_cms/admin",
3
- "version": "5.3.0",
3
+ "version": "5.3.1",
4
4
  "description": "AlchemyCMS",
5
5
  "browser": "package/admin.js",
6
6
  "files": [
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: alchemy_cms
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.3.0
4
+ version: 5.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas von Deyen
@@ -13,7 +13,7 @@ authors:
13
13
  autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
- date: 2022-03-09 00:00:00.000000000 Z
16
+ date: 2022-03-11 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
19
  name: active_model_serializers
@@ -633,7 +633,6 @@ files:
633
633
  - app/assets/javascripts/alchemy/alchemy.initializer.js.coffee
634
634
  - app/assets/javascripts/alchemy/alchemy.link_dialog.js.coffee
635
635
  - app/assets/javascripts/alchemy/alchemy.list_filter.js.coffee
636
- - app/assets/javascripts/alchemy/alchemy.page_sorter.js
637
636
  - app/assets/javascripts/alchemy/alchemy.preview.js.coffee
638
637
  - app/assets/javascripts/alchemy/alchemy.preview_window.js.coffee
639
638
  - app/assets/javascripts/alchemy/alchemy.spinner.js
@@ -650,6 +649,7 @@ files:
650
649
  - app/assets/javascripts/alchemy/templates/node.hbs
651
650
  - app/assets/javascripts/alchemy/templates/node_folder.hbs
652
651
  - app/assets/javascripts/alchemy/templates/page.hbs
652
+ - app/assets/javascripts/alchemy/templates/page_folder.hbs
653
653
  - app/assets/javascripts/alchemy/templates/spinner.hbs
654
654
  - app/assets/javascripts/tinymce/plugins/alchemy_link/plugin.min.js
655
655
  - app/assets/stylesheets/alchemy/_defaults.scss
@@ -927,7 +927,6 @@ files:
927
927
  - app/views/alchemy/admin/pages/configure.html.erb
928
928
  - app/views/alchemy/admin/pages/edit.html.erb
929
929
  - app/views/alchemy/admin/pages/flush.js.erb
930
- - app/views/alchemy/admin/pages/fold.js.erb
931
930
  - app/views/alchemy/admin/pages/index.html.erb
932
931
  - app/views/alchemy/admin/pages/info.html.erb
933
932
  - app/views/alchemy/admin/pages/link.html.erb
@@ -935,7 +934,6 @@ files:
935
934
  - app/views/alchemy/admin/pages/locked.html.erb
936
935
  - app/views/alchemy/admin/pages/new.html.erb
937
936
  - app/views/alchemy/admin/pages/show.html.erb
938
- - app/views/alchemy/admin/pages/sort.html.erb
939
937
  - app/views/alchemy/admin/pages/unlock.js.erb
940
938
  - app/views/alchemy/admin/pages/update.js.erb
941
939
  - app/views/alchemy/admin/partials/_autocomplete_tag_list.html.erb
@@ -1190,6 +1188,7 @@ files:
1190
1188
  - package/src/i18n.js
1191
1189
  - package/src/node_tree.js
1192
1190
  - package/src/page_publication_fields.js
1191
+ - package/src/page_sorter.js
1193
1192
  - package/src/sitemap.js
1194
1193
  - package/src/translations.js
1195
1194
  - package/src/utils/__tests__/ajax.spec.js
@@ -1215,7 +1214,6 @@ files:
1215
1214
  - vendor/assets/javascripts/flatpickr/flatpickr.min.js
1216
1215
  - vendor/assets/javascripts/jquery_plugins/jquery.Jcrop.min.js
1217
1216
  - vendor/assets/javascripts/jquery_plugins/jquery.scrollTo.min.js
1218
- - vendor/assets/javascripts/jquery_plugins/jquery.ui.nestedSortable.js
1219
1217
  - vendor/assets/javascripts/jquery_plugins/jquery.ui.tabspaging.js
1220
1218
  - vendor/assets/javascripts/jquery_plugins/select2.js
1221
1219
  - vendor/assets/javascripts/keymaster.js
@@ -1,24 +0,0 @@
1
- Alchemy.PageSorter = function () {
2
- var $sortables = $("ul#sitemap").find("ul.level_0_children")
3
-
4
- $sortables.nestedSortable({
5
- disableNesting: "no-nest",
6
- forcePlaceholderSize: true,
7
- handle: ".handle",
8
- items: "li",
9
- listType: "ul",
10
- opacity: 0.5,
11
- placeholder: "placeholder",
12
- tabSize: 16,
13
- tolerance: "pointer",
14
- toleranceElement: "> div"
15
- })
16
-
17
- $("#save_page_order").click(function (e) {
18
- e.preventDefault()
19
- Alchemy.Buttons.disable(this)
20
- $.post(Alchemy.routes.order_admin_pages_path, {
21
- set: JSON.stringify($sortables.nestedSortable("toHierarchy"))
22
- })
23
- })
24
- }
@@ -1,2 +0,0 @@
1
- $('#fold_button_<%= @page.id %>').css('background', 'none');
2
- Alchemy.currentSitemap.reload(<%= @page.id %>);
@@ -1,19 +0,0 @@
1
- <% content_for :toolbar do %>
2
- <div class="button_with_label">
3
- <%= link_to alchemy.admin_pages_path, class: 'icon_button' do %>
4
- <%= render_icon 'angle-double-left' %>
5
- <% end %>
6
- <label><%= Alchemy.t(:cancel) %></label>
7
- </div>
8
- <% end %>
9
-
10
- <div id="sort_panel">
11
- <%= render_message do %>
12
- <%= Alchemy.t(:explain_sitemap_dragndrop_sorting) %>
13
- <% end %>
14
- <div class="buttons">
15
- <%= button_tag Alchemy.t('save order'), id: 'save_page_order' %>
16
- </div>
17
- </div>
18
-
19
- <%= render 'sitemap', page_partial: 'page', full: true %>