alchemy_cms 4.3.2 → 4.4.0

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.
Files changed (139) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +92 -0
  3. data/.gitignore +1 -0
  4. data/CHANGELOG.md +59 -2
  5. data/Gemfile +6 -5
  6. data/README.md +7 -6
  7. data/alchemy_cms.gemspec +4 -2
  8. data/app/assets/config/alchemy_manifest.js +15 -0
  9. data/app/assets/javascripts/alchemy/admin.js +1 -0
  10. data/app/assets/javascripts/alchemy/alchemy.base.js.coffee +1 -13
  11. data/app/assets/javascripts/alchemy/alchemy.i18n.js.coffee +1 -1
  12. data/app/assets/javascripts/alchemy/alchemy.link_dialog.js.coffee +84 -87
  13. data/app/assets/javascripts/alchemy/alchemy.preview.js.coffee +0 -4
  14. data/app/assets/javascripts/alchemy/alchemy.sitemap.js.coffee +1 -1
  15. data/app/assets/javascripts/alchemy/alchemy.tinymce.js.coffee +2 -2
  16. data/app/assets/javascripts/alchemy/page_select.js +41 -0
  17. data/app/assets/javascripts/alchemy/templates/index.js +1 -0
  18. data/app/assets/javascripts/alchemy/templates/page.hbs +9 -0
  19. data/app/assets/stylesheets/alchemy/_mixins.scss +11 -1
  20. data/app/assets/stylesheets/alchemy/admin.scss +3 -0
  21. data/app/assets/stylesheets/alchemy/elements.scss +1 -0
  22. data/app/assets/stylesheets/alchemy/forms.scss +6 -5
  23. data/app/assets/stylesheets/alchemy/labels.scss +6 -0
  24. data/app/assets/stylesheets/alchemy/nodes.scss +154 -0
  25. data/app/assets/stylesheets/alchemy/page-select.scss +30 -0
  26. data/app/assets/stylesheets/alchemy/selects.scss +39 -22
  27. data/app/assets/stylesheets/alchemy/sitemap.scss +0 -33
  28. data/app/assets/stylesheets/alchemy/tags.scss +0 -3
  29. data/app/controllers/alchemy/admin/base_controller.rb +1 -0
  30. data/app/controllers/alchemy/admin/elements_controller.rb +24 -11
  31. data/app/controllers/alchemy/admin/languages_controller.rb +5 -0
  32. data/app/controllers/alchemy/admin/nodes_controller.rb +43 -0
  33. data/app/controllers/alchemy/admin/pages_controller.rb +1 -21
  34. data/app/controllers/alchemy/admin/resources_controller.rb +1 -1
  35. data/app/controllers/alchemy/admin/tags_controller.rb +1 -2
  36. data/app/controllers/alchemy/api/contents_controller.rb +17 -2
  37. data/app/controllers/alchemy/api/elements_controller.rb +26 -1
  38. data/app/controllers/alchemy/api/pages_controller.rb +78 -7
  39. data/app/controllers/alchemy/messages_controller.rb +23 -8
  40. data/app/helpers/alchemy/admin/contents_helper.rb +1 -1
  41. data/app/helpers/alchemy/admin/elements_helper.rb +6 -0
  42. data/app/helpers/alchemy/admin/essences_helper.rb +23 -4
  43. data/app/helpers/alchemy/elements_block_helper.rb +11 -3
  44. data/app/helpers/alchemy/elements_helper.rb +3 -3
  45. data/app/helpers/alchemy/essences_helper.rb +36 -9
  46. data/app/helpers/alchemy/pages_helper.rb +29 -0
  47. data/app/models/alchemy/content.rb +1 -1
  48. data/app/models/alchemy/element.rb +20 -8
  49. data/app/models/alchemy/element/element_contents.rb +6 -4
  50. data/app/models/alchemy/element/presenters.rb +2 -2
  51. data/app/models/alchemy/essence_page.rb +29 -0
  52. data/app/models/alchemy/essence_picture.rb +8 -3
  53. data/app/models/alchemy/language.rb +10 -2
  54. data/app/models/alchemy/node.rb +48 -0
  55. data/app/models/alchemy/page.rb +74 -3
  56. data/app/models/alchemy/page/page_elements.rb +12 -4
  57. data/app/models/alchemy/page/page_natures.rb +6 -0
  58. data/app/models/alchemy/page/page_scopes.rb +1 -1
  59. data/app/models/alchemy/picture.rb +5 -1
  60. data/app/models/concerns/alchemy/content_touching.rb +1 -1
  61. data/app/serializers/alchemy/element_serializer.rb +7 -1
  62. data/app/serializers/alchemy/page_serializer.rb +0 -4
  63. data/app/views/alchemy/_menubar.html.erb +1 -1
  64. data/app/views/alchemy/admin/elements/_element.html.erb +18 -2
  65. data/app/views/alchemy/admin/leave.html.erb +1 -1
  66. data/app/views/alchemy/admin/nodes/_form.html.erb +39 -0
  67. data/app/views/alchemy/admin/nodes/_node.html.erb +87 -0
  68. data/app/views/alchemy/admin/nodes/edit.html.erb +1 -0
  69. data/app/views/alchemy/admin/nodes/index.html.erb +58 -0
  70. data/app/views/alchemy/admin/nodes/new.html.erb +1 -0
  71. data/app/views/alchemy/admin/pages/_anchor_link.html.erb +22 -0
  72. data/app/views/alchemy/admin/pages/_form.html.erb +1 -1
  73. data/app/views/alchemy/admin/pages/_internal_link.html.erb +7 -11
  74. data/app/views/alchemy/admin/pages/_menu_fields.html.erb +33 -0
  75. data/app/views/alchemy/admin/pages/_sitemap.html.erb +0 -7
  76. data/app/views/alchemy/admin/pages/link.html.erb +4 -0
  77. data/app/views/alchemy/admin/partials/_language_tree_select.html.erb +7 -3
  78. data/app/views/alchemy/admin/partials/_routes.html.erb +3 -3
  79. data/app/views/alchemy/essences/_essence_boolean_view.html.erb +1 -0
  80. data/app/views/alchemy/essences/_essence_date_view.html.erb +1 -0
  81. data/app/views/alchemy/essences/_essence_file_view.html.erb +1 -0
  82. data/app/views/alchemy/essences/_essence_html_view.html.erb +1 -0
  83. data/app/views/alchemy/essences/_essence_link_view.html.erb +1 -0
  84. data/app/views/alchemy/essences/_essence_page_editor.html.erb +23 -0
  85. data/app/views/alchemy/essences/_essence_page_view.html.erb +5 -0
  86. data/app/views/alchemy/essences/_essence_picture_editor.html.erb +2 -0
  87. data/app/views/alchemy/essences/_essence_picture_view.html.erb +1 -0
  88. data/app/views/alchemy/essences/_essence_richtext_view.html.erb +1 -0
  89. data/app/views/alchemy/essences/_essence_select_editor.html.erb +1 -0
  90. data/app/views/alchemy/essences/_essence_select_view.html.erb +1 -0
  91. data/app/views/alchemy/essences/_essence_text_editor.html.erb +3 -0
  92. data/app/views/alchemy/essences/_essence_text_view.html.erb +1 -0
  93. data/config/alchemy/modules.yml +13 -4
  94. data/config/initializers/assets.rb +1 -13
  95. data/config/locales/alchemy.en.yml +27 -9
  96. data/config/routes.rb +11 -3
  97. data/db/migrate/20191016073858_create_alchemy_essence_pages.rb +8 -0
  98. data/db/migrate/20191029212236_create_alchemy_nodes.rb +24 -0
  99. data/lib/alchemy/admin/locale.rb +1 -1
  100. data/lib/alchemy/auth_accessors.rb +8 -2
  101. data/lib/alchemy/cache_digests/template_tracker.rb +8 -5
  102. data/lib/alchemy/elements_finder.rb +17 -14
  103. data/lib/alchemy/engine.rb +4 -0
  104. data/lib/alchemy/essence.rb +40 -2
  105. data/lib/alchemy/permissions.rb +2 -0
  106. data/lib/alchemy/tasks/tidy.rb +1 -1
  107. data/lib/alchemy/test_support/essence_shared_examples.rb +25 -8
  108. data/lib/alchemy/test_support/factories/essence_page_factory.rb +10 -0
  109. data/lib/alchemy/test_support/factories/essence_picture_factory.rb +5 -0
  110. data/lib/alchemy/test_support/factories/node_factory.rb +21 -0
  111. data/lib/alchemy/version.rb +1 -1
  112. data/lib/rails/generators/alchemy/elements/elements_generator.rb +0 -1
  113. data/lib/rails/generators/alchemy/elements/templates/view.html.erb +3 -3
  114. data/lib/rails/generators/alchemy/elements/templates/view.html.haml +3 -3
  115. data/lib/rails/generators/alchemy/elements/templates/view.html.slim +3 -3
  116. data/lib/rails/generators/alchemy/install/files/{_article_view.html.erb → _article.html.erb} +2 -2
  117. data/lib/rails/generators/alchemy/install/files/application.html.erb +13 -10
  118. data/lib/rails/generators/alchemy/install/install_generator.rb +2 -11
  119. data/lib/rails/generators/alchemy/menus/menus_generator.rb +24 -0
  120. data/lib/rails/generators/alchemy/menus/templates/node.html.erb +19 -0
  121. data/lib/rails/generators/alchemy/menus/templates/node.html.haml +16 -0
  122. data/lib/rails/generators/alchemy/menus/templates/node.html.slim +16 -0
  123. data/lib/rails/generators/alchemy/menus/templates/wrapper.html.erb +8 -0
  124. data/lib/rails/generators/alchemy/menus/templates/wrapper.html.haml +6 -0
  125. data/lib/rails/generators/alchemy/menus/templates/wrapper.html.slim +6 -0
  126. data/lib/rails/generators/alchemy/views/views_generator.rb +1 -1
  127. data/lib/tasks/alchemy/convert.rake +60 -0
  128. metadata +79 -20
  129. data/.rspec +0 -1
  130. data/.travis.yml +0 -28
  131. data/app/models/alchemy/page/page_users.rb +0 -60
  132. data/app/views/alchemy/admin/elements/list.html.erb +0 -16
  133. data/app/views/alchemy/admin/pages/_page_for_links.html.erb +0 -53
  134. data/lib/rails/generators/alchemy/elements/templates/editor.html.erb +0 -9
  135. data/lib/rails/generators/alchemy/elements/templates/editor.html.haml +0 -8
  136. data/lib/rails/generators/alchemy/elements/templates/editor.html.slim +0 -8
  137. data/lib/rails/generators/alchemy/install/files/_article_editor.html.erb +0 -5
  138. data/lib/rails/generators/alchemy/install/files/alchemy.de.yml +0 -31
  139. data/lib/rails/generators/alchemy/install/files/alchemy.es.yml +0 -31
