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
@@ -1,14 +1,2 @@
1
1
  # Add Alchemy assets for precompiling
2
- Rails.application.config.assets.precompile += [
3
- 'alchemy/admin/all.css',
4
- 'alchemy/admin/all.js',
5
- 'alchemy/alchemy-logo.svg',
6
- 'alchemy/favicon.ico',
7
- 'alchemy/preview.js',
8
- 'alchemy/menubar.css',
9
- 'alchemy/menubar.js',
10
- 'alchemy/print.css',
11
- 'alchemy/welcome.css',
12
- 'Jcrop.gif',
13
- 'tinymce/*'
14
- ]
2
+ Rails.application.config.assets.precompile << 'alchemy_manifest.js'
@@ -159,6 +159,7 @@ en:
159
159
 
160
160
  add_nested_element: "Add %{name}"
161
161
  anchor: 'Anchor'
162
+ anchor_link_headline: "You can link to an element anchor from the actual page."
162
163
  attribute_fixed: Value can't be changed for this page type
163
164
  back: 'back'
164
165
  create_tree_as_new_language: "Create %{language} as a new language tree"
@@ -305,13 +306,12 @@ en:
305
306
  assign_file: "Assign a file"
306
307
  assign_file_from_archive: "assign a file from your archive"
307
308
  assign_image: "Assign an image"
309
+ attached_to: "attached to"
308
310
  attachment_filename_notice: "* Please do not use any special characters for the filename."
309
311
  auto_play: "Play movie after load"
310
312
  big_thumbnails: "Big thumbnails"
311
313
  cancel: "cancel"
312
314
  cannot_delete_picture_notice: "Cannot delete Picture %{name}, because it's still in use."
313
- choose_element_as_target: "Please choose an element as target"
314
- choose_element_to_link: "Please choose an element"
315
315
  choose_file_to_link: "Please choose a file to link"
316
316
  "clear clipboard": "clear clipboard"
317
317
  "clear trash": "clear trash"
@@ -320,6 +320,8 @@ en:
320
320
  confirm_to_delete_image: "Do you really want to delete this image from server?"
321
321
  confirm_to_delete_image_from_server: "Do you really want to delete this image from the server?"
322
322
  confirm_to_delete_images_from_server: "Do you really want to delete these images from the server?"
323
+ confirm_to_delete_menu: "Do you really want to delete this menu?"
324
+ confirm_to_delete_node: "Do you really want to delete this menu node?"
323
325
  confirm_to_delete_page: "Do you really want to delete this page? All its elements (even trashed ones) will get lost!"
324
326
  content_essence_not_found: "Content essence not found"
325
327
  content_not_found: "Field for content not present."
@@ -335,12 +337,16 @@ en:
335
337
  "Create language": "Create a new language"
336
338
  "Create site": "Create a new site"
337
339
  create_language_tree_heading: "Create empty language tree"
340
+ create_menu: "Add a menu"
341
+ create_node: "Add a menu node"
338
342
  create_page: "Create a new subpage"
339
343
  currently_edited_by: "This page is locked by"
340
344
  cut_element: "Cut this element."
341
345
  delete_file: "Delete this file from server."
342
346
  delete_image: "Remove this image"
343
347
  delete_language: "Delete this language"
348
+ delete_menu: "Delete this menu"
349
+ delete_node: "Delete this menu node"
344
350
  delete_page: "Delete this page"
345
351
  delete_tag: 'Delete tag'
346
352
  document: "File"
@@ -351,6 +357,8 @@ en:
351
357
  edit_file_properties: "Edit file properties."
352
358
  edit_image_properties: "Edit image properties."
353
359
  edit_language: "Edit language"
360
+ edit_menu: "Edit menu"
361
+ edit_node: "Edit menu node"
354
362
  edit_page: "Edit this page"
355
363
  edit_page_properties: "Edit page properties"
356
364
  edit_tag: 'Edit tag'
@@ -390,9 +398,8 @@ en:
390
398
  image_caption: "Caption"
391
399
  image_name: "Name"
392
400
  image_title: "Title-tag"
