alchemy_cms 5.3.1 → 5.3.4
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +17 -0
- data/app/assets/javascripts/alchemy/alchemy.base.js.coffee +5 -2
- data/app/assets/javascripts/alchemy/alchemy.link_dialog.js.coffee +2 -0
- data/app/assets/stylesheets/alchemy/archive.scss +4 -0
- data/app/helpers/alchemy/elements_helper.rb +2 -2
- data/lib/alchemy/version.rb +1 -1
- data/package/src/node_tree.js +3 -3
- data/package/src/page_sorter.js +3 -9
- data/package/src/sitemap.js +5 -9
- data/package/src/utils/__tests__/ajax.spec.js +71 -27
- data/package/src/utils/ajax.js +20 -3
- data/package.json +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 37f7ca98f0e6c0d8729e8ba6ef3fd432449dc5dba0b900ef72f9bd7494e406d5
|
4
|
+
data.tar.gz: 0d3871f0f550d07b09eda00cd5a26427d9c80303cc0f008aea496a7a3e9a6579
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c91fb49f9939ad01bb30e88fe3042898d4cca8126e0d3ebc143f7a2232cf67cbbc176ca796c8b14f517683e975172ed8d7f92359989297cce30274bdb5bc981d
|
7
|
+
data.tar.gz: a3e8bcf872db1d3276dffb0e56baa01a125e24f4ede546359854032a45446d5abc44b7559ab8f76fb1da8b692572ed7608f51542bf5a70dafb8a1ecb75b9bce3
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,20 @@
|
|
1
|
+
## 5.3.4 (2022-04-11)
|
2
|
+
|
3
|
+
- Don't delete locals in render_element so they can be used by all elem… [#2284](https://github.com/AlchemyCMS/alchemy_cms/pull/2284) ([dbwinger](https://github.com/dbwinger))
|
4
|
+
- Show site and language name on page select in Link dialog [#2280](https://github.com/AlchemyCMS/alchemy_cms/pull/2280) ([dbwinger](https://github.com/dbwinger))
|
5
|
+
|
6
|
+
## 5.3.3 (2022-03-24)
|
7
|
+
|
8
|
+
- fix admin sitemap feature specs ([tvdeyen](https://github.com/tvdeyen))
|
9
|
+
- fix: Add support for ajax.get query params ([tvdeyen](https://github.com/tvdeyen))
|
10
|
+
- fix(Sitemap): Use response data ([tvdeyen](https://github.com/tvdeyen))
|
11
|
+
- Revert "Ajax: Send method override" ([tvdeyen](https://github.com/tvdeyen))
|
12
|
+
|
13
|
+
## 5.3.2 (2022-03-24)
|
14
|
+
|
15
|
+
- ImageLoader: Add error handling ([tvdeyen](https://github.com/tvdeyen))
|
16
|
+
- Fix new Sitemap ([tvdeyen](https://github.com/tvdeyen))
|
17
|
+
|
1
18
|
## 5.3.1 (2022-03-11)
|
2
19
|
|
3
20
|
- Allow all pages in API again ([tvdeyen](https://github.com/tvdeyen))
|
@@ -54,9 +54,12 @@ $.extend Alchemy,
|
|
54
54
|
image.on 'load', ->
|
55
55
|
spinner.stop()
|
56
56
|
image.fadeIn 400
|
57
|
-
image.on 'error', ->
|
57
|
+
image.on 'error', (evt) ->
|
58
|
+
message = "Could not load #{this.src}"
|
58
59
|
spinner.stop()
|
59
|
-
|
60
|
+
console.error(message, evt)
|
61
|
+
$parent.html('<span class="icon fas fa-exclamation-triangle" title="' + message + '" />')
|
62
|
+
return
|
60
63
|
|
61
64
|
# Removes the picture from essence picture thumbnail
|
62
65
|
removePicture: (selector) ->
|
@@ -80,6 +80,8 @@ class window.Alchemy.LinkDialog extends Alchemy.Dialog
|
|
80
80
|
name: page.name
|
81
81
|
url_path: page.url_path
|
82
82
|
page_id: page.id
|
83
|
+
language: page.language
|
84
|
+
site: page.site
|
83
85
|
more: meta.page * meta.per_page < meta.total_count
|
84
86
|
initSelection: ($element, callback) =>
|
85
87
|
urlname = $element.val()
|
@@ -142,8 +142,8 @@ module Alchemy
|
|
142
142
|
render element, {
|
143
143
|
element: element,
|
144
144
|
counter: counter,
|
145
|
-
options: options,
|
146
|
-
}.merge(options
|
145
|
+
options: options.except(:locals),
|
146
|
+
}.merge(options[:locals] || {})
|
147
147
|
rescue ActionView::MissingTemplate => e
|
148
148
|
warning(%(
|
149
149
|
Element view partial not found for #{element.name}.\n
|
data/lib/alchemy/version.rb
CHANGED
data/package/src/node_tree.js
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import Sortable from "sortablejs"
|
2
|
-
import
|
2
|
+
import { patch } from "./utils/ajax"
|
3
3
|
import { on } from "./utils/events"
|
4
4
|
|
5
5
|
function displayNodeFolders() {
|
@@ -23,7 +23,7 @@ function onFinishDragging(evt) {
|
|
23
23
|
new_position: evt.newIndex
|
24
24
|
}
|
25
25
|
|
26
|
-
|
26
|
+
patch(url, data)
|
27
27
|
.then(() => {
|
28
28
|
const message = Alchemy.t("Successfully moved menu item")
|
29
29
|
Alchemy.growl(message)
|
@@ -41,7 +41,7 @@ function handleNodeFolders() {
|
|
41
41
|
const url = Alchemy.routes.toggle_folded_api_node_path(nodeId)
|
42
42
|
const list = menu_item.querySelector(".children")
|
43
43
|
|
44
|
-
|
44
|
+
patch(url)
|
45
45
|
.then(() => {
|
46
46
|
list.classList.toggle("folded")
|
47
47
|
menu_item.dataset.folded =
|
data/package/src/page_sorter.js
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import Sortable from "sortablejs"
|
2
|
+
import { patch } from "./utils/ajax"
|
2
3
|
|
3
4
|
function onFinishDragging(evt) {
|
4
5
|
const pageId = evt.item.dataset.pageId
|
@@ -8,16 +9,9 @@ function onFinishDragging(evt) {
|
|
8
9
|
new_position: evt.newIndex
|
9
10
|
}
|
10
11
|
|
11
|
-
|
12
|
-
method: "PATCH",
|
13
|
-
headers: {
|
14
|
-
"Content-Type": "application/json",
|
15
|
-
Accept: "application/json"
|
16
|
-
},
|
17
|
-
body: JSON.stringify(data)
|
18
|
-
})
|
12
|
+
patch(url, data)
|
19
13
|
.then(async (response) => {
|
20
|
-
const pageData = await response.
|
14
|
+
const pageData = await response.data
|
21
15
|
const pageEl = document.getElementById(`page_${pageId}`)
|
22
16
|
const urlPathEl = pageEl.querySelector(".sitemap_url")
|
23
17
|
|
data/package/src/sitemap.js
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
// The admin sitemap Alchemy class
|
2
2
|
import PageSorter from "./page_sorter"
|
3
3
|
import { on } from "./utils/events"
|
4
|
+
import { get, patch } from "./utils/ajax"
|
4
5
|
import { createSortables, displayPageFolders } from "./page_sorter"
|
5
6
|
|
6
7
|
export default class Sitemap {
|
@@ -30,9 +31,9 @@ export default class Sitemap {
|
|
30
31
|
const spinTarget = this.sitemap_wrapper
|
31
32
|
spinTarget.innerHTML = ""
|
32
33
|
spinner.spin(spinTarget)
|
33
|
-
|
34
|
+
get(this.options.url, { id: pageId })
|
34
35
|
.then(async (response) => {
|
35
|
-
this.render(await response.
|
36
|
+
this.render(await response.data)
|
36
37
|
this.handlePageFolders()
|
37
38
|
spinner.stop()
|
38
39
|
})
|
@@ -52,14 +53,9 @@ export default class Sitemap {
|
|
52
53
|
pageFolder.innerHTML = ""
|
53
54
|
spinner.spin(pageFolder)
|
54
55
|
|
55
|
-
|
56
|
-
method: "PATCH",
|
57
|
-
headers: {
|
58
|
-
Accept: "application/json"
|
59
|
-
}
|
60
|
-
})
|
56
|
+
patch(Alchemy.routes.fold_admin_page_path(pageId))
|
61
57
|
.then(async (response) => {
|
62
|
-
this.reRender(pageId, await response.
|
58
|
+
this.reRender(pageId, await response.data)
|
63
59
|
spinner.stop()
|
64
60
|
})
|
65
61
|
.catch(this.errorHandler)
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import xhrMock from "xhr-mock"
|
2
|
-
import
|
2
|
+
import { get, patch, post } from "../ajax"
|
3
3
|
|
4
4
|
const token = "s3cr3t"
|
5
5
|
|
@@ -8,116 +8,160 @@ beforeEach(() => {
|
|
8
8
|
xhrMock.setup()
|
9
9
|
})
|
10
10
|
|
11
|
-
describe("
|
11
|
+
describe("get", () => {
|
12
12
|
it("sends X-CSRF-TOKEN header", async () => {
|
13
|
-
xhrMock.get("/users", (req, res) => {
|
13
|
+
xhrMock.get("http://localhost/users", (req, res) => {
|
14
14
|
expect(req.header("X-CSRF-TOKEN")).toEqual(token)
|
15
15
|
return res.status(200).body('{"message":"Ok"}')
|
16
16
|
})
|
17
|
-
await
|
17
|
+
await get("/users")
|
18
18
|
})
|
19
19
|
|
20
20
|
it("sends Content-Type header", async () => {
|
21
|
-
xhrMock.get("/users", (req, res) => {
|
21
|
+
xhrMock.get("http://localhost/users", (req, res) => {
|
22
22
|
expect(req.header("Content-Type")).toEqual(
|
23
23
|
"application/json; charset=utf-8"
|
24
24
|
)
|
25
25
|
return res.status(200).body('{"message":"Ok"}')
|
26
26
|
})
|
27
|
-
await
|
27
|
+
await get("/users")
|
28
28
|
})
|
29
29
|
|
30
30
|
it("sends Accept header", async () => {
|
31
|
-
xhrMock.get("/users", (req, res) => {
|
31
|
+
xhrMock.get("http://localhost/users", (req, res) => {
|
32
32
|
expect(req.header("Accept")).toEqual("application/json")
|
33
33
|
return res.status(200).body('{"message":"Ok"}')
|
34
34
|
})
|
35
|
-
await
|
35
|
+
await get("/users")
|
36
36
|
})
|
37
37
|
|
38
38
|
it("returns JSON", async () => {
|
39
|
-
xhrMock.get("/users", (_req, res) => {
|
39
|
+
xhrMock.get("http://localhost/users", (_req, res) => {
|
40
40
|
return res.status(200).body('{"email":"mail@example.com"}')
|
41
41
|
})
|
42
|
-
await
|
42
|
+
await get("/users").then((res) => {
|
43
43
|
expect(res.data).toEqual({ email: "mail@example.com" })
|
44
44
|
})
|
45
45
|
})
|
46
46
|
|
47
47
|
it("JSON parse errors get rejected", async () => {
|
48
|
-
xhrMock.get("/users", (_req, res) => {
|
48
|
+
xhrMock.get("http://localhost/users", (_req, res) => {
|
49
49
|
return res.status(200).body('email => "mail@example.com"')
|
50
50
|
})
|
51
51
|
expect.assertions(1)
|
52
|
-
await
|
52
|
+
await get("/users").catch((e) => {
|
53
53
|
expect(e.message).toMatch("Unexpected token")
|
54
54
|
})
|
55
55
|
})
|
56
56
|
|
57
57
|
it("network errors get rejected", async () => {
|
58
|
-
xhrMock.get("/users", () => {
|
58
|
+
xhrMock.get("http://localhost/users", () => {
|
59
59
|
return Promise.reject(new Error())
|
60
60
|
})
|
61
61
|
expect.assertions(1)
|
62
|
-
await
|
62
|
+
await get("/users").catch((e) => {
|
63
63
|
expect(e.message).toEqual("An error occurred during the transaction")
|
64
64
|
})
|
65
65
|
})
|
66
66
|
|
67
67
|
it("server errors get rejected", async () => {
|
68
|
-
xhrMock.get("/users", (_req, res) => {
|
68
|
+
xhrMock.get("http://localhost/users", (_req, res) => {
|
69
69
|
return res.status(401).body('{"error":"Unauthorized"}')
|
70
70
|
})
|
71
71
|
expect.assertions(1)
|
72
|
-
await
|
72
|
+
await get("/users").catch((e) => {
|
73
73
|
expect(e.error).toEqual("Unauthorized")
|
74
74
|
})
|
75
75
|
})
|
76
76
|
|
77
77
|
it("server errors parsing errors get rejected", async () => {
|
78
|
-
xhrMock.get("/users", (_req, res) => {
|
78
|
+
xhrMock.get("http://localhost/users", (_req, res) => {
|
79
79
|
return res.status(401).body("Unauthorized")
|
80
80
|
})
|
81
81
|
expect.assertions(1)
|
82
|
-
await
|
82
|
+
await get("/users").catch((e) => {
|
83
83
|
expect(e.message).toMatch("Unexpected token")
|
84
84
|
})
|
85
85
|
})
|
86
|
+
|
87
|
+
it("params get attached as query string", async () => {
|
88
|
+
xhrMock.get("http://localhost/users?name=foo", (_req, res) => {
|
89
|
+
return res.status(200).body(`{"name":"foo"}`)
|
90
|
+
})
|
91
|
+
const { data } = await get("/users", { name: "foo" })
|
92
|
+
expect(data.name).toEqual("foo")
|
93
|
+
})
|
94
|
+
})
|
95
|
+
|
96
|
+
describe("patch", () => {
|
97
|
+
it("sends X-CSRF-TOKEN header", async () => {
|
98
|
+
xhrMock.patch("http://localhost/users", (req, res) => {
|
99
|
+
expect(req.header("X-CSRF-TOKEN")).toEqual(token)
|
100
|
+
return res.status(200).body('{"message":"Ok"}')
|
101
|
+
})
|
102
|
+
await patch("/users")
|
103
|
+
})
|
104
|
+
|
105
|
+
it("sends Content-Type header", async () => {
|
106
|
+
xhrMock.patch("http://localhost/users", (req, res) => {
|
107
|
+
expect(req.header("Content-Type")).toEqual(
|
108
|
+
"application/json; charset=utf-8"
|
109
|
+
)
|
110
|
+
return res.status(200).body('{"message":"Ok"}')
|
111
|
+
})
|
112
|
+
await patch("/users")
|
113
|
+
})
|
114
|
+
|
115
|
+
it("sends Accept header", async () => {
|
116
|
+
xhrMock.patch("http://localhost/users", (req, res) => {
|
117
|
+
expect(req.header("Accept")).toEqual("application/json")
|
118
|
+
return res.status(200).body('{"message":"Ok"}')
|
119
|
+
})
|
120
|
+
await patch("/users")
|
121
|
+
})
|
122
|
+
|
123
|
+
it("sends JSON data", async () => {
|
124
|
+
xhrMock.patch("http://localhost/users", (req, res) => {
|
125
|
+
expect(req.body()).toEqual('{"email":"mail@example.com"}')
|
126
|
+
return res.status(200).body('{"message":"Ok"}')
|
127
|
+
})
|
128
|
+
await patch("/users", { email: "mail@example.com" })
|
129
|
+
})
|
86
130
|
})
|
87
131
|
|
88
|
-
describe("
|
132
|
+
describe("post", () => {
|
89
133
|
it("sends X-CSRF-TOKEN header", async () => {
|
90
|
-
xhrMock.post("/users", (req, res) => {
|
134
|
+
xhrMock.post("http://localhost/users", (req, res) => {
|
91
135
|
expect(req.header("X-CSRF-TOKEN")).toEqual(token)
|
92
136
|
return res.status(200).body('{"message":"Ok"}')
|
93
137
|
})
|
94
|
-
await
|
138
|
+
await post("/users")
|
95
139
|
})
|
96
140
|
|
97
141
|
it("sends Content-Type header", async () => {
|
98
|
-
xhrMock.post("/users", (req, res) => {
|
142
|
+
xhrMock.post("http://localhost/users", (req, res) => {
|
99
143
|
expect(req.header("Content-Type")).toEqual(
|
100
144
|
"application/json; charset=utf-8"
|
101
145
|
)
|
102
146
|
return res.status(200).body('{"message":"Ok"}')
|
103
147
|
})
|
104
|
-
await
|
148
|
+
await post("/users")
|
105
149
|
})
|
106
150
|
|
107
151
|
it("sends Accept header", async () => {
|
108
|
-
xhrMock.post("/users", (req, res) => {
|
152
|
+
xhrMock.post("http://localhost/users", (req, res) => {
|
109
153
|
expect(req.header("Accept")).toEqual("application/json")
|
110
154
|
return res.status(200).body('{"message":"Ok"}')
|
111
155
|
})
|
112
|
-
await
|
156
|
+
await post("/users")
|
113
157
|
})
|
114
158
|
|
115
159
|
it("sends JSON data", async () => {
|
116
|
-
xhrMock.post("/users", (req, res) => {
|
160
|
+
xhrMock.post("http://localhost/users", (req, res) => {
|
117
161
|
expect(req.body()).toEqual('{"email":"mail@example.com"}')
|
118
162
|
return res.status(200).body('{"message":"Ok"}')
|
119
163
|
})
|
120
|
-
await
|
164
|
+
await post("/users", { email: "mail@example.com" })
|
121
165
|
})
|
122
166
|
})
|
123
167
|
|
data/package/src/utils/ajax.js
CHANGED
@@ -29,16 +29,33 @@ function getToken() {
|
|
29
29
|
return metaTag.attributes.content.textContent
|
30
30
|
}
|
31
31
|
|
32
|
-
export
|
32
|
+
export function get(url, params) {
|
33
|
+
return ajax("GET", url, params)
|
34
|
+
}
|
35
|
+
|
36
|
+
export function patch(url, data) {
|
37
|
+
return ajax("PATCH", url, data)
|
38
|
+
}
|
39
|
+
|
40
|
+
export function post(url, data) {
|
41
|
+
return ajax("POST", url, data)
|
42
|
+
}
|
43
|
+
|
44
|
+
export default function ajax(method, path, data) {
|
33
45
|
const xhr = new XMLHttpRequest()
|
34
46
|
const promise = buildPromise(xhr)
|
47
|
+
const url = new URL(window.location.origin + path)
|
48
|
+
|
49
|
+
if (data && method.toLowerCase() === "get") {
|
50
|
+
url.search = new URLSearchParams(data).toString()
|
51
|
+
}
|
35
52
|
|
36
|
-
xhr.open(method, url)
|
53
|
+
xhr.open(method, url.toString())
|
37
54
|
xhr.setRequestHeader("Content-type", "application/json; charset=utf-8")
|
38
55
|
xhr.setRequestHeader("Accept", "application/json")
|
39
56
|
xhr.setRequestHeader("X-CSRF-Token", getToken())
|
40
57
|
|
41
|
-
if (data) {
|
58
|
+
if (data && method.toLowerCase() !== "get") {
|
42
59
|
xhr.send(JSON.stringify(data))
|
43
60
|
} else {
|
44
61
|
xhr.send()
|
data/package.json
CHANGED
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.
|
4
|
+
version: 5.3.4
|
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-
|
16
|
+
date: 2022-04-11 00:00:00.000000000 Z
|
17
17
|
dependencies:
|
18
18
|
- !ruby/object:Gem::Dependency
|
19
19
|
name: active_model_serializers
|