@@ -95,6 +95,7 @@ module Alchemy
95
95
  :alchemy_admin_attachments,
96
96
  :alchemy_admin_dashboard,
97
97
  :alchemy_admin_layoutpages,
98
+ :alchemy_admin_nodes,
98
99
  :alchemy_admin_pages,
99
100
  :alchemy_admin_pictures,
100
101
  :alchemy_admin_tags,
@@ -116,6 +117,7 @@ module Alchemy
116
117
  can :manage, Alchemy::EssenceFile
117
118
  can :manage, Alchemy::EssencePicture
118
119
  can :manage, Alchemy::LegacyPageUrl
120
+ can :manage, Alchemy::Node
119
121
  can :read, Alchemy::Picture
120
122
  can [:read, :autocomplete], Alchemy::Tag
121
123
  can(:edit_content, Alchemy::Page) { |p| p.editable_by?(@user) }
@@ -45,7 +45,7 @@ module Alchemy
45
45
 
46
46
  def remove_orphaned_elements
47
47
  puts "\n## Removing orphaned elements"
48
- elements = Alchemy::Element.unscoped.all
48
+ elements = Alchemy::Element.unscoped.not_nested
49
49
  if elements.any?
50
50
  orphaned_elements = elements.select do |element|
51
51
  element.page.nil? && element.page_id.present?
