alchemy_cms 5.2.6 → 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.
- checksums.yaml +4 -4
- data/.gitignore +0 -1
- data/.rspec +1 -0
- data/CHANGELOG.md +19 -0
- data/Rakefile +18 -0
- data/alchemy_cms.gemspec +1 -1
- 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/page-select.scss +29 -4
- data/app/assets/stylesheets/alchemy/sitemap.scss +9 -7
- data/app/controllers/alchemy/admin/pages_controller.rb +10 -13
- data/app/controllers/alchemy/api/pages_controller.rb +14 -4
- data/app/models/alchemy/page.rb +3 -2
- data/app/serializers/alchemy/page_serializer.rb +7 -1
- data/app/serializers/alchemy/page_tree_serializer.rb +3 -3
- 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 -0
- 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 -3
- data/config/routes.rb +4 -2
- data/lib/alchemy/permissions.rb +0 -1
- data/lib/alchemy/version.rb +1 -1
- data/package/admin.js +5 -1
- data/package/src/page_publication_fields.js +27 -0
- data/package/src/page_sorter.js +68 -0
- data/package/src/sitemap.js +152 -0
- data/package.json +1 -1
- metadata +9 -9
- 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/vendor/assets/javascripts/jquery_plugins/jquery.ui.nestedSortable.js +0 -434
@@ -0,0 +1,152 @@
|
|
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"
|
5
|
+
|
6
|
+
export default class Sitemap {
|
7
|
+
// Storing some objects.
|
8
|
+
constructor(options) {
|
9
|
+
const list_template_html = document
|
10
|
+
.getElementById("sitemap-list")
|
11
|
+
.innerHTML.replace(/__ID__/g, "{{id}}")
|
12
|
+
this.search_field = document.querySelector(".search_input_field")
|
13
|
+
this.filter_field_clear = document.querySelector(".search_field_clear")
|
14
|
+
this.filter_field_clear.removeAttribute("href")
|
15
|
+
this.display = document.getElementById("page_filter_result")
|
16
|
+
this.sitemap_wrapper = document.getElementById("sitemap-wrapper")
|
17
|
+
this.template = Handlebars.compile(
|
18
|
+
document.getElementById("sitemap-template").innerHTML
|
19
|
+
)
|
20
|
+
this.list_template = Handlebars.compile(list_template_html)
|
21
|
+
this.items = null
|
22
|
+
this.options = options
|
23
|
+
Handlebars.registerPartial("list", list_template_html)
|
24
|
+
this.load(options.page_root_id)
|
25
|
+
}
|
26
|
+
|
27
|
+
// Loads the sitemap
|
28
|
+
load(pageId) {
|
29
|
+
const spinner = new Alchemy.Spinner("medium")
|
30
|
+
const spinTarget = this.sitemap_wrapper
|
31
|
+
spinTarget.innerHTML = ""
|
32
|
+
spinner.spin(spinTarget)
|
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)
|
40
|
+
}
|
41
|
+
|
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)
|
54
|
+
|
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
|
+
)
|
68
|
+
}
|
69
|
+
|
70
|
+
// Renders the sitemap
|
71
|
+
render(data) {
|
72
|
+
const renderTarget = this.sitemap_wrapper
|
73
|
+
const renderTemplate = this.template
|
74
|
+
|
75
|
+
renderTarget.innerHTML = renderTemplate({ children: data.pages })
|
76
|
+
this.items = document
|
77
|
+
.getElementById("sitemap")
|
78
|
+
.querySelectorAll(".sitemap_page")
|
79
|
+
this.sitemap_wrapper = document.getElementById("sitemap-wrapper")
|
80
|
+
this._observe()
|
81
|
+
PageSorter()
|
82
|
+
}
|
83
|
+
|
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()
|
91
|
+
}
|
92
|
+
|
93
|
+
// Filters the sitemap
|
94
|
+
filter(term) {
|
95
|
+
const results = []
|
96
|
+
|
97
|
+
this.items.forEach(function (item) {
|
98
|
+
if (
|
99
|
+
term !== "" &&
|
100
|
+
item.getAttribute("name").toLowerCase().indexOf(term) !== -1
|
101
|
+
) {
|
102
|
+
item.classList.add("highlight")
|
103
|
+
item.classList.remove("no-match")
|
104
|
+
results.push(item)
|
105
|
+
} else {
|
106
|
+
item.classList.add("no-match")
|
107
|
+
item.classList.remove("highlight")
|
108
|
+
}
|
109
|
+
})
|
110
|
+
this.filter_field_clear.style.display = "inline-block"
|
111
|
+
const { length } = results
|
112
|
+
|
113
|
+
if (length === 1) {
|
114
|
+
this.display.style.display = "block"
|
115
|
+
this.display.innerText = `1 ${Alchemy.t("page_found")}`
|
116
|
+
results[0].scrollIntoView({ behavior: "smooth", block: "center" })
|
117
|
+
} else if (length > 1) {
|
118
|
+
this.display.style.display = "block"
|
119
|
+
this.display.innerText = `${length} ${Alchemy.t("pages_found")}`
|
120
|
+
} else {
|
121
|
+
this.items.forEach((item) =>
|
122
|
+
item.classList.remove("no-match", "highlight")
|
123
|
+
)
|
124
|
+
this.display.style.display = "none"
|
125
|
+
window.scrollTo({
|
126
|
+
top: 0,
|
127
|
+
left: 0,
|
128
|
+
behavior: "smooth"
|
129
|
+
})
|
130
|
+
this.filter_field_clear.style.display = "none"
|
131
|
+
}
|
132
|
+
}
|
133
|
+
|
134
|
+
// Adds onkey up observer to search field
|
135
|
+
_observe() {
|
136
|
+
this.search_field.addEventListener("keyup", (evt) => {
|
137
|
+
const term = evt.target.value
|
138
|
+
this.filter(term.toLowerCase())
|
139
|
+
})
|
140
|
+
this.search_field.addEventListener("focus", () => key.setScope("search"))
|
141
|
+
this.filter_field_clear.addEventListener("click", () => {
|
142
|
+
this.search_field.value = ""
|
143
|
+
this.filter("")
|
144
|
+
return false
|
145
|
+
})
|
146
|
+
}
|
147
|
+
|
148
|
+
errorHandler(error) {
|
149
|
+
Alchemy.growl(error.message || error, "error")
|
150
|
+
console.error(error)
|
151
|
+
}
|
152
|
+
}
|
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.
|
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-
|
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
|
@@ -270,7 +270,7 @@ dependencies:
|
|
270
270
|
version: '1.8'
|
271
271
|
- - "<"
|
272
272
|
- !ruby/object:Gem::Version
|
273
|
-
version:
|
273
|
+
version: '3.0'
|
274
274
|
type: :runtime
|
275
275
|
prerelease: false
|
276
276
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -280,7 +280,7 @@ dependencies:
|
|
280
280
|
version: '1.8'
|
281
281
|
- - "<"
|
282
282
|
- !ruby/object:Gem::Version
|
283
|
-
version:
|
283
|
+
version: '3.0'
|
284
284
|
- !ruby/object:Gem::Dependency
|
285
285
|
name: request_store
|
286
286
|
requirement: !ruby/object:Gem::Requirement
|
@@ -590,6 +590,7 @@ files:
|
|
590
590
|
- ".hound.yml"
|
591
591
|
- ".localeapp/config.rb"
|
592
592
|
- ".prettierrc"
|
593
|
+
- ".rspec"
|
593
594
|
- ".rubocop.yml"
|
594
595
|
- ".yardopts"
|
595
596
|
- CHANGELOG.md
|
@@ -632,10 +633,8 @@ files:
|
|
632
633
|
- app/assets/javascripts/alchemy/alchemy.initializer.js.coffee
|
633
634
|
- app/assets/javascripts/alchemy/alchemy.link_dialog.js.coffee
|
634
635
|
- app/assets/javascripts/alchemy/alchemy.list_filter.js.coffee
|
635
|
-
- app/assets/javascripts/alchemy/alchemy.page_sorter.js
|
636
636
|
- app/assets/javascripts/alchemy/alchemy.preview.js.coffee
|
637
637
|
- app/assets/javascripts/alchemy/alchemy.preview_window.js.coffee
|
638
|
-
- app/assets/javascripts/alchemy/alchemy.sitemap.js.coffee
|
639
638
|
- app/assets/javascripts/alchemy/alchemy.spinner.js
|
640
639
|
- app/assets/javascripts/alchemy/alchemy.string_extension.js.coffee
|
641
640
|
- app/assets/javascripts/alchemy/alchemy.tinymce.js.coffee
|
@@ -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
|
@@ -1189,6 +1187,9 @@ files:
|
|
1189
1187
|
- package/src/__tests__/i18n.spec.js
|
1190
1188
|
- package/src/i18n.js
|
1191
1189
|
- package/src/node_tree.js
|
1190
|
+
- package/src/page_publication_fields.js
|
1191
|
+
- package/src/page_sorter.js
|
1192
|
+
- package/src/sitemap.js
|
1192
1193
|
- package/src/translations.js
|
1193
1194
|
- package/src/utils/__tests__/ajax.spec.js
|
1194
1195
|
- package/src/utils/__tests__/events.spec.js
|
@@ -1213,7 +1214,6 @@ files:
|
|
1213
1214
|
- vendor/assets/javascripts/flatpickr/flatpickr.min.js
|
1214
1215
|
- vendor/assets/javascripts/jquery_plugins/jquery.Jcrop.min.js
|
1215
1216
|
- vendor/assets/javascripts/jquery_plugins/jquery.scrollTo.min.js
|
1216
|
-
- vendor/assets/javascripts/jquery_plugins/jquery.ui.nestedSortable.js
|
1217
1217
|
- vendor/assets/javascripts/jquery_plugins/jquery.ui.tabspaging.js
|
1218
1218
|
- vendor/assets/javascripts/jquery_plugins/select2.js
|
1219
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,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 %>
|