alchemy_cms 4.1.2 → 4.2.0.rc1

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 (155) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/Bug_report.md +0 -5
  3. data/.rubocop.yml +4 -1
  4. data/.travis.yml +3 -3
  5. data/CHANGELOG.md +29 -10
  6. data/Gemfile +5 -7
  7. data/README.md +114 -62
  8. data/Rakefile +2 -2
  9. data/alchemy_cms.gemspec +5 -5
  10. data/app/assets/images/alchemy/icon.svg +1 -1
  11. data/app/assets/javascripts/alchemy/admin.js +2 -0
  12. data/app/assets/javascripts/alchemy/alchemy.base.js.coffee +0 -24
  13. data/app/assets/javascripts/alchemy/alchemy.datepicker.js.coffee +11 -9
  14. data/app/assets/javascripts/alchemy/alchemy.dragndrop.js.coffee +7 -24
  15. data/app/assets/javascripts/alchemy/alchemy.element_editors.js.coffee +9 -8
  16. data/app/assets/javascripts/alchemy/alchemy.fixed_elements.js +38 -0
  17. data/app/assets/javascripts/alchemy/alchemy.sitemap.js.coffee +2 -4
  18. data/app/assets/javascripts/alchemy/alchemy.translations.js.coffee +1 -1
  19. data/app/assets/stylesheets/alchemy/_mixins.scss +2 -1
  20. data/app/assets/stylesheets/alchemy/_variables.scss +7 -2
  21. data/app/assets/stylesheets/alchemy/admin.scss +2 -1
  22. data/app/assets/stylesheets/alchemy/archive.scss +18 -4
  23. data/app/assets/stylesheets/alchemy/buttons.scss +1 -1
  24. data/app/assets/stylesheets/alchemy/dialogs.scss +1 -1
  25. data/app/assets/stylesheets/alchemy/elements.scss +154 -90
  26. data/app/assets/stylesheets/alchemy/filter_field.scss +30 -0
  27. data/app/assets/stylesheets/alchemy/flatpickr.scss +839 -0
  28. data/app/assets/stylesheets/alchemy/forms.scss +5 -1
  29. data/app/assets/stylesheets/alchemy/frame.scss +6 -14
  30. data/app/assets/stylesheets/alchemy/navigation.scss +109 -98
  31. data/app/assets/stylesheets/alchemy/search.scss +11 -29
  32. data/app/assets/stylesheets/alchemy/tables.scss +0 -23
  33. data/app/assets/stylesheets/alchemy/tags.scss +4 -27
  34. data/app/assets/stylesheets/alchemy/toolbar.scss +12 -2
  35. data/app/assets/stylesheets/tinymce/skins/alchemy/skin.min.css.scss +4 -33
  36. data/app/controllers/alchemy/admin/attachments_controller.rb +1 -12
  37. data/app/controllers/alchemy/admin/contents_controller.rb +2 -24
  38. data/app/controllers/alchemy/admin/elements_controller.rb +11 -49
  39. data/app/controllers/alchemy/admin/pages_controller.rb +1 -1
  40. data/app/controllers/alchemy/admin/pictures_controller.rb +1 -14
  41. data/app/controllers/alchemy/api/contents_controller.rb +1 -1
  42. data/app/controllers/alchemy/api/elements_controller.rb +1 -1
  43. data/app/controllers/alchemy/api/pages_controller.rb +1 -1
  44. data/app/controllers/concerns/alchemy/admin/archive_overlay.rb +20 -0
  45. data/app/helpers/alchemy/admin/base_helper.rb +8 -18
  46. data/app/helpers/alchemy/admin/elements_helper.rb +55 -85
  47. data/app/helpers/alchemy/admin/pictures_helper.rb +0 -23
  48. data/app/helpers/alchemy/elements_helper.rb +80 -120
  49. data/app/helpers/alchemy/pages_helper.rb +5 -24
  50. data/app/models/alchemy/content.rb +0 -1
  51. data/app/models/alchemy/content/factory.rb +33 -57
  52. data/app/models/alchemy/element.rb +46 -66
  53. data/app/models/alchemy/element/element_contents.rb +2 -2
  54. data/app/models/alchemy/page.rb +34 -4
  55. data/app/models/alchemy/page/page_elements.rb +30 -122
  56. data/app/serializers/alchemy/attachment_serializer.rb +0 -2
  57. data/app/serializers/alchemy/content_serializer.rb +0 -2
  58. data/app/serializers/alchemy/element_serializer.rb +0 -3
  59. data/app/serializers/alchemy/essence_boolean_serializer.rb +0 -2
  60. data/app/serializers/alchemy/essence_date_serializer.rb +0 -2
  61. data/app/serializers/alchemy/essence_file_serializer.rb +0 -2
  62. data/app/serializers/alchemy/essence_html_serializer.rb +0 -2
  63. data/app/serializers/alchemy/essence_link_serializer.rb +0 -2
  64. data/app/serializers/alchemy/essence_picture_serializer.rb +0 -2
  65. data/app/serializers/alchemy/essence_richtext_serializer.rb +0 -2
  66. data/app/serializers/alchemy/essence_select_serializer.rb +0 -2
  67. data/app/serializers/alchemy/essence_text_serializer.rb +0 -2
  68. data/app/serializers/alchemy/legacy_element_serializer.rb +0 -3
  69. data/app/serializers/alchemy/page_serializer.rb +2 -8
  70. data/app/serializers/alchemy/page_tree_serializer.rb +1 -1
  71. data/app/serializers/alchemy/picture_serializer.rb +0 -2
  72. data/app/views/alchemy/admin/clipboard/index.html.erb +2 -2
  73. data/app/views/alchemy/admin/clipboard/insert.js.erb +9 -12
  74. data/app/views/alchemy/admin/contents/create.js.erb +4 -30
  75. data/app/views/alchemy/admin/elements/_element.html.erb +27 -12
  76. data/app/views/alchemy/admin/elements/_element_toolbar.html.erb +1 -1
  77. data/app/views/alchemy/admin/elements/_new_element_form.html.erb +0 -10
  78. data/app/views/alchemy/admin/elements/create.js.erb +12 -12
  79. data/app/views/alchemy/admin/elements/fold.js.erb +1 -1
  80. data/app/views/alchemy/admin/elements/index.html.erb +20 -19
  81. data/app/views/alchemy/admin/elements/publish.js.erb +5 -0
  82. data/app/views/alchemy/admin/elements/trash.js.erb +4 -1
  83. data/app/views/alchemy/admin/essence_pictures/assign.js.erb +0 -7
  84. data/app/views/alchemy/admin/essence_pictures/destroy.js.erb +0 -22
  85. data/app/views/alchemy/admin/pages/_publication_fields.html.erb +2 -4
  86. data/app/views/alchemy/admin/pages/edit.html.erb +1 -1
  87. data/app/views/alchemy/admin/pages/index.html.erb +14 -10
  88. data/app/views/alchemy/admin/partials/_language_tree_select.html.erb +1 -1
  89. data/app/views/alchemy/admin/partials/_main_navigation_entry.html.erb +1 -1
  90. data/app/views/alchemy/admin/partials/_remote_search_form.html.erb +7 -5
  91. data/app/views/alchemy/admin/partials/_routes.html.erb +0 -1
  92. data/app/views/alchemy/admin/partials/_search_form.html.erb +6 -4
  93. data/app/views/alchemy/admin/pictures/_picture_to_assign.html.erb +6 -3
  94. data/app/views/alchemy/admin/pictures/index.html.erb +1 -1
  95. data/app/views/alchemy/admin/trash/index.html.erb +8 -7
  96. data/app/views/alchemy/elements/_editor_not_found.html.erb +1 -1
  97. data/app/views/alchemy/essences/_essence_picture_editor.html.erb +4 -19
  98. data/app/views/layouts/alchemy/admin.html.erb +1 -0
  99. data/bin/rspec +0 -5
  100. data/config/alchemy/config.yml +3 -0
  101. data/config/brakeman.ignore +1 -1
  102. data/config/locales/alchemy.en.yml +6 -12
  103. data/config/routes.rb +1 -5
  104. data/db/migrate/20180226123013_alchemy_four_point_zero.rb +0 -29
  105. data/db/migrate/20180519204655_add_fixed_to_alchemy_elements.rb +6 -0
  106. data/lib/alchemy/admin/locale.rb +1 -1
  107. data/lib/alchemy/cache_digests/template_tracker.rb +4 -27
  108. data/lib/alchemy/elements_finder.rb +111 -0
  109. data/lib/alchemy/errors.rb +0 -4
  110. data/lib/alchemy/modules.rb +49 -18
  111. data/lib/alchemy/tasks/tidy.rb +3 -40
  112. data/lib/alchemy/test_support/controller_requests.rb +1 -1
  113. data/lib/alchemy/test_support/essence_shared_examples.rb +1 -1
  114. data/lib/alchemy/test_support/factories/attachment_factory.rb +5 -3
  115. data/lib/alchemy/test_support/factories/content_factory.rb +4 -4
  116. data/lib/alchemy/test_support/factories/dummy_user_factory.rb +5 -5
  117. data/lib/alchemy/test_support/factories/element_factory.rb +12 -7
  118. data/lib/alchemy/test_support/factories/essence_text_factory.rb +1 -1
  119. data/lib/alchemy/test_support/factories/language_factory.rb +13 -13
  120. data/lib/alchemy/test_support/factories/page_factory.rb +18 -17
  121. data/lib/alchemy/test_support/factories/picture_factory.rb +6 -4
  122. data/lib/alchemy/test_support/factories/site_factory.rb +6 -6
  123. data/lib/alchemy/tinymce.rb +1 -1
  124. data/lib/alchemy/upgrader/four_point_two.rb +68 -0
  125. data/lib/alchemy/upgrader/tasks/cells_migration.rb +41 -0
  126. data/lib/alchemy/upgrader/tasks/cells_upgrader.rb +146 -0
  127. data/lib/alchemy/upgrader/tasks/picture_gallery_migration.rb +65 -0
  128. data/lib/alchemy/upgrader/tasks/picture_gallery_upgrader.rb +195 -0
  129. data/lib/alchemy/version.rb +1 -1
  130. data/lib/alchemy_cms.rb +1 -0
  131. data/lib/rails/generators/alchemy/elements/elements_generator.rb +1 -0
  132. data/lib/rails/generators/alchemy/elements/templates/editor.html.erb +0 -3
  133. data/lib/rails/generators/alchemy/elements/templates/editor.html.haml +0 -3
  134. data/lib/rails/generators/alchemy/elements/templates/editor.html.slim +0 -3
  135. data/lib/rails/generators/alchemy/elements/templates/view.html.erb +3 -14
  136. data/lib/rails/generators/alchemy/elements/templates/view.html.haml +3 -10
  137. data/lib/rails/generators/alchemy/elements/templates/view.html.slim +3 -10
  138. data/lib/tasks/alchemy/tidy.rake +1 -23
  139. data/lib/tasks/alchemy/upgrade.rake +44 -1
  140. data/vendor/assets/javascripts/flatpickr/flatpickr.min.js +2 -0
  141. data/vendor/assets/javascripts/tinymce/license.txt +0 -0
  142. data/vendor/assets/javascripts/tinymce/tinymce.min.js +2 -2
  143. metadata +25 -31
  144. data/app/assets/stylesheets/alchemy/jquery.datetimepicker.scss +0 -478
  145. data/app/models/alchemy/cell.rb +0 -95
  146. data/app/models/alchemy/page/page_cells.rb +0 -69
  147. data/app/serializers/alchemy/cell_serializer.rb +0 -19
  148. data/app/views/alchemy/admin/contents/new.html.erb +0 -11
  149. data/app/views/alchemy/admin/contents/order.js.erb +0 -3
  150. data/app/views/alchemy/admin/elements/_add_picture.html.erb +0 -14
  151. data/app/views/alchemy/admin/elements/_picture_gallery_editor.html.erb +0 -24
  152. data/bin/spring +0 -16
  153. data/lib/alchemy/test_support/factories/cell_factory.rb +0 -9
  154. data/vendor/assets/javascripts/date-formatter.js +0 -161
  155. data/vendor/assets/javascripts/jquery_plugins/jquery.datetimepicker.full.min.js +0 -2