393
- internal_link_headline: "Choose a page to link to."
394
- internal_link_page_elements_explanation: "Additionally you can click right beside a page on 'Show Elements' to link to an anchor of an element from that page."
395
- internal_link_page_anchors_explanation: "Alternatively you can link to an anchor of the actual page."
401
+ internal_link_headline: "Search for a page to link to by entering its name into the Page select."
402
+ internal_link_page_elements_explanation: "Additionally you can choose an anchor to an element from selected page."
396
403
  "item copied to clipboard": "Copied %{name} to clipboard"
397
404
  "item moved to clipboard": "Moved %{name} to clipboard"
398
405
  "item removed from clipboard": "Removed %{name} from clipboard"
@@ -406,6 +413,7 @@ en:
406
413
  legacy_url_info_text: "A link is a redirect from an old URL to the current URL of this page. This redirect happens with a <a href='https://support.google.com/webmasters/answer/93633' target='_blank'>301 status code</a>."
407
414
  link_image: "Link this image."
408
415
  link_overlay_tab_label:
416
+ anchor: "Anchor"
409
417
  contactform: "Contact form"
410
418
  external: "External"
411
419
  file: "File"
@@ -418,6 +426,7 @@ en:
418
426
  male: "Male"
419
427
  me: "Me"
420
428
  medium_thumbnails: "Medium thumbnails"
429
+ menu: Menu
421
430
  meta_data: "Meta-Data"
422
431
  meta_description: "Meta-Description"
423
432
  meta_keywords: "Meta-Keywords"
@@ -428,6 +437,7 @@ en:
428
437
  languages: "Languages"
429
438
  layoutpages: "Global Pages"
430
439
  library: "Library"
440
+ menus: "Menus"
431
441
  pages: "Pages"
432
442
  tags: "Tags"
433
443
  sites: "Sites"
@@ -435,7 +445,7 @@ en:
435
445
  users: "Users"
436
446
  name: "Name"
437
447
  names: "Names"
438
- navigation_name: "Navigation name"
448
+ node_url_hint: "Please use either a leading slash (/) or an url with protocol (ie. https:)"
439
449
  no_image_for_cropper_found: "No image found. Please save the element first."
440
450
  no: "No"
441
451
  "no pages": "no pages"
@@ -445,13 +455,12 @@ en:
445
455
  no_files_in_archive: "You do not have any files in your archive."
446
456
  no_images_in_archive: "You don't have any images in your archive."
447
457
  no_more_elements_to_add: "No more elements available."
458
+ no_resource_found: "No %{resource} found. Please add your first one below."
448
459
  no_search_results: "Your search did not return any results."
449
460
  "not a valid image": "This is not an valid image."
450
461
  "or": 'or'
451
462
  or_replace_it_with_an_existing_tag: 'Or replace it with an existing tag'
452
463
  "Page created": "Page: '%{name}' created."
453
- page_for_links:
454
- choose_page: "Choose %{name}"
455
464
  page_infos: 'Page info'
456
465
  page_layout_changed_notice: "Page type was changed. Elements not usable anymore have been moved into the trash."
457
466
  page_properties: "Page properties"
@@ -524,7 +533,6 @@ en:
524
533
  select_element: "Select element"
525
534
  seperate_tags_with_comma: "Seperate tags with comma"
526
535
  show_element_content: "Show content of this element."
527
- show_elements_from_page: "Show all elements from this page"
528
536
  show_eq: "Show EQ"
529
537
  show_navigation: "Show in navigation"
530
538
  show_page_in_sitemap: "Show page in sitemap."
@@ -704,6 +712,9 @@ en:
704
712
  alchemy/language:
705
713
  one: "Language"
706
714
  other: "Languages"
715
+ alchemy/node:
716
+ one: "Menu node"
717
+ other: "Menu nodes"
707
718
  alchemy/page:
708
719
  one: "Page"
709
720
  other: "Pages"
@@ -762,6 +773,13 @@ en:
762
773
  code: ISO Code
763
774
  alchemy/legacy_page_url:
764
775
  urlname: "URL path"