@@ -1,16 +1,33 @@
1
- require 'rails_helper'
1
+ # frozen_string_literal: true
2
2
 
3
- shared_examples_for "an essence" do
3
+ require 'shoulda-matchers'
4
+ require 'alchemy/test_support/factories/page_factory'
5
+ require 'alchemy/test_support/factories/element_factory'
6
+ require 'alchemy/test_support/factories/content_factory'
7
+
8
+ RSpec.shared_examples_for "an essence" do
4
9
  let(:element) { Alchemy::Element.new }
5
10
  let(:content) { Alchemy::Content.new(name: 'foo') }
6
11
  let(:content_definition) { {'name' => 'foo'} }
7
12
 
13
+ describe 'eager loading' do
14
+ before do
15
+ 2.times { described_class.create! }
16
+ end
17
+
18
+ it 'does not throw error if eager loaded' do
19
+ expect {
20
+ described_class.all.includes(:ingredient_association).to_a
21
+ }.to_not raise_error
22
+ end
23
+ end
24
+
8
25
  it "touches the content after update" do
9
- element = create(:alchemy_element)
10
- content = create(:alchemy_content, element: element, essence: essence, essence_type: essence.class.name)
26
+ element = FactoryBot.create(:alchemy_element)
27
+ content = FactoryBot.create(:alchemy_content, element: element, essence: essence, essence_type: essence.class.name)
11
28
 
12
29
  content.update_column(:updated_at, 3.days.ago)
13
- content.essence.update_attributes(essence.ingredient_column.to_sym => ingredient_value)
30
+ content.essence.update(essence.ingredient_column.to_sym => ingredient_value)
14
31
 
15
32
  content.reload
16
33
  expect(content.updated_at).to be_within(3.seconds).of(Time.current)
@@ -153,7 +170,7 @@ shared_examples_for "an essence" do
153
170
 
154
171
  describe 'uniqueness' do
155
172
  before do
156
- allow(essence).to receive(:element).and_return(build_stubbed(:alchemy_element))
173
+ allow(essence).to receive(:element).and_return(FactoryBot.build_stubbed(:alchemy_element))
157
174
  essence.update(essence.ingredient_column.to_sym => ingredient_value)
158
175
  end
159
176
 
@@ -256,8 +273,8 @@ shared_examples_for "an essence" do
256
273
  end
257
274
 
258
275
  describe 'essence relations' do
259
- let(:page) { create(:alchemy_page, :restricted) }
260
- let(:element) { create(:alchemy_element) }
276
+ let(:page) { FactoryBot.create(:alchemy_page, :restricted) }
277
+ let(:element) { FactoryBot.create(:alchemy_element) }
261
278
 
262
279
  it "registers itself on page as essence relation" do
263
280
  expect(page.respond_to?(essence.class.model_name.route_key)).to be(true)
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'factory_bot'
4
+ require 'alchemy/test_support/factories/page_factory'
5
+
6
+ FactoryBot.define do
7
+ factory :alchemy_essence_page, class: 'Alchemy::EssencePage' do
8
+ page factory: :alchemy_page
9
+ end
10
+ end
@@ -1,10 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'factory_bot'
4
+ require 'alchemy/test_support/factories/content_factory'
4
5
  require 'alchemy/test_support/factories/picture_factory'
5
6
 
6
7
  FactoryBot.define do
7
8
  factory :alchemy_essence_picture, class: 'Alchemy::EssencePicture' do
8
9
  picture factory: :alchemy_picture
10
+
11
+ trait :with_content do
12
+ association :content, factory: :alchemy_content
13
+ end
9
14
  end
10
15
  end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'factory_bot'
4
+ require 'alchemy/test_support/factories/language_factory'
5
+ require 'alchemy/test_support/factories/page_factory'
6
+
7
+ FactoryBot.define do
8
+ factory :alchemy_node, class: 'Alchemy::Node' do
9
+ language { Alchemy::Language.default }
10
+ name { 'A Node' }
11
+
12
+ trait :with_page do
13
+ association :page, factory: :alchemy_page
14
+ name { nil }
15
+ end
16
+
17
+ trait :with_url do
18
+ url { 'https://example.com' }
19
+ end
20
+ end
21
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Alchemy
4
- VERSION = "4.3.2"
4
+ VERSION = "4.4.0"
5
5
 
6
6
  def self.version
7
7
  VERSION
@@ -19,7 +19,6 @@ module Alchemy
19
19
  raise "Element name '#{element['name']}' has wrong format. Only lowercase and non whitespace characters allowed."
20
20
  end
21
21
 
22
- conditional_template "editor.html.#{template_engine}", "#{elements_dir}/_#{@element_name}_editor.html.#{template_engine}"
23
22
  conditional_template "view.html.#{template_engine}", "#{elements_dir}/_#{@element_name}_view.html.#{template_engine}"
24
23
  end
25
24
  end