@@ -2,6 +2,6 @@ require 'factory_bot'
2
2
 
3
3
  FactoryBot.define do
4
4
  factory :alchemy_essence_text, class: 'Alchemy::EssenceText' do
5
- body 'This is a headline'
5
+ body { 'This is a headline' }
6
6
  end
7
7
  end
@@ -3,26 +3,26 @@ require 'alchemy/test_support/factories/site_factory'
3
3
 
4
4
  FactoryBot.define do
5
5
  factory :alchemy_language, class: 'Alchemy::Language' do
6
- name 'Deutsch'
7
- code 'de'
8
- default true
9
- frontpage_name 'Intro'
6
+ name { 'Deutsch' }
7
+ code { 'de' }
8
+ default { true }
9
+ frontpage_name { 'Intro' }
10
10
  page_layout { Alchemy::Config.get(:default_language)['page_layout'] }
11
- public true
11
+ public { true }
12
12
  site { Alchemy::Site.default }
13
13
 
14
14
  trait :klingon do
15
- name 'Klingon'
16
- code 'kl'
17
- frontpage_name 'Tuq'
18
- default false
15
+ name { 'Klingon' }
16
+ code { 'kl' }
17
+ frontpage_name { 'Tuq' }
18
+ default { false }
19
19
  end
20
20
 