776
+ alchemy/node:
777
+ name: "Name"
778
+ title: "Title"
779
+ nofollow: "Search engine must not follow"
780
+ url: "URL"
781
+ page: "Page"
782
+ external: "Open link in new tab"
765
783
  alchemy/page:
766
784
  created_at: "Created at"
767
785
  language: "Language"
@@ -17,13 +17,18 @@ Alchemy::Engine.routes.draw do
17
17
  namespace :admin, {path: Alchemy.admin_path, constraints: Alchemy.admin_constraints} do
18
18
  resources :contents, only: [:create]
19
19
 
20
+ resources :nodes do
21
+ member do
22
+ patch :toggle
23
+ end
24
+ end
25
+
20
26
  resources :pages do
21
27
  resources :elements
22
28
  collection do
23
29
  post :order
24
30
  post :flush
25
31
  post :copy_language_tree
26
- get :switch_language
27
32
  get :create_language
28
33
  get :link
29
34
  get :sort
@@ -43,7 +48,6 @@ Alchemy::Engine.routes.draw do
43
48
  resources :elements do
44
49
  resources :contents
45
50
  collection do
46
- get :list
47
51
  post :order
48
52
  end
49
53
  member do
@@ -88,7 +92,11 @@ Alchemy::Engine.routes.draw do
88
92
  end
89
93
 
90
94
  resources :legacy_page_urls
91
- resources :languages
95
+ resources :languages do
96
+ collection do
97
+ get :switch
98
+ end
99
+ end
92
100
 
93
101
  resource :clipboard, only: :index, controller: 'clipboard' do
94
102
  collection do
@@ -0,0 +1,8 @@
1
+ class CreateAlchemyEssencePages < ActiveRecord::Migration[5.0]
2
+ def change
3
+ create_table :alchemy_essence_pages do |t|
4
+ t.references :page, null: true, foreign_key: { to_table: :alchemy_pages }
5
+ t.timestamps
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,24 @@
1
+ class CreateAlchemyNodes < ActiveRecord::Migration[5.0]
2
+ def change
3
+ create_table :alchemy_nodes do |t|
4
+ t.string :name
5
+ t.string :title
6
+ t.string :url
7
+ t.boolean :nofollow, null: false, default: false
8
+ t.boolean :external, null: false, default: false
9
+ t.boolean :folded, null: false, default: false
10
+
11
+ t.integer :parent_id, index: true
12
+ t.integer :lft, null: false, index: true
13
+ t.integer :rgt, null: false, index: true
14
+ t.integer :depth, null: false, default: 0
15
+
16
+ t.references :page, foreign_key: { to_table: :alchemy_pages, on_delete: :cascade }
17
+ t.references :language, null: false, foreign_key: { to_table: :alchemy_languages }
18
+ t.references :creator, index: true
19
+ t.references :updater, index: true
20
+
21
+ t.timestamps
22
+ end
23
+ end
24
+ end
@@ -41,7 +41,7 @@ module Alchemy
41
41
  #
42
42
  def available_locale
43
43
  locales = [params[:admin_locale], locale_from_user, locale_from_browser].compact.map(&:to_sym)
44
- locales.detect { |locale| ::I18n.available_locales.include?(locale) }
44
+ locales.detect { |locale| Alchemy::I18n.available_locales.include?(locale) }
45
45
  end
46
46
 
47
47
  # Try to get the locale from user settings.
@@ -9,6 +9,7 @@
9
9
  # +Alchemy.signup_path defaults to +'/signup'+
10
10
  # +Alchemy.login_path defaults to +'/login'+
11
11
  # +Alchemy.logout_path defaults to +'/logout'+
12
+ # +Alchemy.logout_method defaults to +'delete'+
12
13
  #
13
14
  # Anyway, you can tell Alchemy about your authentication model configuration:
14
15
  #
@@ -18,6 +19,7 @@
18
19
  # 3. The path to the signup form - @see: Alchemy.signup_path
19
20
  # 4. The path to the login form - @see: Alchemy.login_path
20
21
  # 5. The path to the logout method - @see: Alchemy.logout_path
