alchemy_cms 6.0.0.pre.rc4 → 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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +8 -15
- data/.github/workflows/stale.yml +21 -7
- data/.gitignore +0 -1
- data/.rspec +1 -0
- data/CHANGELOG.md +87 -0
- data/Gemfile +7 -6
- data/Rakefile +5 -1
- data/alchemy_cms.gemspec +2 -2
- data/app/assets/javascripts/alchemy/admin.js +0 -2
- data/app/assets/javascripts/alchemy/alchemy.dialog.js.coffee +6 -1
- data/app/assets/javascripts/alchemy/page_select.js +13 -8
- data/app/assets/javascripts/alchemy/templates/index.js +1 -0
- data/app/assets/javascripts/alchemy/templates/page.hbs +17 -7
- data/app/assets/javascripts/alchemy/templates/page_folder.hbs +3 -0
- data/app/assets/stylesheets/alchemy/archive.scss +4 -0
- data/app/assets/stylesheets/alchemy/page-select.scss +29 -4
- data/app/assets/stylesheets/alchemy/sitemap.scss +9 -7
- data/app/controllers/alchemy/admin/pages_controller.rb +10 -15
- data/app/controllers/alchemy/api/pages_controller.rb +14 -4
- data/app/models/alchemy/ingredient.rb +6 -1
- data/app/models/alchemy/page.rb +9 -3
- data/app/serializers/alchemy/page_serializer.rb +7 -1
- data/app/serializers/alchemy/page_tree_serializer.rb +3 -3
- data/app/services/alchemy/tag_validations.rb +21 -0
- data/app/views/alchemy/admin/pages/_form.html.erb +19 -0
- data/app/views/alchemy/admin/pages/_new_page_form.html.erb +16 -5
- data/app/views/alchemy/admin/pages/_page.html.erb +111 -133
- data/app/views/alchemy/admin/pages/_sitemap.html.erb +10 -16
- data/app/views/alchemy/admin/pages/_toolbar.html.erb +0 -12
- data/app/views/alchemy/admin/pages/edit.html.erb +1 -1
- data/app/views/alchemy/admin/pages/index.html.erb +1 -1
- data/app/views/alchemy/admin/pages/update.js.erb +7 -5
- data/app/views/alchemy/admin/partials/_routes.html.erb +8 -1
- data/app/views/alchemy/essences/_essence_page_editor.html.erb +1 -1
- data/config/locales/alchemy.en.yml +0 -4
- data/config/routes.rb +4 -3
- data/db/migrate/20200226213334_alchemy_four_point_four.rb +30 -30
- data/db/migrate/20200423073425_create_alchemy_essence_nodes.rb +1 -1
- data/db/migrate/20200504210159_remove_site_id_from_nodes.rb +1 -1
- data/db/migrate/20200505215518_add_language_id_foreign_key_to_alchemy_pages.rb +1 -1
- data/db/migrate/20200511113603_add_menu_type_to_alchemy_nodes.rb +1 -1
- data/db/migrate/20200514091507_make_page_layoutpage_null_false.rb +1 -1
- data/db/migrate/20200519073500_remove_visible_from_alchemy_pages.rb +1 -1
- data/db/migrate/20200617110713_create_alchemy_picture_thumbs.rb +1 -1
- data/db/migrate/20200907111332_remove_tri_state_booleans.rb +1 -1
- data/db/migrate/20201207131309_create_page_versions.rb +1 -1
- data/db/migrate/20201207135820_add_page_version_id_to_alchemy_elements.rb +1 -1
- data/lib/alchemy/engine.rb +5 -11
- data/lib/alchemy/permissions.rb +0 -1
- data/lib/alchemy/test_support/shared_ingredient_examples.rb +4 -2
- data/lib/alchemy/version.rb +1 -1
- data/lib/generators/alchemy/install/install_generator.rb +6 -1
- data/package/admin.js +5 -1
- data/package/src/image_loader.js +4 -2
- data/package/src/node_tree.js +13 -6
- data/package/src/page_publication_fields.js +28 -0
- data/package/src/page_sorter.js +62 -0
- data/package/src/picture_editors.js +4 -4
- data/package/src/sitemap.js +148 -0
- data/package/src/utils/__tests__/ajax.spec.js +52 -16
- data/package/src/utils/ajax.js +12 -0
- data/package.json +1 -1
- metadata +24 -24
- data/app/assets/javascripts/alchemy/alchemy.page_sorter.js +0 -24
- data/app/assets/javascripts/alchemy/alchemy.sitemap.js.coffee +0 -119
- data/app/views/alchemy/admin/pages/fold.js.erb +0 -2
- data/app/views/alchemy/admin/pages/sort.html.erb +0 -19
- data/lib/alchemy/error_tracking/airbrake_handler.rb +0 -13
- data/vendor/assets/javascripts/jquery_plugins/jquery.ui.nestedSortable.js +0 -434
@@ -0,0 +1,148 @@
|
|
1
|
+
// The admin sitemap Alchemy class
|
2
|
+
import PageSorter from "./page_sorter"
|
3
|
+
import { on } from "./utils/events"
|
4
|
+
import { get, patch } from "./utils/ajax"
|
5
|
+
import { createSortables, displayPageFolders } from "./page_sorter"
|
6
|
+
|
7
|
+
export default class Sitemap {
|
8
|
+
// Storing some objects.
|
9
|
+
constructor(options) {
|
10
|
+
const list_template_html = document
|
11
|
+
.getElementById("sitemap-list")
|
12
|
+
.innerHTML.replace(/__ID__/g, "{{id}}")
|
13
|
+
this.search_field = document.querySelector(".search_input_field")
|
14
|
+
this.filter_field_clear = document.querySelector(".search_field_clear")
|
15
|
+
this.filter_field_clear.removeAttribute("href")
|
16
|
+
this.display = document.getElementById("page_filter_result")
|
17
|
+
this.sitemap_wrapper = document.getElementById("sitemap-wrapper")
|
18
|
+
this.template = Handlebars.compile(
|
19
|
+
document.getElementById("sitemap-template").innerHTML
|
20
|
+
)
|
21
|
+
this.list_template = Handlebars.compile(list_template_html)
|
22
|
+
this.items = null
|
23
|
+
this.options = options
|
24
|
+
Handlebars.registerPartial("list", list_template_html)
|
25
|
+
this.load(options.page_root_id)
|
26
|
+
}
|
27
|
+
|
28
|
+
// Loads the sitemap
|
29
|
+
load(pageId) {
|
30
|
+
const spinner = new Alchemy.Spinner("medium")
|
31
|
+
const spinTarget = this.sitemap_wrapper
|
32
|
+
spinTarget.innerHTML = ""
|
33
|
+
spinner.spin(spinTarget)
|
34
|
+
get(this.options.url, { id: pageId })
|
35
|
+
.then(async (response) => {
|
36
|
+
this.render(await response.data)
|
37
|
+
this.handlePageFolders()
|
38
|
+
spinner.stop()
|
39
|
+
})
|
40
|
+
.catch(this.errorHandler)
|
41
|
+
}
|
42
|
+
|
43
|
+
// Watch page folder clicks and re-render the page branch
|
44
|
+
handlePageFolders() {
|
45
|
+
on(
|
46
|
+
"click",
|
47
|
+
"#sitemap",
|
48
|
+
".page_folder",
|
49
|
+
function (evt) {
|
50
|
+
const spinner = new Alchemy.Spinner("small")
|
51
|
+
const pageFolder = evt.target.closest(".page_folder")
|
52
|
+
const pageId = pageFolder.dataset.pageId
|
53
|
+
pageFolder.innerHTML = ""
|
54
|
+
spinner.spin(pageFolder)
|
55
|
+
|
56
|
+
patch(Alchemy.routes.fold_admin_page_path(pageId))
|
57
|
+
.then(async (response) => {
|
58
|
+
this.reRender(pageId, await response.data)
|
59
|
+
spinner.stop()
|
60
|
+
})
|
61
|
+
.catch(this.errorHandler)
|
62
|
+
}.bind(this)
|
63
|
+
)
|
64
|
+
}
|
65
|
+
|
66
|
+
// Renders the sitemap
|
67
|
+
render(data) {
|
68
|
+
const renderTarget = this.sitemap_wrapper
|
69
|
+
const renderTemplate = this.template
|
70
|
+
|
71
|
+
renderTarget.innerHTML = renderTemplate({ children: data.pages })
|
72
|
+
this.items = document
|
73
|
+
.getElementById("sitemap")
|
74
|
+
.querySelectorAll(".sitemap_page")
|
75
|
+
this.sitemap_wrapper = document.getElementById("sitemap-wrapper")
|
76
|
+
this._observe()
|
77
|
+
PageSorter()
|
78
|
+
}
|
79
|
+
|
80
|
+
reRender(pageId, data) {
|
81
|
+
let pageEl = document.getElementById(`page_${pageId}`)
|
82
|
+
pageEl.outerHTML = this.list_template({ children: data.pages })
|
83
|
+
pageEl = document.getElementById(`page_${pageId}`)
|
84
|
+
const sortables = pageEl.querySelectorAll("ul.children")
|
85
|
+
createSortables(sortables)
|
86
|
+
displayPageFolders()
|
87
|
+
}
|
88
|
+
|
89
|
+
// Filters the sitemap
|
90
|
+
filter(term) {
|
91
|
+
const results = []
|
92
|
+
|
93
|
+
this.items.forEach(function (item) {
|
94
|
+
if (
|
95
|
+
term !== "" &&
|
96
|
+
item.getAttribute("name").toLowerCase().indexOf(term) !== -1
|
97
|
+
) {
|
98
|
+
item.classList.add("highlight")
|
99
|
+
item.classList.remove("no-match")
|
100
|
+
results.push(item)
|
101
|
+
} else {
|
102
|
+
item.classList.add("no-match")
|
103
|
+
item.classList.remove("highlight")
|
104
|
+
}
|
105
|
+
})
|
106
|
+
this.filter_field_clear.style.display = "inline-block"
|
107
|
+
const { length } = results
|
108
|
+
|
109
|
+
if (length === 1) {
|
110
|
+
this.display.style.display = "block"
|
111
|
+
this.display.innerText = `1 ${Alchemy.t("page_found")}`
|
112
|
+
results[0].scrollIntoView({ behavior: "smooth", block: "center" })
|
113
|
+
} else if (length > 1) {
|
114
|
+
this.display.style.display = "block"
|
115
|
+
this.display.innerText = `${length} ${Alchemy.t("pages_found")}`
|
116
|
+
} else {
|
117
|
+
this.items.forEach((item) =>
|
118
|
+
item.classList.remove("no-match", "highlight")
|
119
|
+
)
|
120
|
+
this.display.style.display = "none"
|
121
|
+
window.scrollTo({
|
122
|
+
top: 0,
|
123
|
+
left: 0,
|
124
|
+
behavior: "smooth"
|
125
|
+
})
|
126
|
+
this.filter_field_clear.style.display = "none"
|
127
|
+
}
|
128
|
+
}
|
129
|
+
|
130
|
+
// Adds onkey up observer to search field
|
131
|
+
_observe() {
|
132
|
+
this.search_field.addEventListener("keyup", (evt) => {
|
133
|
+
const term = evt.target.value
|
134
|
+
this.filter(term.toLowerCase())
|
135
|
+
})
|
136
|
+
this.search_field.addEventListener("focus", () => key.setScope("search"))
|
137
|
+
this.filter_field_clear.addEventListener("click", () => {
|
138
|
+
this.search_field.value = ""
|
139
|
+
this.filter("")
|
140
|
+
return false
|
141
|
+
})
|
142
|
+
}
|
143
|
+
|
144
|
+
errorHandler(error) {
|
145
|
+
Alchemy.growl(error.message || error, "error")
|
146
|
+
console.error(error)
|
147
|
+
}
|
148
|
+
}
|
@@ -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,13 +8,13 @@ beforeEach(() => {
|
|
8
8
|
xhrMock.setup()
|
9
9
|
})
|
10
10
|
|
11
|
-
describe("
|
11
|
+
describe("get", () => {
|
12
12
|
it("sends X-CSRF-TOKEN header", async () => {
|
13
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 () => {
|
@@ -24,7 +24,7 @@ describe("ajax('get')", () => {
|
|
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 () => {
|
@@ -32,14 +32,14 @@ describe("ajax('get')", () => {
|
|
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
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
|
})
|
@@ -49,7 +49,7 @@ describe("ajax('get')", () => {
|
|
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
|
})
|
@@ -59,7 +59,7 @@ describe("ajax('get')", () => {
|
|
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
|
})
|
@@ -69,7 +69,7 @@ describe("ajax('get')", () => {
|
|
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
|
})
|
@@ -79,7 +79,7 @@ describe("ajax('get')", () => {
|
|
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
|
})
|
@@ -88,18 +88,54 @@ describe("ajax('get')", () => {
|
|
88
88
|
xhrMock.get("http://localhost/users?name=foo", (_req, res) => {
|
89
89
|
return res.status(200).body(`{"name":"foo"}`)
|
90
90
|
})
|
91
|
-
const { data } = await
|
91
|
+
const { data } = await get("/users", { name: "foo" })
|
92
92
|
expect(data.name).toEqual("foo")
|
93
93
|
})
|
94
94
|
})
|
95
95
|
|
96
|
-
describe("
|
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
|
+
})
|
130
|
+
})
|
131
|
+
|
132
|
+
describe("post", () => {
|
97
133
|
it("sends X-CSRF-TOKEN header", async () => {
|
98
134
|
xhrMock.post("http://localhost/users", (req, res) => {
|
99
135
|
expect(req.header("X-CSRF-TOKEN")).toEqual(token)
|
100
136
|
return res.status(200).body('{"message":"Ok"}')
|
101
137
|
})
|
102
|
-
await
|
138
|
+
await post("/users")
|
103
139
|
})
|
104
140
|
|
105
141
|
it("sends Content-Type header", async () => {
|
@@ -109,7 +145,7 @@ describe("ajax('post')", () => {
|
|
109
145
|
)
|
110
146
|
return res.status(200).body('{"message":"Ok"}')
|
111
147
|
})
|
112
|
-
await
|
148
|
+
await post("/users")
|
113
149
|
})
|
114
150
|
|
115
151
|
it("sends Accept header", async () => {
|
@@ -117,7 +153,7 @@ describe("ajax('post')", () => {
|
|
117
153
|
expect(req.header("Accept")).toEqual("application/json")
|
118
154
|
return res.status(200).body('{"message":"Ok"}')
|
119
155
|
})
|
120
|
-
await
|
156
|
+
await post("/users")
|
121
157
|
})
|
122
158
|
|
123
159
|
it("sends JSON data", async () => {
|
@@ -125,7 +161,7 @@ describe("ajax('post')", () => {
|
|
125
161
|
expect(req.body()).toEqual('{"email":"mail@example.com"}')
|
126
162
|
return res.status(200).body('{"message":"Ok"}')
|
127
163
|
})
|
128
|
-
await
|
164
|
+
await post("/users", { email: "mail@example.com" })
|
129
165
|
})
|
130
166
|
})
|
131
167
|
|
data/package/src/utils/ajax.js
CHANGED
@@ -29,6 +29,18 @@ function getToken() {
|
|
29
29
|
return metaTag.attributes.content.textContent
|
30
30
|
}
|
31
31
|
|
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
|
+
|
32
44
|
export default function ajax(method, path, data) {
|
33
45
|
const xhr = new XMLHttpRequest()
|
34
46
|
const promise = buildPromise(xhr)
|
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: 6.0.0.pre.
|
4
|
+
version: 6.0.0.pre.rc7
|
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-03-28 00:00:00.000000000 Z
|
17
17
|
dependencies:
|
18
18
|
- !ruby/object:Gem::Dependency
|
19
19
|
name: actionmailer
|
@@ -410,7 +410,7 @@ dependencies:
|
|
410
410
|
version: '1.8'
|
411
411
|
- - "<="
|
412
412
|
- !ruby/object:Gem::Version
|
413
|
-
version: 2.
|
413
|
+
version: 2.6.0
|
414
414
|
type: :runtime
|
415
415
|
prerelease: false
|
416
416
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -420,7 +420,7 @@ dependencies:
|
|
420
420
|
version: '1.8'
|
421
421
|
- - "<="
|
422
422
|
- !ruby/object:Gem::Version
|
423
|
-
version: 2.
|
423
|
+
version: 2.6.0
|
424
424
|
- !ruby/object:Gem::Dependency
|
425
425
|
name: request_store
|
426
426
|
requirement: !ruby/object:Gem::Requirement
|
@@ -571,20 +571,6 @@ dependencies:
|
|
571
571
|
- - "~>"
|
572
572
|
- !ruby/object:Gem::Version
|
573
573
|
version: '1.0'
|
574
|
-
- !ruby/object:Gem::Dependency
|
575
|
-
name: cuprite
|
576
|
-
requirement: !ruby/object:Gem::Requirement
|
577
|
-
requirements:
|
578
|
-
- - "~>"
|
579
|
-
- !ruby/object:Gem::Version
|
580
|
-
version: '0.13'
|
581
|
-
type: :development
|
582
|
-
prerelease: false
|
583
|
-
version_requirements: !ruby/object:Gem::Requirement
|
584
|
-
requirements:
|
585
|
-
- - "~>"
|
586
|
-
- !ruby/object:Gem::Version
|
587
|
-
version: '0.13'
|
588
574
|
- !ruby/object:Gem::Dependency
|
589
575
|
name: factory_bot_rails
|
590
576
|
requirement: !ruby/object:Gem::Requirement
|
@@ -669,6 +655,20 @@ dependencies:
|
|
669
655
|
- - "~>"
|
670
656
|
- !ruby/object:Gem::Version
|
671
657
|
version: '0.20'
|
658
|
+
- !ruby/object:Gem::Dependency
|
659
|
+
name: webdrivers
|
660
|
+
requirement: !ruby/object:Gem::Requirement
|
661
|
+
requirements:
|
662
|
+
- - "~>"
|
663
|
+
- !ruby/object:Gem::Version
|
664
|
+
version: '5.0'
|
665
|
+
type: :development
|
666
|
+
prerelease: false
|
667
|
+
version_requirements: !ruby/object:Gem::Requirement
|
668
|
+
requirements:
|
669
|
+
- - "~>"
|
670
|
+
- !ruby/object:Gem::Version
|
671
|
+
version: '5.0'
|
672
672
|
- !ruby/object:Gem::Dependency
|
673
673
|
name: webmock
|
674
674
|
requirement: !ruby/object:Gem::Requirement
|
@@ -731,6 +731,7 @@ files:
|
|
731
731
|
- ".hound.yml"
|
732
732
|
- ".localeapp/config.rb"
|
733
733
|
- ".prettierrc"
|
734
|
+
- ".rspec"
|
734
735
|
- ".rubocop.yml"
|
735
736
|
- ".yardopts"
|
736
737
|
- CHANGELOG.md
|
@@ -772,10 +773,8 @@ files:
|
|
772
773
|
- app/assets/javascripts/alchemy/alchemy.initializer.js.coffee
|
773
774
|
- app/assets/javascripts/alchemy/alchemy.link_dialog.js.coffee
|
774
775
|
- app/assets/javascripts/alchemy/alchemy.list_filter.js.coffee
|
775
|
-
- app/assets/javascripts/alchemy/alchemy.page_sorter.js
|
776
776
|
- app/assets/javascripts/alchemy/alchemy.preview.js.coffee
|
777
777
|
- app/assets/javascripts/alchemy/alchemy.preview_window.js.coffee
|
778
|
-
- app/assets/javascripts/alchemy/alchemy.sitemap.js.coffee
|
779
778
|
- app/assets/javascripts/alchemy/alchemy.spinner.js
|
780
779
|
- app/assets/javascripts/alchemy/alchemy.string_extension.js.coffee
|
781
780
|
- app/assets/javascripts/alchemy/alchemy.tinymce.js.coffee
|
@@ -789,6 +788,7 @@ files:
|
|
789
788
|
- app/assets/javascripts/alchemy/templates/node.hbs
|
790
789
|
- app/assets/javascripts/alchemy/templates/node_folder.hbs
|
791
790
|
- app/assets/javascripts/alchemy/templates/page.hbs
|
791
|
+
- app/assets/javascripts/alchemy/templates/page_folder.hbs
|
792
792
|
- app/assets/javascripts/alchemy/templates/spinner.hbs
|
793
793
|
- app/assets/javascripts/tinymce/plugins/alchemy_link/plugin.min.js
|
794
794
|
- app/assets/stylesheets/alchemy/_defaults.scss
|
@@ -1007,6 +1007,7 @@ files:
|
|
1007
1007
|
- app/serializers/alchemy/picture_serializer.rb
|
1008
1008
|
- app/services/alchemy/delete_elements.rb
|
1009
1009
|
- app/services/alchemy/duplicate_element.rb
|
1010
|
+
- app/services/alchemy/tag_validations.rb
|
1010
1011
|
- app/views/alchemy/_edit_mode.html.erb
|
1011
1012
|
- app/views/alchemy/_menubar.html.erb
|
1012
1013
|
- app/views/alchemy/_preview_mode_code.html.erb
|
@@ -1106,7 +1107,6 @@ files:
|
|
1106
1107
|
- app/views/alchemy/admin/pages/configure.html.erb
|
1107
1108
|
- app/views/alchemy/admin/pages/edit.html.erb
|
1108
1109
|
- app/views/alchemy/admin/pages/flush.js.erb
|
1109
|
-
- app/views/alchemy/admin/pages/fold.js.erb
|
1110
1110
|
- app/views/alchemy/admin/pages/index.html.erb
|
1111
1111
|
- app/views/alchemy/admin/pages/info.html.erb
|
1112
1112
|
- app/views/alchemy/admin/pages/link.html.erb
|
@@ -1114,7 +1114,6 @@ files:
|
|
1114
1114
|
- app/views/alchemy/admin/pages/locked.html.erb
|
1115
1115
|
- app/views/alchemy/admin/pages/new.html.erb
|
1116
1116
|
- app/views/alchemy/admin/pages/show.html.erb
|
1117
|
-
- app/views/alchemy/admin/pages/sort.html.erb
|
1118
1117
|
- app/views/alchemy/admin/pages/unlock.js.erb
|
1119
1118
|
- app/views/alchemy/admin/pages/update.js.erb
|
1120
1119
|
- app/views/alchemy/admin/partials/_autocomplete_tag_list.html.erb
|
@@ -1308,7 +1307,6 @@ files:
|
|
1308
1307
|
- lib/alchemy/elements_finder.rb
|
1309
1308
|
- lib/alchemy/engine.rb
|
1310
1309
|
- lib/alchemy/error_tracking.rb
|
1311
|
-
- lib/alchemy/error_tracking/airbrake_handler.rb
|
1312
1310
|
- lib/alchemy/errors.rb
|
1313
1311
|
- lib/alchemy/essence.rb
|
1314
1312
|
- lib/alchemy/filetypes.rb
|
@@ -1431,7 +1429,10 @@ files:
|
|
1431
1429
|
- package/src/image_cropper.js
|
1432
1430
|
- package/src/image_loader.js
|
1433
1431
|
- package/src/node_tree.js
|
1432
|
+
- package/src/page_publication_fields.js
|
1433
|
+
- package/src/page_sorter.js
|
1434
1434
|
- package/src/picture_editors.js
|
1435
|
+
- package/src/sitemap.js
|
1435
1436
|
- package/src/translations.js
|
1436
1437
|
- package/src/utils/__tests__/ajax.spec.js
|
1437
1438
|
- package/src/utils/__tests__/events.spec.js
|
@@ -1456,7 +1457,6 @@ files:
|
|
1456
1457
|
- vendor/assets/javascripts/flatpickr/flatpickr.min.js
|
1457
1458
|
- vendor/assets/javascripts/jquery_plugins/jquery.Jcrop.min.js
|
1458
1459
|
- vendor/assets/javascripts/jquery_plugins/jquery.scrollTo.min.js
|
1459
|
-
- vendor/assets/javascripts/jquery_plugins/jquery.ui.nestedSortable.js
|
1460
1460
|
- vendor/assets/javascripts/jquery_plugins/jquery.ui.tabspaging.js
|
1461
1461
|
- vendor/assets/javascripts/jquery_plugins/select2.js
|
1462
1462
|
- 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,119 +0,0 @@
|
|
1
|
-
window.Alchemy = {} if typeof(window.Alchemy) is 'undefined'
|
2
|
-
|
3
|
-
# The admin sitemap Alchemy module
|
4
|
-
Alchemy.Sitemap =
|
5
|
-
|
6
|
-
# Storing some objects.
|
7
|
-
init: (options) ->
|
8
|
-
@search_field = $(".search_input_field")
|
9
|
-
@filter_field_clear = $('.search_field_clear')
|
10
|
-
@display = $('#page_filter_result')
|
11
|
-
@sitemap_wrapper = $('#sitemap-wrapper p.loading')
|
12
|
-
@template = Handlebars.compile($('#sitemap-template').html())
|
13
|
-
list_template_regexp = new RegExp '\/' + options.page_root_id, 'g'
|
14
|
-
list_template_html = $('#sitemap-list').html().replace(list_template_regexp, '/{{id}}')
|
15
|
-
@list_template = Handlebars.compile(list_template_html)
|
16
|
-
@items = null
|
17
|
-
@options = options
|
18
|
-
@watchPagePublicationState()
|
19
|
-
true
|
20
|
-
|
21
|
-
Handlebars.registerPartial('list', list_template_html)
|
22
|
-
|
23
|
-
@fetch()
|
24
|
-
|
25
|
-
# Fetches the sitemap from JSON
|
26
|
-
fetch: (foldingId) ->
|
27
|
-
self = Alchemy.Sitemap
|
28
|
-
|
29
|
-
if foldingId
|
30
|
-
spinner = new Alchemy.Spinner('small')
|
31
|
-
spinTarget = $('#fold_button_' + foldingId)
|
32
|
-
renderTarget = $('#page_' + foldingId)
|
33
|
-
renderTemplate = @list_template
|
34
|
-
pageId = foldingId
|
35
|
-
else
|
36
|
-
spinner = @options.spinner || new Alchemy.Spinner('medium')
|
37
|
-
spinTarget = @sitemap_wrapper
|
38
|
-
renderTarget = @sitemap_wrapper
|
39
|
-
renderTemplate = @template
|
40
|
-
pageId = @options.page_root_id
|
41
|
-
|
42
|
-
spinner.spin(spinTarget[0])
|
43
|
-
|
44
|
-
request = $.ajax url: @options.url, data:
|
45
|
-
id: pageId
|
46
|
-
full: @options.full
|
47
|
-
|
48
|
-
request.done (data) ->
|
49
|
-
# This will also remove the spinner
|
50
|
-
renderTarget.replaceWith(renderTemplate({children: data.pages}))
|
51
|
-
self.items = $(".sitemap_page", '#sitemap')
|
52
|
-
self._observe()
|
53
|
-
|
54
|
-
if self.options.ready
|
55
|
-
self.options.ready()
|
56
|
-
|
57
|
-
request.fail (jqXHR, status) ->
|
58
|
-
console.warn("Request failed: " + status)
|
59
|
-
|
60
|
-
# Filters the sitemap
|
61
|
-
filter: (term) ->
|
62
|
-
results = []
|
63
|
-
self = Alchemy.Sitemap
|
64
|
-
self.items.map ->
|
65
|
-
item = $(this)
|
66
|
-
if term != '' && item.attr('name').toLowerCase().indexOf(term) != -1
|
67
|
-
item.addClass('highlight')
|
68
|
-
item.removeClass('no-match')
|
69
|
-
results.push item
|
70
|
-
else
|
71
|
-
item.addClass('no-match')
|
72
|
-
item.removeClass('highlight')
|
73
|
-
self.filter_field_clear.show()
|
74
|
-
length = results.length
|
75
|
-
if length == 1
|
76
|
-
self.display.show().text("1 #{Alchemy.t('page_found')}")
|
77
|
-
$.scrollTo(results[0], {duration: 400, offset: -80})
|
78
|
-
else if length > 1
|
79
|
-
self.display.show().text("#{length} #{Alchemy.t('pages_found')}")
|
80
|
-
else
|
81
|
-
self.items.removeClass('no-match highlight')
|
82
|
-
self.display.hide()
|
83
|
-
$.scrollTo('0', 400)
|
84
|
-
self.filter_field_clear.hide()
|
85
|
-
|
86
|
-
# Adds onkey up observer to search field
|
87
|
-
_observe: ->
|
88
|
-
filter = @filter
|
89
|
-
@search_field.on 'keyup', ->
|
90
|
-
term = $(this).val()
|
91
|
-
filter(term.toLowerCase())
|
92
|
-
@search_field.on 'focus', ->
|
93
|
-
key.setScope('search')
|
94
|
-
@filter_field_clear.click =>
|
95
|
-
@search_field.val('')
|
96
|
-
filter('')
|
97
|
-
false
|
98
|
-
|
99
|
-
# Handles the page publication date fields
|
100
|
-
watchPagePublicationState: ->
|
101
|
-
$(document).on 'DialogReady.Alchemy', (e, $dialog) ->
|
102
|
-
$public_on_field = $('#page_public_on', $dialog)
|
103
|
-
$public_until_field = $('#page_public_until', $dialog)
|
104
|
-
$publication_date_fields = $('.page-publication-date-fields', $dialog)
|
105
|
-
|
106
|
-
$('#page_public', $dialog).click ->
|
107
|
-
$checkbox = $(this)
|
108
|
-
format = $checkbox.data('date-format')
|
109
|
-
now = new Date()
|
110
|
-
if $checkbox.is(':checked')
|
111
|
-
$publication_date_fields.removeClass('hidden')
|
112
|
-
$public_on_field[0]._flatpickr.setDate(now)
|
113
|
-
else
|
114
|
-
$publication_date_fields.addClass('hidden')
|
115
|
-
$public_on_field.val('')
|
116
|
-
$public_until_field.val('')
|
117
|
-
true
|
118
|
-
|
119
|
-
return
|
@@ -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 %>
|