@@ -1,5 +1,5 @@
1
- <%%- cache(<%= @element_name %>_view) do -%>
2
- <%%= element_view_for(<%= @element_name %>_view) do |el| -%>
1
+ <%%- cache(<%= @element_name %>) do -%>
2
+ <%%= element_view_for(<%= @element_name %>) do |el| -%>
3
3
  <%- @contents.each do |content| -%>
4
4
  <%- if @contents.length > 1 -%>
5
5
  <div class="<%= content["name"] %>">
@@ -10,7 +10,7 @@
10
10
  <%- end -%>
11
11
  <%- end -%>
12
12
  <%- if @element['nestable_elements'].present? -%>
13
- <%%= render <%= @element_name %>_view.nested_elements %>
13
+ <%%= render <%= @element_name %>.nested_elements.available %>
14
14
  <%- end -%>
15
15
  <%%- end -%>
16
16
  <%%- end -%>
@@ -1,5 +1,5 @@
1
- - cache(<%= @element_name -%>_view) do
2
- = element_view_for(<%= @element_name -%>_view) do |el|
1
+ - cache(<%= @element_name -%>) do
2
+ = element_view_for(<%= @element_name -%>) do |el|
3
3
  <%- @contents.each do |content| -%>
4
4
  <%- if @contents.length > 1 -%>
5
5
  .<%= content["name"] %>
@@ -9,5 +9,5 @@
9
9
  <%- end -%>
10
10
  <%- end -%>
11
11
  <%- if @element['nestable_elements'].present? -%>
12
- = render <%= @element_name -%>_view.nested_elements
12
+ = render <%= @element_name -%>.nested_elements.available
13
13
  <%- end -%>
@@ -1,5 +1,5 @@
1
- - cache(<%= @element_name -%>_view) do
2
- = element_view_for(<%= @element_name -%>_view) do |el|
1
+ - cache(<%= @element_name -%>) do
2
+ = element_view_for(<%= @element_name -%>) do |el|
3
3
  <%- @contents.each do |content| -%>
4
4
  <%- if @contents.length > 1 -%>
5
5
  .<%= content["name"] %>
@@ -9,5 +9,5 @@
9
9
  <%- end -%>
10
10
  <%- end -%>
11
11
  <%- if @element['nestable_elements'].present? -%>
12
- = render <%= @element_name -%>_view.nested_elements
12
+ = render <%= @element_name -%>.nested_elements.available
13
13
  <%- end -%>
@@ -1,5 +1,5 @@
1
- <%- cache(element) do -%>
2
- <%= element_view_for(element, tag: 'article') do |el| -%>
1
+ <%- cache(article) do -%>
2
+ <%= element_view_for(article, tag: 'article') do |el| -%>
3
3
  <h2><%= el.render :headline %></h2>
4
4
  <%= el.render :picture, size: '1200x600' %>
5
5
  <%= el.render :text %>
@@ -1,13 +1,16 @@
1
1
  <!DOCTYPE html>
2
2
  <html lang="<%= @page.language_code %>">
3
- <head>
4
- <%= render "alchemy/pages/meta_data" %>
5
- <%= stylesheet_link_tag 'application', media: 'all' %>
6
- <%= javascript_include_tag 'application' %>
7
- <%= csrf_meta_tags %>
8
- </head>
9
- <body>
10
- <%= yield %>
11
- <%= render "alchemy/edit_mode" %>
12
- </body>
3
+ <head>
4
+ <%= render "alchemy/pages/meta_data" %>
5
+ <%= csrf_meta_tags %>
6
+ <%= csp_meta_tag %>
7
+
8
+ <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
9
+ <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
10
+ </head>
11
+
12
+ <body>
13
+ <%= yield %>
14
+ <%= render "alchemy/edit_mode" %>
15
+ </body>
13
16
  </html>
@@ -41,18 +41,9 @@ module Alchemy
41
41
  create_file "app/assets/stylesheets/application.css", "/*\n#{stylesheet_require} */\n"
42
42
  end
43
43
 
44
- [
45
- "_article_editor.html.erb",
46
- "_article_view.html.erb"
47
- ].each do |file|
48
- copy_file file, "app/views/alchemy/elements/#{file}"
49
- end
50
-
44
+ copy_file "_article.html.erb", "app/views/alchemy/elements/_article.html.erb"
51
45
  copy_file "_standard.html.erb", "app/views/alchemy/page_layouts/_standard.html.erb"
52
-
53
- %w(de en es).each do |locale|
54
- copy_file "alchemy.#{locale}.yml", "config/locales/alchemy.#{locale}.yml"
55
- end
46
+ copy_file "alchemy.en.yml", "config/locales/alchemy.en.yml"
56
47
  end
57
48
 