22
+ # 6. The http verb for the logout method - @see: Alchemy.logout_method
21
23
  #
22
24
  # == Example
23
25
  #
@@ -27,6 +29,7 @@
27
29
  # Alchemy.signup_path = '/auth/signup'
28
30
  # Alchemy.login_path = '/auth/login'
29
31
  # Alchemy.logout_path = '/auth/logout'
32
+ # Alchemy.logout_method = 'get'
30
33
  #
31
34
  # If you don't have your own user model or don't want to provide one,
32
35
  # add the `alchemy-devise` gem into your App's Gemfile.
@@ -42,7 +45,8 @@ module Alchemy
42
45
  :current_user_method,
43
46
  :signup_path,
44
47
  :login_path,
45
- :logout_path
48
+ :logout_path,
49
+ :logout_method
46
50
 
47
51
  # Defaults
48
52
  #
@@ -51,6 +55,7 @@ module Alchemy
51
55
  @@signup_path = '/signup'
52
56
  @@login_path = '/login'
53
57
  @@logout_path = '/logout'
58
+ @@logout_method = 'delete'
54
59
 
55
60
  # Returns the user class
56
61
  #
@@ -80,7 +85,8 @@ module Alchemy
80
85
  Please add a user class and tell Alchemy about it or, if you don't want
81
86
  to create your own class, add the `alchemy-devise` gem to your Gemfile.
82
87
 
83
- gem 'alchemy-devise', '~> 2.1.0'
88
+ bundle add alchemy-devise
89
+
84
90
  MSG
85
91
  else
86
92
  raise e
@@ -15,12 +15,15 @@ module Alchemy
15
15
  case @name.to_s
16
16
  when /^alchemy\/pages\/show/
17
17
  PageLayout.all.map { |p| "alchemy/page_layouts/_#{p['name']}" }
18
- when /^alchemy\/page_layouts\/_(.+)/
18
+ when /^alchemy\/page_layouts\/_(\w+)/
19
19
  page_layout = PageLayout.get($1)
20
- page_layout.fetch('elements', []).map { |name| "alchemy/elements/_#{name}_view" }
21
- when /alchemy\/elements\/_(.+)_view/
22
- essences = essence_types($1)
23
- essences.map { |name| "alchemy/essences/_#{name.underscore}_view" }.uniq
20
+ layout_elements = page_layout.fetch('elements', [])
21
+ layout_elements.map { |name| "alchemy/elements/_#{name}_view" } +
22
+ layout_elements.map { |name| "alchemy/elements/_#{name}" }
23
+ when /^alchemy\/elements\/_(\w+)_view/, /^alchemy\/elements\/_(\w+)/
24
+ essence_types($1).map { |name|
25
+ "alchemy/essences/_#{name.underscore}_view"
26
+ }.uniq
24
27
  else
25
28
  ActionView::DependencyTracker::ERBTracker.call(@name, @template)
26
29
  end
@@ -57,13 +57,15 @@ module Alchemy
57
57
 
58
58
  attr_reader :page, :options
59
59
 
60
- def find_elements(page)
61
- elements = Alchemy::Element
62
- .where(page_id: page_ids(page))
63
- .merge(Alchemy::Element.not_nested)
64
- .where(fixed: !!options[:fixed])
65
- .order(position: :asc)
66
- .available
60
+ def find_elements(page_or_layout)
61
+ @page = get_page(page_or_layout)
62
+ return Alchemy::Element.none unless page
63
+
64
+ if options[:fixed]
65
+ elements = page.fixed_elements
66
+ else
67
+ elements = page.elements
68
+ end
67
69
 
68
70
  if options[:only]
69
71
  elements = elements.named(options[:only])
@@ -76,15 +78,16 @@ module Alchemy
76
78
  elements
77
79
  end
78
80
 
79
- def page_ids(page)
80
- case page
81
+ def get_page(page_or_layout)
82
+ case page_or_layout
83
+ when Alchemy::Page
84
+ page_or_layout
81
85
  when String