21
21
  trait :english do
22
- name 'English'
23
- code 'en'
24
- frontpage_name 'Intro'
25
- default false
22
+ name { 'English' }
23
+ code { 'en' }
24
+ frontpage_name { 'Intro' }
25
+ default { false }
26
26
  end
27
27
  end
28
28
  end
@@ -5,7 +5,7 @@ FactoryBot.define do
5
5
  factory :alchemy_page, class: 'Alchemy::Page' do
6
6
  language { Alchemy::Language.default || FactoryBot.create(:alchemy_language) }
7
7
  sequence(:name) { |n| "A Page #{n}" }
8
- page_layout "standard"
8
+ page_layout { "standard" }
9
9
 
10
10
  parent_id do
11
11
  (Alchemy::Page.find_by(language_root: true) ||
@@ -13,20 +13,20 @@ FactoryBot.define do
13
13
  end
14
14
 
15
15
  # This speeds up creating of pages dramatically.
16
- # Pass do_not_autogenerate: false to generate elements
17
- do_not_autogenerate true
16
+ # Pass autogenerate_elements: true to generate elements
17
+ autogenerate_elements { false }
18
18
 
19
19
  trait :root do
20
- name 'Root'
21
- language nil
22
- parent_id nil
23
- page_layout nil
20
+ name { 'Root' }
21
+ language { nil }
22
+ parent_id { nil }
23
+ page_layout { nil }
24
24
  end
25
25
 
26
26
  trait :language_root do
27
- name 'Startseite'
27
+ name { 'Startseite' }
28
28
  page_layout { language.page_layout }
29
- language_root true
29
+ language_root { true }
30
30
  public_on { Time.current }
31
31
  parent_id { Alchemy::Page.root.id }
32
32
  end
@@ -37,22 +37,23 @@ FactoryBot.define do
37
37
  end
38
38
 
39
39
  trait :system do
40
- name "Systempage"
40
+ name { "Systempage" }
41
41
  parent_id { Alchemy::Page.root.id }
42
- language_root false
43
- page_layout nil
44
- language nil
42
+ language_root { false }
43
+ page_layout { nil }
44
+ language { nil }
45
45
  end
46
46
 
47
47
  trait :layoutpage do
48
- name "Footer"
48
+ name { "Footer" }
49
49
  parent_id { Alchemy::Page.find_or_create_layout_root_for(Alchemy::Language.current.id).id }
50
- page_layout "footer"
50
+ layoutpage { true }
51
+ page_layout { "footer" }
51
52
  end
52
53
 
53
54
  trait :restricted do
54
- name "Restricted page"
55
- restricted true
55
+ name { "Restricted page" }
56
+ restricted { true }
56
57
  end
57
58
 
58
59
  trait :locked do
@@ -2,9 +2,11 @@ require 'factory_bot'
2
2
 
3
3
  FactoryBot.define do
4
4
  factory :alchemy_picture, class: 'Alchemy::Picture' do
5
- image_file File.new(Alchemy::Engine.root.join('lib', 'alchemy', 'test_support', 'fixtures', 'image.png'))
6
- name 'image'
7
- image_file_name 'image.png'
8
- upload_hash Time.current.hash
5
+ image_file do
6
+ File.new(Alchemy::Engine.root.join('lib', 'alchemy', 'test_support', 'fixtures', 'image.png'))
7
+ end
8
+ name { 'image' }
9
+ image_file_name { 'image.png' }
10
+ upload_hash { Time.current.hash }
9
11
  end
10
12
  end
@@ -2,17 +2,17 @@ require 'factory_bot'
2
2
 
3
3
  FactoryBot.define do
4
4
  factory :alchemy_site, class: 'Alchemy::Site' do
5
- name 'A Site'
6
- host 'domain.com'
5
+ name { 'A Site' }
6
+ host { 'domain.com' }
7
7
 
8
8
  trait :default do
9
- public true
10
- name Alchemy::Config.get(:default_site)['name']
11
- host Alchemy::Config.get(:default_site)['host']
9
+ public { true }
10
+ name { Alchemy::Config.get(:default_site)['name'] }
11
+ host { Alchemy::Config.get(:default_site)['host'] }
12
12
  end
13
13
 
14
14
  trait :public do
15
- public true
15
+ public { true }
16
16
  end
17
17
  end
18
18
  end
@@ -4,7 +4,7 @@ module Alchemy
4
4
  module Tinymce
5
5
  mattr_accessor :languages, :plugins
6
6
 
7
- @@plugins = %w(alchemy_link anchor autoresize charmap code directionality fullscreen hr link paste tabfocus table)
7
+ @@plugins = %w(alchemy_link anchor autoresize charmap code directionality fullscreen hr link lists paste tabfocus table)
8
8
  @@init = {
9
9
  skin: 'alchemy',
10
10
  width: 'auto',
@@ -0,0 +1,68 @@
1
+ require_relative 'tasks/picture_gallery_upgrader'
2
+ require_relative 'tasks/picture_gallery_migration'
3
+ require_relative 'tasks/cells_upgrader'
4
+ require_relative 'tasks/cells_migration'
5
+
6
+ module Alchemy
7
+ class Upgrader::FourPointTwo < Upgrader
8
+ class << self
9
+ def convert_picture_galleries
10
+ desc 'Convert `picture_gallery` element definitions to `nestable_elements`.'
11
+ Alchemy::Upgrader::Tasks::PictureGalleryUpgrader.new.convert_picture_galleries
12
+ end
13
+
14
+ def migrate_picture_galleries
15
+ desc 'Migrate existing gallery elements to `nestable_elements`.'
16
+ Alchemy::Upgrader::Tasks::PictureGalleryMigration.new.migrate_picture_galleries
17
+ end
18
+
19
+ def convert_cells
20
+ desc 'Convert cells config to fixed nestable elements.'
21
+ Alchemy::Upgrader::Tasks::CellsUpgrader.new.convert_cells
22
+ end
23
+
24
+ def migrate_cells
25
+ desc 'Migrate existing cells to fixed nestable elements.'
26
+ Alchemy::Upgrader::Tasks::CellsMigration.new.migrate_cells
27
+ end
28
+
29
+ def alchemy_4_2_todos
30
+ notice = <<-NOTE
31
+
32
+ Element's "picture_gallery" feature removed
33
+ ----------------------------------------------
34
+
35
+ The `picture_gallery` feature of elements was removed and has been replaced by nestable elements.
36
+
37
+ The automatic updater that just ran updated your `config/alchemy/elements.yml`. A backup was made.
38
+ Nevertheless, you should have a look into it and double check the changes.
39
+
40
+ We created nested elements for each gallery picture we found in your database.
41
+
42
+ We also updated your element view partials so they have hints about how to render the child elements.
43
+
44
+ Cells replaced by fixed nestable elements
45
+ -----------------------------------------
46
+
47
+ The Cells feature has been replaced by fixed nestable elements.
48
+
49
+ The automatic updater that just ran updated your `config/alchemy/elements.yml`.
50
+ Nevertheless, you should have a look into it and double check the changes.
51
+
52
+ We defined new fixed elements for each cell former defined in `cells.yml`
53
+ and put its `elements` into the `nestable_elements` collection of the new elements definition.
54
+
55
+ We also updated your element view partials so they render the child elements.
56
+
57
+ Please review and fix markup, if necessary.
58
+
59
+ PLEASE DOUBLE CHECK YOUR ELEMENT PARTIALS AND ADJUST ACCORDINGLY!
60
+
61
+ As always `git diff` is your friend.
62
+
63
+ NOTE
64
+ todo notice, 'Alchemy v4.2 changes'
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,41 @@
1
+ module Alchemy::Upgrader::Tasks
2
+ class CellsMigration
3
+ class Cell < ActiveRecord::Base
4
+ self.table_name = 'alchemy_cells'
5
+ belongs_to :page, class_name: 'Alchemy::Page'
6
+ end
7
+
8
+ def migrate_cells
9
+ if ActiveRecord::Base.connection.data_source_exists?('alchemy_cells')
10
+ cells = Cell.all
11
+
12
+ if cells.any?
13
+ cells.each do |cell|
14
+ migrate_cell!(cell)
15
+ end
16
+ else
17
+ puts "No cells found. Skip"
18
+ end
19
+ else
20
+ puts "Cells table does not exist. Skip"
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def migrate_cell!(cell)
27
+ # bust element definitions insta cache
28
+ Alchemy::Element.instance_variable_set('@definitions', nil)
29
+ fixed_element = Alchemy::Element.find_or_initialize_by(fixed: true, name: cell.name, page: cell.page)
30
+ elements = Alchemy::Element.where(cell_id: cell.id)
31
+
32
+ if fixed_element.new_record?
33
+ fixed_element.nested_elements = elements
34
+ fixed_element.save!
35
+ puts "Created new fixed element '#{fixed_element.name}' for cell '#{cell.name}'."
36
+ else
37
+ puts "Element for cell '#{cell.name}' already present. Skip"
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,146 @@
1
+ require 'alchemy/upgrader'
2
+ require 'rails/generators'
3
+
4
+ module Alchemy::Upgrader::Tasks
5
+ class CellsUpgrader < Thor
6
+ include Thor::Actions
7
+
8
+ no_tasks do
9
+ def convert_cells
10
+ if File.exist?(page_layouts_config_file)
11
+ backup_config
12
+ convert_page_layouts_config
13
+ else
14
+ puts "\nNo page layouts config found. Skipping."
15
+ end
16
+ if File.exist?(cells_config_file)
17
+ convert_cell_config
18
+ delete_cells_config
19
+ else
20
+ puts "\nNo cells config found. Skipping."
21
+ end
22
+ update_cell_views
23
+ update_render_cell_calls
24
+ move_cell_views
25
+ generate_editor_partials
26
+ puts 'Done ✔'
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def backup_config
33
+ print "-- Copy existing config file to `config/alchemy/page_layouts.yml.old` ... "
34
+
35
+ FileUtils.copy Rails.root.join('config', 'alchemy', 'page_layouts.yml'),
36
+ Rails.root.join('config', 'alchemy', 'page_layouts.yml.old')
37
+
38
+ puts "done ✔\n"
39
+ end
40
+
41
+ def write_config(config)
42
+ print '-- Writing new `config/alchemy/page_layouts.yml` ... '
43
+
44
+ File.open(Rails.root.join('config', 'alchemy', 'page_layouts.yml'), "w") do |f|
45
+ f.write config.to_yaml.sub("---\n", "").gsub("\n-", "\n\n-")
46
+ end
47
+
48
+ puts "done ✔\n"
49
+ end
50
+
51
+ def convert_page_layouts_config
52
+ print '-- Moving `cells` from page layouts definition into autogenerated `elements` ... '
53
+ page_layouts = YAML.load_file(page_layouts_config_file)
54
+ page_layouts.select { |p| p['cells'].present? }.map do |page_layout|
55
+ elements = page_layout['elements'] || []
56
+ autogenerate_elements = page_layout['autogenerate'] || []
57
+ cell_elements = page_layout.delete('cells')
58
+ page_layout['elements'] = (elements + cell_elements).uniq
59
+ page_layout['autogenerate'] = (autogenerate_elements + cell_elements).uniq
60
+ end
61
+ puts "done ✔\n"
62
+ write_config(page_layouts)
63
+ end
64
+
65
+ def page_layouts_config_file
66
+ Rails.root.join('config', 'alchemy', 'page_layouts.yml')
67
+ end
68
+
69
+ def cells_config_file
70
+ Rails.root.join('config', 'alchemy', 'cells.yml')
71
+ end
72
+
73
+ def convert_cell_config
74
+ puts '-- Converting cells into unique fixed nestable elements.'
75
+
76
+ YAML.load_file(cells_config_file).each do |cell|
77
+ append_to_file Rails.root.join('config', 'alchemy', 'elements.yml') do
78
+ <<-CELL.strip_heredoc
79
+
80
+ - name: #{cell['name']}
81
+ fixed: true
82
+ unique: true
83
+ nestable_elements: [#{cell['elements'].join(', ')}]
84
+ CELL
85
+ end
86
+ end
87
+ end
88
+
89
+ def delete_cells_config
90
+ puts '-- Deleting cells config file.'
91
+ FileUtils.rm(cells_config_file)
92
+ end
93
+
94
+ def move_cell_views
95
+ if Dir.exist? cells_view_folder
96
+ puts "-- Move cell views into elements view folder"
97
+ Dir.glob("#{cells_view_folder}/*").each do |view|
98
+ filename = File.basename(view).gsub(/(_\w+)\.(\w*\.)?(erb|haml|slim)/, '\1_view.\2\3')
99
+ FileUtils.mv(view, "#{elements_view_folder}/#{filename}")
100
+ puts " Moved #{File.basename(view)} into `app/views/alchemy/elements/` folder"
101
+ end
102
+ FileUtils.rm_rf(cells_view_folder)
103
+ else
104
+ puts "No cell views found. Skip"
105
+ end
106
+ end
107
+
108
+ def generate_editor_partials
109
+ puts "-- Generate editor partials"
110
+ Rails::Generators.invoke('alchemy:elements', ['--skip'])
111
+ end
112
+
113
+ def update_cell_views
114
+ if Dir.exist? cells_view_folder
115
+ puts "-- Update cell views"
116
+ Dir.glob("#{cells_view_folder}/*").each do |view|
117
+ gsub_file(view, /cell\.elements/, 'element.nested_elements.published')
118
+ gsub_file(view, /render_elements\(?from_cell:\scell\)?/, 'render element.nested_elements.published')
119
+ gsub_file(view, /cell/, 'element')
120
+ end
121
+ else
122
+ puts "No cell views found. Skip"
123
+ end
124
+ end
125
+
126
+ def update_render_cell_calls
127
+ puts "-- Update render_cell calls"
128
+ Dir.glob("#{alchemy_views_folder}/**/*").each do |view|
129
+ next if File.directory?(view)
130
+ gsub_file(view, /render_cell[\(\s]?([:'"]?[a-z_]+['"]?)\)?/, 'render_elements(only: \1, fixed: true)')
131
+ end
132
+ end
133
+
134
+ def elements_view_folder
135
+ Rails.root.join('app', 'views', 'alchemy', 'elements')
136
+ end
137
+
138
+ def cells_view_folder
139
+ Rails.root.join('app', 'views', 'alchemy', 'cells')
140
+ end
141
+
142
+ def alchemy_views_folder
143
+ Rails.root.join('app', 'views', 'alchemy')
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,65 @@
1
+ module Alchemy
2
+ class Upgrader::Tasks::PictureGalleryMigration
3
+ def migrate_picture_galleries
4
+ if picture_gallery_elements.present?
5
+ picture_gallery_elements.each do |el|
6
+ migrate_element(el)
7
+ end
8
+ else
9
+ puts "No `picture_gallery` elements found. Skip"
10
+ end
11
+ end
12
+
13
+ private
14
+
15
+ def picture_gallery_elements
16
+ Element.distinct.joins(:contents).where("#{Content.table_name}.name LIKE 'essence_picture_%'")
17
+ end
18
+
19
+ def migrate_element(element)
20
+ gallery_contents = element.contents.where("#{Content.table_name}.name LIKE 'essence_picture_%'").order("#{Content.table_name}.position ASC")
21
+
22
+ if gallery_contents.any?
23
+ if element.nestable_elements.any? { |el| el != "#{element.name}_picture" }
24
+ parent = create_gallery_element(element)
25
+ else
26
+ parent = element
27
+ end
28
+ gallery_contents.each do |content|
29
+ create_element_for_content(content, parent)
30
+ end
31
+ else
32
+ puts "No gallery contents found for #{element.dom_id}. Skip"
33
+ end
34
+ end
35
+
36
+ def create_gallery_element(parent)
37
+ new_element = parent.nested_elements.create!(
38
+ name: "#{parent.name}_picture_gallery",
39
+ public: parent.public,
40
+ folded: parent.folded,
41
+ creator: parent.creator,
42
+ updater: parent.updater,
43
+ page: parent.page,
44
+ autogenerate_contents: false
45
+ )
46
+ puts "Created new `#{new_element.name}` for `#{parent.name}`"
47
+ new_element
48
+ end
49
+
50
+ def create_element_for_content(content, parent)
51
+ new_element = parent.nested_elements.create!(
52
+ name: "#{parent.name}_picture",
53
+ public: parent.public,
54
+ folded: parent.folded,
55
+ creator: parent.creator,
56
+ updater: parent.updater,
57
+ page: parent.page,
58
+ autogenerate_contents: false
59
+ )
60
+
61
+ content.update_columns(element_id: new_element.id, name: 'picture')
62
+ puts "Created new `#{new_element.name}` for `#{parent.name}`"
63
+ end
64
+ end
65
+ end