58
49
  def copy_dragonfly_config
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../base'
4
+
5
+ module Alchemy
6
+ module Generators
7
+ class MenusGenerator < Base
8
+ desc "This generator generates Alchemy menu partials."
9
+ source_root File.expand_path('templates', __dir__)
10
+
11
+ def create_partials
12
+ menus = Alchemy::Node.roots
13
+ return unless menus
14
+
15
+ menus.each do |menu|
16
+ conditional_template "wrapper.html.#{template_engine}",
17
+ "app/views/#{menu.view_folder_name}/_wrapper.html.#{template_engine}"
18
+ conditional_template "node.html.#{template_engine}",
19
+ "app/views/#{menu.view_folder_name}/_node.html.#{template_engine}"
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,19 @@
1
+ <%% cache node do %>
2
+ <%%= content_tag :li, class: ['nav-item', node.children.any? ? 'dropdown' : nil].compact do %>
3
+ <%%= link_to_if node.url,
4
+ node.name,
5
+ @preview_mode ? 'javascript: void(0)' : node.url,
6
+ class: ['nav-link', current_page?(node.url) ? 'active' : nil].compact,
7
+ title: node.title,
8
+ target: node.external? ? '_blank' : nil,
9
+ rel: node.nofollow? ? 'nofollow' : nil %>
10
+ <%% if node.children.any? %>
11
+ <ul class="dropdown-menu">
12
+ <%%= render partial: options[:node_partial_name],
13
+ collection: node.children.includes(:page, :children),
14
+ locals: { options: options },
15
+ as: 'node' %>
16
+ </ul>
17
+ <%% end %>
18
+ <%% end %>
19
+ <%% end %>
@@ -0,0 +1,16 @@
1
+ - cache node do
2
+ = content_tag :li,
3
+ class: ['nav-item', node.children.any? ? 'dropdown' : nil].compact do
4
+ = link_to_if node.url,
5
+ node.name,
6
+ @preview_mode ? 'javascript: void(0)' : node.url,
7
+ class: ['nav-link', current_page?(node.url) ? 'active' : nil].compact,
8
+ title: node.title,
9
+ target: node.external? ? '_blank' : nil,
10
+ rel: node.nofollow? ? 'nofollow' : nil
11
+ - if node.children.any?
12
+ %ul.dropdown-menu
13
+ = render partial: options[:node_partial_name],
14
+ collection: node.children.includes(:page, :children),
15
+ locals: { options: options },
16
+ as: 'node'
@@ -0,0 +1,16 @@
1
+ - cache node do
2
+ = content_tag :li,
3
+ class: ['nav-item', node.children.any? ? 'dropdown' : nil].compact do
4
+ = link_to_if node.url,
5
+ node.name,
6
+ @preview_mode ? 'javascript: void(0)' : node.url,
7
+ class: ['nav-link', current_page?(node.url) ? 'active' : nil].compact,
8
+ title: node.title,
9
+ target: node.external? ? '_blank' : nil,
10
+ rel: node.nofollow? ? 'nofollow' : nil
11
+ - if node.children.any?
12
+ ul.dropdown-menu
13
+ = render partial: options[:node_partial_name],
14
+ collection: node.children.includes(:page, :children),
15
+ locals: { options: options },
16
+ as: 'node'
@@ -0,0 +1,8 @@
1
+ <%% cache menu do %>
2
+ <ul class="nav">
3
+ <%%= render partial: options[:node_partial_name],
4
+ collection: menu.children.includes(:page, :children),
5
+ locals: { options: options },
6
+ as: 'node' %>
7
+ </ul>
8
+ <%% end %>
@@ -0,0 +1,6 @@
1
+ - cache menu do
2
+ %ul.nav
3
+ = render partial: options[:node_partial_name],
4
+ collection: menu.children.includes(:page, :children),
5
+ locals: { options: options },
6
+ as: 'node' %>
@@ -0,0 +1,6 @@
1
+ - cache menu do
2
+ ul.nav
3
+ = render partial: options[:node_partial_name],
4
+ collection: menu.children.includes(:page, :children),
5
+ locals: { options: options },
6
+ as: 'node' %>
@@ -3,7 +3,7 @@ require 'rails'
3
3
  module Alchemy
4
4
  module Generators
5
5
  class ViewsGenerator < ::Rails::Generators::Base
6
- ALCHEMY_VIEWS = %w(breadcrumb language_links messages_mailer navigation)
6
+ ALCHEMY_VIEWS = %w(breadcrumb language_links messages_mailer)
7
7
 
8
8
  desc "Generates Alchemy views for #{ALCHEMY_VIEWS.to_sentence}."
9
9
 
@@ -31,5 +31,65 @@ namespace :alchemy do
31
31
  puts "Done."
32
32
  end
33
33
  end
34
+
35
+ namespace :page_trees do
36
+ desc "Converts the page tree into a menu."
37
+ task to_menus: [:environment] do
38
+ if Alchemy::Node.roots.exists?
39
+ abort "\n⨯ There are already menus present in your database. Aborting!"
40
+ end
41
+
42
+ def name_for_node(page)
43
+ if page.visible? && page.public? && !page.redirects_to_external?
44
+ nil
45
+ else
46
+ page.name
47
+ end
48
+ end
49
+
50
+ def page_for_node(page)
51
+ if page.visible? && page.public? && !page.redirects_to_external?
52
+ page
53
+ elsif Alchemy::Config.get(:redirect_to_public_child) && page.visible? && !page.public? && page.children.published.any?
54
+ page.children.published.first
55
+ end
56
+ end
57
+
58
+ def convert_to_nodes(children, node:)
59
+ children.each do |page|
60
+ has_children = page.children.any?
61
+ next unless page.visible || has_children
62
+
63
+ Alchemy::Deprecation.silence do
64
+ new_node = node.children.create!(
65
+ name: name_for_node(page),
66
+ page: page_for_node(page),
67
+ url: page.redirects_to_external? ? page.urlname : nil,
68
+ external: page.redirects_to_external? && Alchemy::Config.get(:open_external_links_in_new_tab),
69
+ language_id: page.language_id
70
+ )
71
+ print "."
72
+ if has_children
73
+ convert_to_nodes(page.children, node: new_node)
74
+ end
75
+ end
76
+ end
77
+ end
78
+
79
+ menu_count = Alchemy::Language.count
80
+ puts "\n- Converting #{menu_count} page #{'tree'.pluralize(menu_count)} into #{'menu'.pluralize(menu_count)}."
81
+ Alchemy::BaseRecord.transaction do
82
+ Alchemy::Language.all.each do |language|
83
+ locale = language.locale.presence || I18n.default_locale
84
+ menu_name = I18n.t('Main Navigation', scope: 'alchemy.menu_names', default: 'Main Navigation', locale: locale)
85
+ root_node = Alchemy::Node.create(language: language, name: menu_name)
86
+ language.pages.language_roots.each do |root_page|
87
+ convert_to_nodes(root_page.children, node: root_node)
88
+ end
89
+ end
90
+ end
91
+ puts "\n✓ Done."
92
+ end
93
+ end
34
94
  end