82
- Alchemy::Language.current.pages.where(
83
- page_layout: page,
86
+ Alchemy::Page.find_by(
87
+ language: Alchemy::Language.current,
88
+ page_layout: page_or_layout,
84
89
  restricted: false
85
- ).pluck("#{Alchemy::Page.table_name}.id")
86
- when Alchemy::Page
87
- page.id
90
+ )
88
91
  end
89
92
  end
90
93
 
@@ -4,6 +4,10 @@ module Alchemy
4
4
  engine_name 'alchemy'
5
5
  config.mount_at = '/'
6
6
 
7
+ initializer 'alchemy.lookup_context' do
8
+ Alchemy::LOOKUP_CONTEXT = ActionView::LookupContext.new(Rails.root.join('app', 'views', 'alchemy'))
9
+ end
10
+
7
11
  initializer 'alchemy.dependency_tracker' do
8
12
  [:erb, :slim, :haml].each do |handler|
9
13
  ActionView::DependencyTracker.register_tracker(handler, CacheDigests::TemplateTracker)
@@ -3,6 +3,18 @@
3
3
  require 'active_record'
4
4
 
5
5
  module Alchemy #:nodoc:
6
+ # A bogus association that skips eager loading for essences not having an ingredient association
7
+ class IngredientAssociation < ActiveRecord::Associations::BelongsToAssociation
8
+ # Skip eager loading if called by Rails' preloader
9
+ def klass
10
+ if caller.any? { |line| line =~ /preloader\.rb/ }
11
+ nil
12
+ else
13
+ super
14
+ end
15
+ end
16
+ end
17
+
6
18
  module Essence #:nodoc:
7
19
  def self.included(base)
8
20
  base.extend(ClassMethods)
@@ -31,13 +43,15 @@ module Alchemy #:nodoc:
31
43
  ingredient_column: 'body'
32
44
  }.update(options)
33
45
 
46
+ @_classes_with_ingredient_association ||= []
47
+
34
48
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
35
49
  attr_writer :validation_errors
36
50
  include Alchemy::Essence::InstanceMethods
37
51
  stampable stamper_class_name: Alchemy.user_class_name
38
52
  validate :validate_ingredient, on: :update, if: -> { validations.any? }
39
53
 
40
- has_one :content, as: :essence, class_name: "Alchemy::Content"
54
+ has_one :content, as: :essence, class_name: "Alchemy::Content", inverse_of: :essence
41
55
  has_one :element, through: :content, class_name: "Alchemy::Element"
42
56
  has_one :page, through: :element, class_name: "Alchemy::Page"
43
57
 
@@ -66,8 +80,31 @@ module Alchemy #:nodoc:
66
80
  '#{configuration[:preview_text_column] || configuration[:ingredient_column]}'
67
81
  end
68
82
  RUBY
83
+
84
+ if configuration[:belongs_to]
85
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
86
+ belongs_to :ingredient_association, #{configuration[:belongs_to]}
87
+
88
+ alias_method :#{configuration[:ingredient_column]}, :ingredient_association
89
+ alias_method :#{configuration[:ingredient_column]}=, :ingredient_association=
90
+ RUBY
91
+
92
+ @_classes_with_ingredient_association << self
93
+ end
69
94
  end
70
95
 
96
+ # Overwrite ActiveRecords method to return a bogus association class that skips eager loading
97
+ # for essence classes that do not have an ingredient association
98
+ def _reflect_on_association(name)
99
+ if name == :ingredient_association && !in?(@_classes_with_ingredient_association)
100
+ OpenStruct.new(association_class: Alchemy::IngredientAssociation)
101
+ else
102
+ super
103
+ end
104
+ end
105
+
106
+ private
107
+
71
108
  # Register the current class as has_many association on +Alchemy::Page+ and +Alchemy::Element+ models
72
109
  def register_as_essence_association!
73
110
  klass_name = model_name.to_s
@@ -231,4 +268,5 @@ module Alchemy #:nodoc:
231
268
  end
232
269
  end
233
270
  end
234
- ActiveRecord::Base.class_eval { include Alchemy::Essence } if defined?(Alchemy::Essence)
271
+
272
+ ActiveRecord::Base.include(Alchemy::Essence)