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.

Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -1
  3. data/.rspec +1 -0
  4. data/CHANGELOG.md +19 -0
  5. data/Rakefile +18 -0
  6. data/alchemy_cms.gemspec +1 -1
  7. data/app/assets/javascripts/alchemy/admin.js +0 -2
  8. data/app/assets/javascripts/alchemy/alchemy.dialog.js.coffee +6 -1
  9. data/app/assets/javascripts/alchemy/page_select.js +13 -8
  10. data/app/assets/javascripts/alchemy/templates/index.js +1 -0
  11. data/app/assets/javascripts/alchemy/templates/page.hbs +17 -7
  12. data/app/assets/javascripts/alchemy/templates/page_folder.hbs +3 -0
  13. data/app/assets/stylesheets/alchemy/page-select.scss +29 -4
  14. data/app/assets/stylesheets/alchemy/sitemap.scss +9 -7
  15. data/app/controllers/alchemy/admin/pages_controller.rb +10 -13
  16. data/app/controllers/alchemy/api/pages_controller.rb +14 -4
  17. data/app/models/alchemy/page.rb +3 -2
  18. data/app/serializers/alchemy/page_serializer.rb +7 -1
  19. data/app/serializers/alchemy/page_tree_serializer.rb +3 -3
  20. data/app/views/alchemy/admin/pages/_form.html.erb +19 -0
  21. data/app/views/alchemy/admin/pages/_new_page_form.html.erb +16 -5
  22. data/app/views/alchemy/admin/pages/_page.html.erb +111 -133
  23. data/app/views/alchemy/admin/pages/_sitemap.html.erb +10 -16
  24. data/app/views/alchemy/admin/pages/_toolbar.html.erb +0 -12
  25. data/app/views/alchemy/admin/pages/edit.html.erb +1 -1
  26. data/app/views/alchemy/admin/pages/index.html.erb +1 -1
  27. data/app/views/alchemy/admin/pages/update.js.erb +7 -0
  28. data/app/views/alchemy/admin/partials/_routes.html.erb +8 -1
  29. data/app/views/alchemy/essences/_essence_page_editor.html.erb +1 -1
  30. data/config/locales/alchemy.en.yml +0 -3
  31. data/config/routes.rb +4 -2
  32. data/lib/alchemy/permissions.rb +0 -1
  33. data/lib/alchemy/version.rb +1 -1
  34. data/package/admin.js +5 -1
  35. data/package/src/page_publication_fields.js +27 -0
  36. data/package/src/page_sorter.js +68 -0
  37. data/package/src/sitemap.js +152 -0
  38. data/package.json +1 -1
  39. metadata +9 -9
  40. data/app/assets/javascripts/alchemy/alchemy.page_sorter.js +0 -24
  41. data/app/assets/javascripts/alchemy/alchemy.sitemap.js.coffee +0 -119
  42. data/app/views/alchemy/admin/pages/fold.js.erb +0 -2
  43. data/app/views/alchemy/admin/pages/sort.html.erb +0 -19
  44. data/vendor/assets/javascripts/jquery_plugins/jquery.ui.nestedSortable.js +0 -434
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 97e1ed1598e179337636198e31cf6d94b85bce3376cd1cb704e6a6e3312224b7
4
- data.tar.gz: 2cfe0ee0fb63eddb1d5de0ac156e9f3abfcc6ac91d6652ebf8aaf80db3da6e61
3
+ metadata.gz: 0d0f346b9e40e791697acdf21d5e1193c72023f8f2570b777683ba2e781b67c1
4
+ data.tar.gz: b0c6a7f6e466bd0b134f9a7fdc76cb88ec1a56d0ca068209fa6b004619ed3a8e
5
5
  SHA512:
6
- metadata.gz: 43f19d474f2e3e153af2b98d3867e7b0151f6ccc3fa4518e88f4b88055fe99cda98a11d53e668e8e5c8485ed17e4a52f0547a8e819f8475ba95c06b6de5f33c1
7
- data.tar.gz: 641ade4c39110add57ddcf2c5a5968541ebafc953f47b9c3f10d6681cfa6d31357794df4b03d488597bc5f56b0e1696a550d57e29da170aac74946bf8b86d167
6
+ metadata.gz: e10199dcdc4b12d01bfebef27d23b752d1dd95c393263dac664c2d5588677aca80113c8b99ca281aefa130592767cc01304ab635d09273c63f3cc575ab2a1313
7
+ data.tar.gz: eaf3f967e1cb5ac4644cddf31ffdfcf3e931107be5508091fe94f61ceb7c096bacc4e39a8203ab8ba1ddf820992abfdae795774f91ac4ff571fc7687f7efd0ba
data/.gitignore CHANGED
@@ -34,7 +34,6 @@ spec/dummy/uploads/
34
34
  .ruby-gemset
35
35
  .ruby-version
36
36
  .env
37
- .rspec
38
37
  node_modules
39
38
  yarn-error.log
40
39
  yarn-debug.log*
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
data/CHANGELOG.md CHANGED
@@ -1,3 +1,22 @@
1
+ ## 5.3.1 (2022-03-11)
2
+
3
+ - Allow all pages in API again ([tvdeyen](https://github.com/tvdeyen))
4
+ - New sortable page tree ([tvdeyen](https://github.com/tvdeyen))
5
+ - Send language_id to Api::PagesController#index so Pages can be restricted to the language of the page. ([dbwinger](https://github.com/dbwinger))
6
+ - Eager load in PageTree serializer ([tvdeyen](https://github.com/tvdeyen))
7
+
8
+ ## 5.3.0 (2022-03-09)
9
+
10
+ - Allow parent page change ([tvdeyen](https://github.com/tvdeyen))
11
+ - Precompile packs during test setup ([tvdeyen](https://github.com/tvdeyen))
12
+ - Rework Sitemap JS ([tvdeyen](https://github.com/tvdeyen))
13
+ - Fix rendering errors in page configure overlay ([tvdeyen](https://github.com/tvdeyen))
14
+
15
+ ## 5.2.7 (2022-03-01)
16
+
17
+ - Fix copying page with descendants to a different language ([dbwinger](https://github.com/dbwinger))
18
+ - Handle copying/pasting global pages ([dbwinger](https://github.com/dbwinger))
19
+
1
20
  ## 5.2.6 (2022-02-28)
2
21
 
3
22
  - Add crop_resize Dragonfly processor ([tvdeyen](https://github.com/tvdeyen))
data/Rakefile CHANGED
@@ -41,12 +41,16 @@ namespace :alchemy do
41
41
  task :prepare do
42
42
  system(
43
43
  <<~BASH
44
+ yarn install && \
45
+ yarn link && \
44
46
  cd spec/dummy && \
45
47
  export RAILS_ENV=test && \
46
48
  bin/rake db:create && \
47
49
  bin/rake db:environment:set && \
48
50
  bin/rake db:migrate:reset && \
49
51
  bin/rails g alchemy:install --skip --skip-demo-files --auto-accept && \
52
+ yarn link @alchemy_cms/admin && \
53
+ RAILS_ENV=test bin/webpack && \
50
54
  cd -
51
55
  BASH
52
56
  ) || fail
@@ -72,4 +76,18 @@ namespace :alchemy do
72
76
  File.delete(backup)
73
77
  end
74
78
  end
79
+
80
+ desc "Release a new Ruby gem and npm package in one command"
81
+ task :release do
82
+ require "json"
83
+ require_relative "lib/alchemy/version"
84
+ package = File.read("package.json")
85
+ unless JSON.parse(package)["version"] == Alchemy.version
86
+ abort "Ruby gem and npm package versions are out of sync! Please fix."
87
+ end
88
+ # Release the Ruby gem with bundler
89
+ Rake::Task["release"].invoke
90
+ # Publish npm package via CLI
91
+ system "npm publish"
92
+ end
75
93
  end
data/alchemy_cms.gemspec CHANGED
@@ -33,7 +33,7 @@ Gem::Specification.new do |gem|
33
33
  gem.add_runtime_dependency 'originator', ['~> 3.1']
34
34
  gem.add_runtime_dependency 'non-stupid-digest-assets', ['~> 1.0.8']
35
35
  gem.add_runtime_dependency 'rails', ['>= 5.2.0', '< 6.1']
36
- gem.add_runtime_dependency 'ransack', ['>= 1.8', '< 2.4.2'] # 2.4.2 dropped Ruby 2.5 support in a patch level release
36
+ gem.add_runtime_dependency 'ransack', ['>= 1.8', '< 3.0']
37
37
  gem.add_runtime_dependency 'request_store', ['~> 1.2']
38
38
  gem.add_runtime_dependency 'responders', ['>= 2.0', '< 4.0']
39
39
  gem.add_runtime_dependency 'sassc-rails', ['~> 2.1']
@@ -37,10 +37,8 @@
37
37
  //= require alchemy/alchemy.link_dialog
38
38
  //= require alchemy/alchemy.list_filter
39
39
  //= require alchemy/alchemy.initializer
40
- //= require alchemy/alchemy.page_sorter
41
40
  //= require alchemy/alchemy.uploader
42
41
  //= require alchemy/alchemy.preview_window
43
- //= require alchemy/alchemy.sitemap
44
42
  //= require alchemy/alchemy.spinner
45
43
  //= require alchemy/alchemy.tinymce
46
44
  //= require alchemy/alchemy.tooltips
@@ -82,7 +82,12 @@ class window.Alchemy.Dialog
82
82
  @dialog_body.hide()
83
83
  @dialog_body.html(data)
84
84
  @init()
85
- @dialog.trigger('DialogReady.Alchemy', @dialog_body)
85
+ @dialog[0].dispatchEvent(new CustomEvent(
86
+ "DialogReady.Alchemy",
87
+ bubbles: true
88
+ detail:
89
+ body: @dialog_body[0]
90
+ ))
86
91
  if @options.ready?
87
92
  @options.ready(@dialog_body)
88
93
  @dialog_body.show('fade', 200)
@@ -1,9 +1,11 @@
1
- $.fn.alchemyPageSelect = function(options) {
1
+ $.fn.alchemyPageSelect = function (options) {
2
2
  var pageTemplate = HandlebarsTemplates.page
3
3
 
4
4
  return this.select2({
5
5
  placeholder: options.placeholder,
6
- allowClear: true,
6
+ allowClear: options.hasOwnProperty("allowClear")
7
+ ? options.allowClear
8
+ : true,
7
9
  minimumInputLength: 3,
8
10
  initSelection: function (_$el, callback) {
9
11
  if (options.initialSelection) {
@@ -12,13 +14,16 @@ $.fn.alchemyPageSelect = function(options) {
12
14
  },
13
15
  ajax: {
14
16
  url: options.url,
15
- datatype: 'json',
17
+ datatype: "json",
16
18
  quietMillis: 300,
17
19
  data: function (term, page) {
18
20
  return {
19
- q: $.extend({
20
- name_cont: term
21
- }, options.query_params),
21
+ q: $.extend(
22
+ {
23
+ name_cont: term
24
+ },
25
+ options.query_params
26
+ ),
22
27
  page: page
23
28
  }
24
29
  },
@@ -34,8 +39,8 @@ $.fn.alchemyPageSelect = function(options) {
34
39
  formatSelection: function (page) {
35
40
  return page.text || page.name
36
41
  },
37
- formatResult: function(page) {
38
- return pageTemplate({page: page})
42
+ formatResult: function (page) {
43
+ return pageTemplate({ page: page })
39
44
  }
40
45
  })
41
46
  }
@@ -2,3 +2,4 @@
2
2
  //= require alchemy/templates/page
3
3
  //= require alchemy/templates/node_folder
4
4
  //= require alchemy/templates/node
5
+ //= require alchemy/templates/page_folder
@@ -1,9 +1,19 @@
1
1
  <div class="page-select--page">
2
- <i class="icon far fa-file fa-lg"></i>
3
- <span class="page-select--page-name">
4
- {{ page.name }}
5
- </span>
6
- <span class="page-select--page-urlname">
7
- {{ page.url_path }}
8
- </span>
2
+ <div class="page-select--top">
3
+ <i class="icon far fa-file fa-lg"></i>
4
+ <span class="page-select--page-name">
5
+ {{ page.name }}
6
+ </span>
7
+ <span class="page-select--page-urlname">
8
+ {{ page.url_path }}
9
+ </span>
10
+ </div>
11
+ <div class="page-select--bottom">
12
+ <span class="page-select--site-name">
13
+ {{ page.site.name }}
14
+ </span>
15
+ <span class="page-select--language-code">
16
+ {{ page.language.name }}
17
+ </span>
18
+ </div>
9
19
  </div>
@@ -0,0 +1,3 @@
1
+ <a class="page_folder" data-page-id="{{ page.id }}">
2
+ <i class="far fa-{{#if page.folded }}plus{{else}}minus{{/if}}-square fa-fw"></i>
3
+ </a>
@@ -7,24 +7,49 @@
7
7
 
8
8
  .page-select--page {
9
9
  display: flex;
10
- align-items: center;
10
+ flex-direction: column;
11
11
 
12
12
  .icon {
13
13
  margin: 0 8px 0 4px;
14
14
 
15
15
  .select2-highlighted & {
16
- color: $white
16
+ color: $white;
17
17
  }
18
18
  }
19
19
  }
20
20
 
21
+ .page-select--top,
22
+ .page-select--bottom {
23
+ display: flex;
24
+ flex-direction: row;
25
+ align-items: center;
26
+ }
27
+
28
+ .page-select--bottom {
29
+ font-size: $small-font-size;
30
+ padding-left: 6 * $default-padding;
31
+ }
32
+
33
+ .page-select--language-code {
34
+ display: inline-block;
35
+ background-color: $medium-gray;
36
+ margin-left: auto;
37
+ border-radius: $default-border-radius;
38
+ padding: $default-padding / 2 $default-padding;
39
+
40
+ .select2-highlighted & {
41
+ color: $select-hover-bg-color;
42
+ background-color: white;
43
+ }
44
+ }
45
+
21
46
  .page-select--page-urlname {
22
47
  margin-left: auto;
23
- padding: $default-padding 2*$default-padding;
48
+ padding: $default-padding 2 * $default-padding;
24
49
  color: $dark-gray;
25
50
  font-size: $small-font-size;
26
51
 
27
52
  .select2-highlighted & {
28
- color: $white
53
+ color: $white;
29
54
  }
30
55
  }
@@ -23,7 +23,7 @@ $sitemap-url-xlarge-width: 350px;
23
23
 
24
24
  #sitemap-wrapper {
25
25
  position: relative;
26
- min-height: calc(100vh - 96px);
26
+ min-height: calc(100vh - 148px);
27
27
  }
28
28
 
29
29
  .sitemap_pagename_link {
@@ -142,18 +142,16 @@ $sitemap-url-xlarge-width: 350px;
142
142
  #sitemap {
143
143
  padding: 0 0 104px 0;
144
144
 
145
- &.sorting {
146
- padding-top: 100px;
147
-
148
- .page_icon {
149
- cursor: move;
150
- }
145
+ .handle {
146
+ cursor: move;
151
147
  }
152
148
 
153
149
  .page_folder {
154
150
  position: absolute;
155
151
  left: -23px;
156
152
  top: 0;
153
+ width: 16px;
154
+ height: $sitemap-line-height;
157
155
  }
158
156
 
159
157
  .placeholder {
@@ -258,3 +256,7 @@ $sitemap-url-xlarge-width: 350px;
258
256
  }
259
257
  }
260
258
  }
259
+
260
+ #search_field_clear {
261
+ cursor: pointer;
262
+ }
@@ -7,7 +7,7 @@ module Alchemy
7
7
 
8
8
  helper "alchemy/pages"
9
9
 
10
- before_action :load_resource, except: [:index, :flush, :new, :order, :create, :copy_language_tree, :link, :sort]
10
+ before_action :load_resource, except: [:index, :flush, :new, :order, :create, :copy_language_tree, :link]
11
11
 
12
12
  authorize_resource class: Alchemy::Page, except: [:index, :tree]
13
13
 
@@ -21,7 +21,7 @@ module Alchemy
21
21
  except: [:show]
22
22
 
23
23
  before_action :set_root_page,
24
- only: [:index, :show, :sort, :order]
24
+ only: [:index, :show, :order]
25
25
 
26
26
  before_action :run_on_page_layout_callbacks,
27
27
  if: :run_on_page_layout_callbacks?,
@@ -128,6 +128,7 @@ module Alchemy
128
128
  def update
129
129
  # stores old page_layout value, because unfurtunally rails @page.changes does not work here.
130
130
  @old_page_layout = @page.page_layout
131
+ @old_parent_id = @page.parent_id
131
132
  if @page.update(page_params)
132
133
  @notice = Alchemy.t("Page saved", name: @page.name)
133
134
  @while_page_edit = request.referer.include?("edit")
@@ -136,7 +137,7 @@ module Alchemy
136
137
  @tree = serialized_page_tree
137
138
  end
138
139
  else
139
- configure
140
+ render :configure
140
141
  end
141
142
  end
142
143
 
@@ -172,9 +173,7 @@ module Alchemy
172
173
  def fold
173
174
  # @page is fetched via before filter
174
175
  @page.fold!(current_alchemy_user.id, !@page.folded?(current_alchemy_user.id))
175
- respond_to do |format|
176
- format.js
177
- end
176
+ render json: serialized_page_tree
178
177
  end
179
178
 
180
179
  # Leaves the page editing mode and unlocks the page for other users
@@ -219,10 +218,6 @@ module Alchemy
219
218
  redirect_to admin_pages_path
220
219
  end
221
220
 
222
- def sort
223
- @sorting = true
224
- end
225
-
226
221
  # Receives a JSON object representing a language tree to be ordered
227
222
  # and updates all pages in that language structure to their correct indexes
228
223
  def order
@@ -404,9 +399,11 @@ module Alchemy
404
399
  end
405
400
 
406
401
  def serialized_page_tree
407
- PageTreeSerializer.new(@page, ability: current_ability,
408
- user: current_alchemy_user,
409
- full: params[:full] == "true")
402
+ PageTreeSerializer.new(
403
+ @page,
404
+ ability: current_ability,
405
+ user: current_alchemy_user,
406
+ )
410
407
  end
411
408
 
412
409
  def load_languages_and_layouts
@@ -2,17 +2,19 @@
2
2
 
3
3
  module Alchemy
4
4
  class Api::PagesController < Api::BaseController
5
+ serialization_scope :current_ability
5
6
  before_action :load_page, only: [:show]
6
7
 
7
8
  # Returns all pages as json object
8
9
  #
9
10
  def index
10
11
  # Fix for cancancan not able to merge multiple AR scopes for logged in users
11
- if cannot? :edit_content, Alchemy::Page
12
- @pages = Alchemy::Page.accessible_by(current_ability, :index)
13
- @pages = @pages.where(language: Language.current)
12
+ if can? :edit_content, Alchemy::Page
13
+ @pages = Alchemy::Page.all
14
14
  else
15
- @pages = Language.current&.pages.presence || Alchemy::Page.none
15
+ language = Alchemy::Language.find_by(id: params[:language_id]) || Alchemy::Language.current
16
+ @pages = Alchemy::Page.accessible_by(current_ability, :index)
17
+ @pages = @pages.where(language: language)
16
18
  end
17
19
  @pages = @pages.includes(*page_includes)
18
20
  @pages = @pages.ransack(params[:q]).result
@@ -49,6 +51,14 @@ module Alchemy
49
51
  respond_with @page
50
52
  end
51
53
 
54
+ def move
55
+ @page = Page.find(params[:id])
56
+ authorize! :update, @page
57
+ target_parent_page = Page.find(params[:target_parent_id])
58
+ @page.move_to_child_with_index(target_parent_page, params[:new_position])
59
+ render json: @page, serializer: PageSerializer
60
+ end
61
+
52
62
  private
53
63
 
54
64
  def load_page
@@ -217,8 +217,8 @@ module Alchemy
217
217
 
218
218
  def copy_and_paste(source, new_parent, new_name)
219
219
  page = copy(source, {
220
- parent_id: new_parent.id,
221
- language: new_parent.language,
220
+ parent: new_parent,
221
+ language: new_parent&.language,
222
222
  name: new_name,
223
223
  title: new_name,
224
224
  })
@@ -415,6 +415,7 @@ module Alchemy
415
415
  next if child == new_parent
416
416
 
417
417
  new_child = Page.copy(child, {
418
+ parent_id: new_parent.id,
418
419
  language_id: new_parent.language_id,
419
420
  language_code: new_parent.language_code,
420
421
  })
@@ -14,8 +14,14 @@ module Alchemy
14
14
  :created_at,
15
15
  :updated_at,
16
16
  :status,
17
- :url_path
17
+ :url_path,
18
+ :parent_id
18
19
 
19
20
  has_many :elements
21
+
22
+ with_options if: -> { scope.can?(:edit_content, object) } do
23
+ belongs_to :site
24
+ belongs_to :language
25
+ end
20
26
  end
21
27
  end
@@ -3,13 +3,13 @@
3
3
  module Alchemy
4
4
  class PageTreeSerializer < BaseSerializer
5
5
  def attributes
6
- {"pages" => nil}
6
+ { "pages" => nil }
7
7
  end
8
8
 
9
9
  def pages
10
10
  tree = []
11
- path = [{id: object.parent_id, children: tree}]
12
- page_list = object.self_and_descendants
11
+ path = [{ id: object.parent_id, children: tree }]
12
+ page_list = object.self_and_descendants.includes(language: :site)
13
13
  base_level = object.level - 1
14
14
  # Load folded pages in advance
15
15
  folded_user_pages = FoldedPage.folded_for_user(opts[:user]).pluck(:page_id)
@@ -1,4 +1,8 @@
1
1
  <%= alchemy_form_for [:admin, @page], class: 'edit_page' do |f| %>
2
+ <% unless @page.language_root? || @page.layoutpage %>
3
+ <%= f.input :parent_id, required: true, input_html: { class: 'alchemy_selectbox' } %>
4
+ <% end %>
5
+
2
6
  <%= f.input :page_layout,
3
7
  collection: @page_layouts,
4
8
  label: page_layout_label(@page),
@@ -43,3 +47,18 @@
43
47
 
44
48
  <%= f.submit Alchemy.t(:save) %>
45
49
  <% end %>
50
+
51
+ <script>
52
+ $('#page_parent_id').alchemyPageSelect({
53
+ placeholder: "<%= Alchemy.t(:search_page) %>",
54
+ url: "<%= alchemy.api_pages_path %>",
55
+ allowClear: false,
56
+ <% if @page.parent %>
57
+ initialSelection: {
58
+ id: <%= @page.parent.id %>,
59
+ text: "<%= @page.parent.name %>",
60
+ url_path: "<%= @page.parent.url_path %>"
61
+ }
62
+ <% end %>
63
+ })
64
+ </script>
@@ -3,11 +3,7 @@
3
3
  <%= f.hidden_field(:parent_id) %>
4
4
  <% else %>
5
5
  <% @page.parent = @current_language.root_page %>
6
- <%= f.input :parent_id,
7
- collection: @current_language.pages.contentpages,
8
- label_method: :name,
9
- value_method: :id,
10
- input_html: { class: "alchemy_selectbox" } %>
6
+ <%= f.input :parent_id, as: :string, input_html: { class: 'alchemy_selectbox' } %>
11
7
  <% end %>
12
8
  <%= f.hidden_field(:language_id) %>
13
9
  <%= f.hidden_field(:layoutpage) %>
@@ -21,3 +17,18 @@
21
17
  <%= f.input :name %>
22
18
  <%= f.submit Alchemy.t(:create) %>
23
19
  <% end %>
20
+
21
+ <script>
22
+ $('input[type="text"]#page_parent_id').alchemyPageSelect({
23
+ placeholder: "<%= Alchemy.t(:search_page) %>",
24
+ url: "<%= alchemy.api_pages_path %>",
25
+ allowClear: false,
26
+ <% if @page.parent %>
27
+ initialSelection: {
28
+ id: <%= @page.parent.id %>,
29
+ text: "<%= @page.parent.name %>",
30
+ url_path: "<%= @page.parent.url_path %>"
31
+ }
32
+ <% end %>
33
+ })
34
+ </script>