35
95
  end
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: 4.3.2
4
+ version: 4.4.0
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: 2019-11-08 00:00:00.000000000 Z
16
+ date: 2020-01-06 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
19
  name: active_model_serializers
@@ -33,16 +33,22 @@ dependencies:
33
33
  name: acts_as_list
34
34
  requirement: !ruby/object:Gem::Requirement
35
35
  requirements:
36
- - - "~>"
36
+ - - ">="
37
37
  - !ruby/object:Gem::Version
38
38
  version: '0.3'
39
+ - - "<"
40
+ - !ruby/object:Gem::Version
41
+ version: '2'
39
42
  type: :runtime
40
43
  prerelease: false
41
44
  version_requirements: !ruby/object:Gem::Requirement
42
45
  requirements:
43
- - - "~>"
46
+ - - ">="
44
47
  - !ruby/object:Gem::Version
45
48
  version: '0.3'
49
+ - - "<"
50
+ - !ruby/object:Gem::Version
51
+ version: '2'
46
52
  - !ruby/object:Gem::Dependency
47
53
  name: awesome_nested_set
48
54
  requirement: !ruby/object:Gem::Requirement
@@ -355,6 +361,26 @@ dependencies:
355
361
  - - "<"
356
362
  - !ruby/object:Gem::Version
357
363
  version: '6'
364
+ - !ruby/object:Gem::Dependency
365
+ name: sprockets
366
+ requirement: !ruby/object:Gem::Requirement
367
+ requirements:
368
+ - - ">="
369
+ - !ruby/object:Gem::Version
370
+ version: '3.0'
371
+ - - "<"
372
+ - !ruby/object:Gem::Version
373
+ version: '5'
374
+ type: :runtime
375
+ prerelease: false
376
+ version_requirements: !ruby/object:Gem::Requirement
377
+ requirements:
378
+ - - ">="
379
+ - !ruby/object:Gem::Version
380
+ version: '3.0'
381
+ - - "<"
382
+ - !ruby/object:Gem::Version
383
+ version: '5'
358
384
  - !ruby/object:Gem::Dependency
359
385
  name: turbolinks
360
386
  requirement: !ruby/object:Gem::Requirement
@@ -411,6 +437,20 @@ dependencies:
411
437
  - - "~>"
412
438
  - !ruby/object:Gem::Version
413
439
  version: '5.0'
440
+ - !ruby/object:Gem::Dependency
441
+ name: puma
442
+ requirement: !ruby/object:Gem::Requirement
443
+ requirements:
444
+ - - "~>"
445
+ - !ruby/object:Gem::Version
446
+ version: '4.0'
447
+ type: :development
448
+ prerelease: false
449
+ version_requirements: !ruby/object:Gem::Requirement
450
+ requirements:
451
+ - - "~>"
452
+ - !ruby/object:Gem::Version
453
+ version: '4.0'
414
454
  - !ruby/object:Gem::Dependency
415
455
  name: rails-controller-testing
416
456
  requirement: !ruby/object:Gem::Requirement
@@ -454,19 +494,19 @@ dependencies:
454
494
  - !ruby/object:Gem::Version
455
495
  version: 4.0.0.beta2
456
496
  - !ruby/object:Gem::Dependency
457
- name: selenium-webdriver
497
+ name: webdrivers
458
498
  requirement: !ruby/object:Gem::Requirement
459
499
  requirements:
460
500
  - - "~>"
461
501
  - !ruby/object:Gem::Version
462
- version: '3.8'
502
+ version: '4.0'
463
503
  type: :development
464
504
  prerelease: false
465
505
  version_requirements: !ruby/object:Gem::Requirement
466
506
  requirements:
467
507
  - - "~>"
468
508
  - !ruby/object:Gem::Version
469
- version: '3.8'
509
+ version: '4.0'
470
510
  - !ruby/object:Gem::Dependency
471
511
  name: shoulda-matchers
472
512
  requirement: !ruby/object:Gem::Requirement
@@ -493,12 +533,11 @@ files:
493
533
  - ".github/FUNDING.yml"
494
534
  - ".github/ISSUE_TEMPLATE/Bug_report.md"
495
535
  - ".github/ISSUE_TEMPLATE/Feature_request.md"
536
+ - ".github/workflows/ci.yml"
496
537
  - ".gitignore"
497
538
  - ".hound.yml"
498
539
  - ".localeapp/config.rb"
499
- - ".rspec"
500
540
  - ".rubocop.yml"
501
- - ".travis.yml"
502
541
  - ".yardopts"
503
542
  - CHANGELOG.md
504
543
  - CODE_OF_CONDUCT.md
@@ -509,6 +548,7 @@ files:
509
548
  - README.md
510
549
  - Rakefile
511
550
  - alchemy_cms.gemspec
551
+ - app/assets/config/alchemy_manifest.js
512
552
  - app/assets/images/alchemy/alchemy-logo.png
513
553
  - app/assets/images/alchemy/alchemy-logo.svg
514
554
  - app/assets/images/alchemy/favicon.ico
@@ -552,8 +592,10 @@ files:
552
592
  - app/assets/javascripts/alchemy/alchemy.trash_window.js.coffee
553
593
  - app/assets/javascripts/alchemy/alchemy.uploader.js.coffee
554
594
  - app/assets/javascripts/alchemy/menubar.js.coffee
595
+ - app/assets/javascripts/alchemy/page_select.js
555
596
  - app/assets/javascripts/alchemy/preview.js
556
597
  - app/assets/javascripts/alchemy/templates/index.js
598
+ - app/assets/javascripts/alchemy/templates/page.hbs
557
599
  - app/assets/javascripts/alchemy/templates/spinner.hbs
558
600
  - app/assets/javascripts/tinymce/plugins/alchemy_link/plugin.min.js
559
601
  - app/assets/stylesheets/alchemy/_defaults.scss
@@ -581,10 +623,13 @@ files:
581
623
  - app/assets/stylesheets/alchemy/icons.scss
582
624
  - app/assets/stylesheets/alchemy/image_library.scss
583
625
  - app/assets/stylesheets/alchemy/jquery-ui.scss
626
+ - app/assets/stylesheets/alchemy/labels.scss
584
627
  - app/assets/stylesheets/alchemy/lists.scss
585
628
  - app/assets/stylesheets/alchemy/menubar.scss
586
629
  - app/assets/stylesheets/alchemy/navigation.scss
630
+ - app/assets/stylesheets/alchemy/nodes.scss
587
631
  - app/assets/stylesheets/alchemy/notices.scss
632
+ - app/assets/stylesheets/alchemy/page-select.scss
588
633
  - app/assets/stylesheets/alchemy/pagination.scss
589
634
  - app/assets/stylesheets/alchemy/preview_window.scss
590
635
  - app/assets/stylesheets/alchemy/print.scss
@@ -623,6 +668,7 @@ files:
623
668
  - app/controllers/alchemy/admin/languages_controller.rb
624
669
  - app/controllers/alchemy/admin/layoutpages_controller.rb
625
670
  - app/controllers/alchemy/admin/legacy_page_urls_controller.rb
671
+ - app/controllers/alchemy/admin/nodes_controller.rb
626
672
  - app/controllers/alchemy/admin/pages_controller.rb
627
673
  - app/controllers/alchemy/admin/pictures_controller.rb
628
674
  - app/controllers/alchemy/admin/resources_controller.rb
@@ -678,6 +724,7 @@ files:
678
724
  - app/models/alchemy/essence_file.rb
679
725
  - app/models/alchemy/essence_html.rb
680
726
  - app/models/alchemy/essence_link.rb
727
+ - app/models/alchemy/essence_page.rb
681
728
  - app/models/alchemy/essence_picture.rb
682
729
  - app/models/alchemy/essence_picture_view.rb
683
730
  - app/models/alchemy/essence_richtext.rb
@@ -688,13 +735,13 @@ files:
688
735
  - app/models/alchemy/language/code.rb
689
736
  - app/models/alchemy/legacy_page_url.rb
690
737
  - app/models/alchemy/message.rb
738
+ - app/models/alchemy/node.rb
691
739
  - app/models/alchemy/page.rb
692
740
  - app/models/alchemy/page/fixed_attributes.rb
693
741
  - app/models/alchemy/page/page_elements.rb
694
742
  - app/models/alchemy/page/page_naming.rb
695
743
  - app/models/alchemy/page/page_natures.rb
696
744
  - app/models/alchemy/page/page_scopes.rb
697
- - app/models/alchemy/page/page_users.rb
698
745
  - app/models/alchemy/picture.rb
699
746
  - app/models/alchemy/picture/transformations.rb
700
747
  - app/models/alchemy/picture/url.rb
@@ -757,7 +804,6 @@ files:
757
804
  - app/views/alchemy/admin/elements/create.js.erb
758
805
  - app/views/alchemy/admin/elements/fold.js.erb
759
806
  - app/views/alchemy/admin/elements/index.html.erb
760
- - app/views/alchemy/admin/elements/list.html.erb
761
807
  - app/views/alchemy/admin/elements/new.html.erb
762
808
  - app/views/alchemy/admin/elements/order.js.erb
763
809
  - app/views/alchemy/admin/elements/publish.js.erb
@@ -786,6 +832,12 @@ files:
786
832
  - app/views/alchemy/admin/legacy_page_urls/create.js.erb
787
833
  - app/views/alchemy/admin/legacy_page_urls/destroy.js.erb
788
834
  - app/views/alchemy/admin/legacy_page_urls/update.js.erb
835
+ - app/views/alchemy/admin/nodes/_form.html.erb
836
+ - app/views/alchemy/admin/nodes/_node.html.erb
837
+ - app/views/alchemy/admin/nodes/edit.html.erb
838
+ - app/views/alchemy/admin/nodes/index.html.erb
839
+ - app/views/alchemy/admin/nodes/new.html.erb
840
+ - app/views/alchemy/admin/pages/_anchor_link.html.erb
789
841
  - app/views/alchemy/admin/pages/_create_language_form.html.erb
790
842
  - app/views/alchemy/admin/pages/_current_page.html.erb
791
843
  - app/views/alchemy/admin/pages/_external_link.html.erb
@@ -794,9 +846,9 @@ files:
794
846
  - app/views/alchemy/admin/pages/_internal_link.html.erb
795
847
  - app/views/alchemy/admin/pages/_legacy_urls.html.erb
796
848
  - app/views/alchemy/admin/pages/_locked_page.html.erb
849
+ - app/views/alchemy/admin/pages/_menu_fields.html.erb
797
850
  - app/views/alchemy/admin/pages/_new_page_form.html.erb
798
851
  - app/views/alchemy/admin/pages/_page.html.erb
799
- - app/views/alchemy/admin/pages/_page_for_links.html.erb
800
852
  - app/views/alchemy/admin/pages/_page_infos.html.erb
801
853
  - app/views/alchemy/admin/pages/_page_status.html.erb
802
854
  - app/views/alchemy/admin/pages/_publication_fields.html.erb
@@ -889,6 +941,8 @@ files:
889
941
  - app/views/alchemy/essences/_essence_html_view.html.erb
890
942
  - app/views/alchemy/essences/_essence_link_editor.html.erb
891
943
  - app/views/alchemy/essences/_essence_link_view.html.erb
944
+ - app/views/alchemy/essences/_essence_page_editor.html.erb
945
+ - app/views/alchemy/essences/_essence_page_view.html.erb
892
946
  - app/views/alchemy/essences/_essence_picture_editor.html.erb
893
947
  - app/views/alchemy/essences/_essence_picture_view.html.erb
894
948
  - app/views/alchemy/essences/_essence_richtext_editor.html.erb
@@ -938,6 +992,8 @@ files:
938
992
  - db/migrate/20180226123013_alchemy_four_point_zero.rb
939
993
  - db/migrate/20180227224537_migrate_tags_to_gutentag.rb
940
994
  - db/migrate/20180519204655_add_fixed_to_alchemy_elements.rb
995
+ - db/migrate/20191016073858_create_alchemy_essence_pages.rb
996
+ - db/migrate/20191029212236_create_alchemy_nodes.rb
941
997
  - lib/alchemy/ability_helper.rb
942
998
  - lib/alchemy/admin/locale.rb
943
999
  - lib/alchemy/auth_accessors.rb
@@ -981,9 +1037,11 @@ files:
981
1037
  - lib/alchemy/test_support/factories/dummy_user_factory.rb
982
1038
  - lib/alchemy/test_support/factories/element_factory.rb
983
1039
  - lib/alchemy/test_support/factories/essence_file_factory.rb
1040
+ - lib/alchemy/test_support/factories/essence_page_factory.rb
984
1041
  - lib/alchemy/test_support/factories/essence_picture_factory.rb
985
1042
  - lib/alchemy/test_support/factories/essence_text_factory.rb
986
1043
  - lib/alchemy/test_support/factories/language_factory.rb
1044
+ - lib/alchemy/test_support/factories/node_factory.rb
987
1045
  - lib/alchemy/test_support/factories/page_factory.rb
988
1046
  - lib/alchemy/test_support/factories/picture_factory.rb
989
1047
  - lib/alchemy/test_support/factories/site_factory.rb
@@ -1007,21 +1065,15 @@ files:
1007
1065
  - lib/kaminari/scoped_pagination_url_helper.rb
1008
1066
  - lib/rails/generators/alchemy/base.rb
1009
1067
  - lib/rails/generators/alchemy/elements/elements_generator.rb
1010
- - lib/rails/generators/alchemy/elements/templates/editor.html.erb
1011
- - lib/rails/generators/alchemy/elements/templates/editor.html.haml
1012
- - lib/rails/generators/alchemy/elements/templates/editor.html.slim
1013
1068
  - lib/rails/generators/alchemy/elements/templates/view.html.erb
1014
1069
  - lib/rails/generators/alchemy/elements/templates/view.html.haml
1015
1070
  - lib/rails/generators/alchemy/elements/templates/view.html.slim
1016
1071
  - lib/rails/generators/alchemy/essence/essence_generator.rb
1017
1072
  - lib/rails/generators/alchemy/essence/templates/editor.html.erb
1018
1073
  - lib/rails/generators/alchemy/essence/templates/view.html.erb
1019
- - lib/rails/generators/alchemy/install/files/_article_editor.html.erb
1020
- - lib/rails/generators/alchemy/install/files/_article_view.html.erb
1074
+ - lib/rails/generators/alchemy/install/files/_article.html.erb
1021
1075
  - lib/rails/generators/alchemy/install/files/_standard.html.erb
1022
- - lib/rails/generators/alchemy/install/files/alchemy.de.yml
1023
1076
  - lib/rails/generators/alchemy/install/files/alchemy.en.yml
1024
- - lib/rails/generators/alchemy/install/files/alchemy.es.yml
1025
1077
  - lib/rails/generators/alchemy/install/files/all.css
1026
1078
  - lib/rails/generators/alchemy/install/files/all.js
1027
1079
  - lib/rails/generators/alchemy/install/files/application.html.erb
@@ -1030,6 +1082,13 @@ files:
1030
1082
  - lib/rails/generators/alchemy/install/templates/dragonfly.rb.tt
1031
1083
  - lib/rails/generators/alchemy/install/templates/elements.yml.tt
1032
1084
  - lib/rails/generators/alchemy/install/templates/page_layouts.yml.tt
1085
+ - lib/rails/generators/alchemy/menus/menus_generator.rb
1086
+ - lib/rails/generators/alchemy/menus/templates/node.html.erb
1087
+ - lib/rails/generators/alchemy/menus/templates/node.html.haml
1088
+ - lib/rails/generators/alchemy/menus/templates/node.html.slim
1089
+ - lib/rails/generators/alchemy/menus/templates/wrapper.html.erb
1090
+ - lib/rails/generators/alchemy/menus/templates/wrapper.html.haml
1091
+ - lib/rails/generators/alchemy/menus/templates/wrapper.html.slim
1033
1092
  - lib/rails/generators/alchemy/module/module_generator.rb
1034
1093
  - lib/rails/generators/alchemy/module/templates/ability.rb.tt
1035
1094
  - lib/rails/generators/alchemy/module/templates/controller.rb.tt
@@ -1129,7 +1188,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
1129
1188
  version: '0'
1130
1189
  requirements:
1131
1190
  - ImageMagick (libmagick), v6.6 or greater.
1132
- rubygems_version: 3.0.3
1191
+ rubygems_version: 3.1.2
1133
1192
  signing_key:
1134
1193
  specification_version: 4
1135
1194
  summary: A powerful, userfriendly and flexible CMS for Rails 5