alchemy_cms 7.3.5 → 7.4.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.
Files changed (128) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +60 -0
  3. data/Gemfile +3 -3
  4. data/README.md +2 -2
  5. data/alchemy_cms.gemspec +1 -4
  6. data/app/assets/builds/alchemy/admin.css +9 -1
  7. data/app/assets/builds/alchemy/admin.css.map +1 -1
  8. data/app/assets/builds/alchemy/custom-properties.css +1 -1
  9. data/app/assets/builds/alchemy/custom-properties.css.map +1 -1
  10. data/app/assets/builds/alchemy/preview.min.js +1 -0
  11. data/app/assets/builds/alchemy/welcome.css +1 -1
  12. data/app/assets/builds/alchemy/welcome.css.map +1 -1
  13. data/app/assets/builds/tinymce/skins/content/alchemy/content.min.css +1 -1
  14. data/app/assets/builds/tinymce/skins/content/alchemy/content.min.css.map +1 -1
  15. data/app/assets/config/alchemy_manifest.js +0 -4
  16. data/app/assets/javascripts/alchemy/admin.js +8 -6
  17. data/app/assets/stylesheets/alchemy/admin/elements.scss +43 -7
  18. data/app/assets/stylesheets/alchemy/admin/forms.scss +4 -0
  19. data/app/assets/stylesheets/alchemy/admin/navigation.scss +9 -1
  20. data/app/assets/stylesheets/alchemy/admin/preview_window.scss +22 -17
  21. data/app/assets/stylesheets/alchemy/admin.scss +1 -1
  22. data/app/assets/stylesheets/alchemy/custom-properties.css +2 -1
  23. data/app/components/alchemy/ingredients/link_view.rb +7 -1
  24. data/app/components/alchemy/ingredients/picture_view.rb +5 -2
  25. data/app/components/alchemy/ingredients/text_view.rb +4 -1
  26. data/app/components/concerns/alchemy/ingredients/link_target.rb +18 -0
  27. data/app/controllers/alchemy/admin/base_controller.rb +8 -3
  28. data/app/controllers/alchemy/admin/elements_controller.rb +2 -2
  29. data/app/controllers/alchemy/admin/layoutpages_controller.rb +1 -0
  30. data/app/controllers/alchemy/admin/pages_controller.rb +5 -1
  31. data/app/controllers/alchemy/elements_controller.rb +3 -0
  32. data/app/helpers/alchemy/admin/form_helper.rb +1 -1
  33. data/app/helpers/alchemy/admin/navigation_helper.rb +22 -1
  34. data/app/javascript/alchemy_admin/components/action.js +2 -1
  35. data/app/javascript/alchemy_admin/components/dialog_link.js +3 -18
  36. data/app/javascript/alchemy_admin/components/element_editor.js +9 -0
  37. data/app/javascript/alchemy_admin/components/elements_window.js +34 -0
  38. data/app/javascript/alchemy_admin/components/elements_window_handle.js +65 -0
  39. data/app/javascript/alchemy_admin/components/icon.js +2 -2
  40. data/app/javascript/alchemy_admin/components/index.js +1 -0
  41. data/app/javascript/alchemy_admin/components/preview_window.js +5 -5
  42. data/app/javascript/alchemy_admin/components/uploader/file_upload.js +1 -1
  43. data/app/javascript/alchemy_admin/confirm_dialog.js +9 -11
  44. data/app/javascript/alchemy_admin/dialog.js +329 -0
  45. data/app/javascript/alchemy_admin/hotkeys.js +3 -2
  46. data/app/javascript/alchemy_admin/image_cropper.js +56 -48
  47. data/app/javascript/alchemy_admin/image_overlay.js +73 -0
  48. data/app/javascript/alchemy_admin/initializer.js +51 -2
  49. data/app/javascript/alchemy_admin/link_dialog.js +2 -1
  50. data/app/javascript/alchemy_admin/node_tree.js +3 -1
  51. data/app/javascript/alchemy_admin/page_sorter.js +1 -1
  52. data/app/javascript/alchemy_admin/picture_selector.js +2 -1
  53. data/app/javascript/alchemy_admin/shoelace_theme.js +2 -2
  54. data/app/javascript/alchemy_admin/templates/compiled.js +1 -0
  55. data/app/javascript/alchemy_admin.js +10 -6
  56. data/app/javascript/preview.js +117 -0
  57. data/app/models/alchemy/image_cropper_settings.rb +3 -4
  58. data/app/views/alchemy/_preview_mode_code.html.erb +1 -1
  59. data/app/views/alchemy/admin/crop.html.erb +18 -16
  60. data/app/views/alchemy/admin/dashboard/info.html.erb +1 -1
  61. data/app/views/alchemy/admin/elements/_add_nested_element_form.html.erb +9 -8
  62. data/app/views/alchemy/admin/elements/_clipboard_button.html.erb +14 -0
  63. data/app/views/alchemy/admin/elements/_element.html.erb +2 -0
  64. data/app/views/alchemy/admin/elements/_form.html.erb +15 -13
  65. data/app/views/alchemy/admin/elements/create.turbo_stream.erb +34 -0
  66. data/app/views/alchemy/admin/elements/index.html.erb +3 -15
  67. data/app/views/alchemy/admin/ingredients/_picture_fields.html.erb +1 -1
  68. data/app/views/alchemy/admin/layoutpages/edit.html.erb +7 -5
  69. data/app/views/alchemy/admin/nodes/_form.html.erb +1 -1
  70. data/app/views/alchemy/admin/pages/_current_page.html.erb +1 -1
  71. data/app/views/alchemy/admin/pages/_form.html.erb +43 -40
  72. data/app/views/alchemy/admin/pages/_locked_page.html.erb +1 -1
  73. data/app/views/alchemy/admin/pages/_page_layout_filter.html.erb +1 -1
  74. data/app/views/alchemy/admin/pages/_sitemap.html.erb +1 -1
  75. data/app/views/alchemy/admin/pages/_table.html.erb +2 -2
  76. data/app/views/alchemy/admin/pages/edit.html.erb +1 -1
  77. data/app/views/alchemy/admin/pages/update.turbo_stream.erb +39 -0
  78. data/app/views/alchemy/admin/partials/_main_navigation_entry.html.erb +3 -4
  79. data/app/views/alchemy/admin/pictures/_picture_description_field.html.erb +7 -5
  80. data/app/views/alchemy/admin/pictures/index.html.erb +13 -9
  81. data/app/views/alchemy/admin/resources/_filter_bar.html.erb +1 -1
  82. data/app/views/layouts/alchemy/admin.html.erb +8 -4
  83. data/bun.lockb +0 -0
  84. data/bundles/tinymce.js +2 -0
  85. data/config/alchemy/config.yml +3 -3
  86. data/config/alchemy/modules.yml +7 -6
  87. data/config/importmap.rb +4 -0
  88. data/config/routes.rb +1 -1
  89. data/lib/alchemy/engine.rb +6 -0
  90. data/lib/alchemy/modules.rb +0 -27
  91. data/lib/alchemy/test_support/having_picture_thumbnails_examples.rb +10 -10
  92. data/lib/alchemy/tinymce.rb +2 -1
  93. data/lib/alchemy/upgrader/seven_point_four.rb +26 -0
  94. data/lib/alchemy/version.rb +1 -1
  95. data/lib/alchemy.rb +14 -0
  96. data/lib/alchemy_cms.rb +0 -2
  97. data/lib/generators/alchemy/ingredient/ingredient_generator.rb +5 -0
  98. data/lib/generators/alchemy/ingredient/templates/view.html.erb +1 -1
  99. data/lib/generators/alchemy/ingredient/templates/view_component.rb.tt +10 -0
  100. data/lib/generators/alchemy/install/install_generator.rb +0 -1
  101. data/lib/generators/alchemy/install/templates/elements.yml.tt +1 -1
  102. data/lib/tasks/alchemy/upgrade.rake +19 -20
  103. data/rollup.config.mjs +44 -1
  104. data/vendor/javascript/cropperjs.min.js +10 -0
  105. data/vendor/javascript/handlebars.min.js +29 -0
  106. data/vendor/javascript/jquery.min.js +2 -0
  107. data/vendor/javascript/select2.min.js +23 -0
  108. data/vendor/javascript/tinymce.min.js +1 -1
  109. metadata +40 -92
  110. data/app/assets/javascripts/alchemy/alchemy.dialog.js.coffee +0 -271
  111. data/app/assets/javascripts/alchemy/alchemy.image_overlay.coffee +0 -54
  112. data/app/assets/javascripts/alchemy/alchemy.preview.js.coffee +0 -97
  113. data/app/assets/javascripts/alchemy/preview.js +0 -1
  114. data/app/assets/javascripts/alchemy/templates/index.js +0 -2
  115. data/app/javascript/alchemy_admin/gui.js +0 -12
  116. data/app/views/alchemy/admin/elements/create.js.erb +0 -35
  117. data/app/views/alchemy/admin/pages/update.js.erb +0 -43
  118. data/lib/alchemy/upgrader/seven_point_zero.rb +0 -36
  119. data/vendor/assets/images/Jcrop.gif +0 -0
  120. data/vendor/assets/javascripts/jquery_plugins/jquery.Jcrop.min.js +0 -7
  121. data/vendor/assets/javascripts/jquery_plugins/select2.js +0 -3729
  122. data/vendor/assets/stylesheets/jquery.Jcrop.min.css +0 -2
  123. data/vendor/assets/stylesheets/tinymce/skins/content/default/content.min.css +0 -1
  124. /data/app/{assets/javascripts/alchemy → javascript/alchemy_admin}/templates/node_folder.hbs +0 -0
  125. /data/app/{assets/javascripts/alchemy → javascript/alchemy_admin}/templates/page_folder.hbs +0 -0
  126. /data/app/{assets/javascripts/tinymce/icons/remixicons/icons.js → javascript/tinymce/icons/remixicons/index.js} +0 -0
  127. /data/app/{assets/javascripts/tinymce/plugins/alchemy_link/plugin.min.js → javascript/tinymce/plugins/alchemy_link/index.js} +0 -0
  128. /data/vendor/assets/{fonts → images}/remixicon.symbol.svg +0 -0
@@ -1 +1 @@
1
- {"version":3,"sourceRoot":"","sources":["../../stylesheets/alchemy/custom-properties.css","../../stylesheets/alchemy/_fonts.scss","../../stylesheets/alchemy/welcome.scss","../../stylesheets/alchemy/_variables.scss"],"names":[],"mappings":"AAAA,MAEE,iBACA,iBACA,iBACA,kBACA,kBACA,kBACA,kBACA,kBACA,kBAGA,wBACA,yBACA,qBACA,uBACA,uBACA,wBAGA,8FAEA,6GAIA,wBACA,yBACA,wBAEA,0BACA,wBAGA,4BAGA,+CACA,0CACA,2CACA,yCAEA,+CACA,2CACA,4CACA,0CAEA,2CACA,4CACA,0CAEA,6CACA,0CACA,+CAEA,4CACA,uCACA,wCACA,sCAEA,4CACA,uCACA,wCACA,sCACA,2CAEA,mCAEA,0CACA,gDACA,2CAGF,eACE,0CAEA,6CACA,wCAEA,iDACA,4CACA,0CAEA,yDACA,sEACA,iEACA,+DAEA,0EACA,uEACA,wEACA,6EACA,iFC7FF,WACE,wBACA,ylxFACA,gBACA,kBAGF,WACE,wBACA,i7wFACA,gBACA,kBCPF,KACE,iBCgImB,uBD/HnB,yBACA,YCiBoB,0FDhBpB,mBACA,eACA,iBAGF,GACE,iBACA,eACA,gBACA,mBACA,iBAGF,WACE,kBACA,QACA,SACA,YACA,iBACA,8CAGF,GACE,gBACA,mBACA,UACA,kBACA,WACA,4BAEA,MACE,yBACA,mBACA,sBACA,qBACA,iBAIJ,EACE,yBACA,0BACA,+BAEA,QACE,yBACA","file":"welcome.css"}
1
+ {"version":3,"sourceRoot":"","sources":["../../stylesheets/alchemy/custom-properties.css","../../stylesheets/alchemy/_fonts.scss","../../stylesheets/alchemy/welcome.scss","../../stylesheets/alchemy/_variables.scss"],"names":[],"mappings":"AAAA,MAEE,iBACA,iBACA,iBACA,kBACA,kBACA,kBACA,kBACA,kBACA,kBAGA,wBACA,yBACA,qBACA,uBACA,uBACA,wBAGA,8FAEA,6GAIA,wBACA,yBACA,wBAEA,0BACA,wBAGA,4BACA,0BAGA,+CACA,0CACA,2CACA,yCAEA,+CACA,2CACA,4CACA,0CAEA,2CACA,4CACA,0CAEA,6CACA,0CACA,+CAEA,4CACA,uCACA,wCACA,sCAEA,4CACA,uCACA,wCACA,sCACA,2CAEA,mCAEA,0CACA,gDACA,2CAGF,eACE,0CAEA,6CACA,wCAEA,iDACA,4CACA,0CAEA,yDACA,sEACA,iEACA,+DAEA,0EACA,uEACA,wEACA,6EACA,iFC9FF,WACE,wBACA,ylxFACA,gBACA,kBAGF,WACE,wBACA,i7wFACA,gBACA,kBCPF,KACE,iBCgImB,uBD/HnB,yBACA,YCiBoB,0FDhBpB,mBACA,eACA,iBAGF,GACE,iBACA,eACA,gBACA,mBACA,iBAGF,WACE,kBACA,QACA,SACA,YACA,iBACA,8CAGF,GACE,gBACA,mBACA,UACA,kBACA,WACA,4BAEA,MACE,yBACA,mBACA,sBACA,qBACA,iBAIJ,EACE,yBACA,0BACA,+BAEA,QACE,yBACA","file":"welcome.css"}
@@ -1 +1 @@
1
- :root{--spacing-0: 2px;--spacing-1: 4px;--spacing-2: 8px;--spacing-3: 12px;--spacing-4: 16px;--spacing-5: 20px;--spacing-6: 24px;--spacing-7: 28px;--spacing-8: 32px;--icon-size-xs: 0.75rem;--icon-size-sm: 0.875rem;--icon-size-1x: 1rem;--icon-size-md: 1.3rem;--icon-size-xl: 1.5rem;--icon-size-xxl: 1.6rem;--font-mono: Menlo, Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace;--font-sans: "Open Sans", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Verdana, Tahoma, sans-serif;--font-size_small: 10px;--font-size_medium: 12px;--font-size_large: 16px;--font-weigth_normal: 500;--font-weigth_bold: 700;--border-radius_medium: 3px;--color-blue_very_light: hsl(203deg, 32%, 97%);--color-blue_light: hsl(203deg, 32%, 85%);--color-blue_medium: hsl(212deg, 52%, 36%);--color-blue_dark: hsl(212deg, 52%, 26%);--color-green_very_light: hsl(88deg, 47%, 88%);--color-green_light: hsl(127deg, 25%, 69%);--color-green_medium: hsl(127deg, 25%, 48%);--color-green_dark: hsl(128deg, 32%, 26%);--color-yellow_light: hsl(60deg, 81%, 92%);--color-yellow_medium: hsl(56deg, 68%, 85%);--color-yellow_dark: hsl(56deg, 53%, 29%);--color-orange_medium: hsl(42deg, 100%, 74%);--color-orange_dark: hsl(28deg, 77%, 68%);--color-orange_very_dark: hsl(28deg, 77%, 48%);--color-red_very_light: hsl(0deg, 47%, 88%);--color-red_light: hsl(0deg, 25%, 69%);--color-red_medium: hsl(0deg, 51%, 42%);--color-red_dark: hsl(0deg, 51%, 25%);--color-grey_very_light: hsl(0deg, 0%, 97%);--color-grey_light: hsl(0deg, 0%, 94%);--color-grey_medium: hsl(0deg, 0%, 78%);--color-grey_dark: hsl(0deg, 0%, 40%);--color-grey_very_dark: hsl(0deg, 0%, 20%);--color-white: hsl(0deg, 0%, 100%);--color-text: hsla(224deg, 23%, 26%, 0.8);--color-text_muted: hsla(224deg, 23%, 26%, 0.5);--color-icon: hsla(224deg, 23%, 26%, 0.75)}.alchemy-light{--outline-color: var(--color-orange_dark);--font-color_failed: var(--color-red_medium);--font-color_default: var(--color-text);--tabs_indicator-color: var(--color-orange_dark);--tabs_track-color: var(--color-grey_light);--sl-input-label-color: var(--color-text);--file-upload_background-color: hsla(0deg, 0%, 80%, 0.8);--file-upload_single-upload-background-color: var(--color-grey_light);--file-upload_progress-track-color: var(--color-blue_very_light);--file-upload_progress-indicator-color: var(--color-blue_dark);--file-upload_progress-indicator-color-canceled: hsla(0deg, 0%, 60%, 0.8);--file-upload_progress-indicator-color-failed: var(--color-red_medium);--file-upload_progress-indicator-color-invalid: var(--color-red_medium);--file-upload_progress-indicator-color-successful: var(--color-green_medium);--file-upload_progress-indicator-color-upload-finished: var( --color-blue_dark )}html{font-size:13px}body{font-family:"Open Sans","Lucida Grande","Lucida Sans Unicode","Lucida Sans",Verdana,Tahoma,sans-serif;line-height:1.4;margin:1em;color:var(--color-text)}a{color:var(--color-blue_dark)}table{border-collapse:collapse}table td,table th{border:1px solid rgba(176,176,176,.5);padding:.4rem}figure{display:table;margin:1rem auto}figure figcaption{color:var(--color-grey_dark);display:block;margin-top:.25rem;text-align:center}hr{border-color:rgba(176,176,176,.5);border-style:solid;border-width:1px 0 0 0}code{background-color:var(--color-grey_very_light);border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid rgba(176,176,176,.5);margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid rgba(176,176,176,.5);margin-right:1.5rem;padding-right:1rem}/*# sourceMappingURL=content.min.css.map */
1
+ :root{--spacing-0: 2px;--spacing-1: 4px;--spacing-2: 8px;--spacing-3: 12px;--spacing-4: 16px;--spacing-5: 20px;--spacing-6: 24px;--spacing-7: 28px;--spacing-8: 32px;--icon-size-xs: 0.75rem;--icon-size-sm: 0.875rem;--icon-size-1x: 1rem;--icon-size-md: 1.3rem;--icon-size-xl: 1.5rem;--icon-size-xxl: 1.6rem;--font-mono: Menlo, Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace;--font-sans: "Open Sans", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Verdana, Tahoma, sans-serif;--font-size_small: 10px;--font-size_medium: 12px;--font-size_large: 16px;--font-weigth_normal: 500;--font-weigth_bold: 700;--border-radius_medium: 3px;--border-width_small: 1px;--color-blue_very_light: hsl(203deg, 32%, 97%);--color-blue_light: hsl(203deg, 32%, 85%);--color-blue_medium: hsl(212deg, 52%, 36%);--color-blue_dark: hsl(212deg, 52%, 26%);--color-green_very_light: hsl(88deg, 47%, 88%);--color-green_light: hsl(127deg, 25%, 69%);--color-green_medium: hsl(127deg, 25%, 48%);--color-green_dark: hsl(128deg, 32%, 26%);--color-yellow_light: hsl(60deg, 81%, 92%);--color-yellow_medium: hsl(56deg, 68%, 85%);--color-yellow_dark: hsl(56deg, 53%, 29%);--color-orange_medium: hsl(42deg, 100%, 74%);--color-orange_dark: hsl(28deg, 77%, 68%);--color-orange_very_dark: hsl(28deg, 77%, 48%);--color-red_very_light: hsl(0deg, 47%, 88%);--color-red_light: hsl(0deg, 25%, 69%);--color-red_medium: hsl(0deg, 51%, 42%);--color-red_dark: hsl(0deg, 51%, 25%);--color-grey_very_light: hsl(0deg, 0%, 97%);--color-grey_light: hsl(0deg, 0%, 94%);--color-grey_medium: hsl(0deg, 0%, 78%);--color-grey_dark: hsl(0deg, 0%, 40%);--color-grey_very_dark: hsl(0deg, 0%, 20%);--color-white: hsl(0deg, 0%, 100%);--color-text: hsla(224deg, 23%, 26%, 0.8);--color-text_muted: hsla(224deg, 23%, 26%, 0.5);--color-icon: hsla(224deg, 23%, 26%, 0.75)}.alchemy-light{--outline-color: var(--color-orange_dark);--font-color_failed: var(--color-red_medium);--font-color_default: var(--color-text);--tabs_indicator-color: var(--color-orange_dark);--tabs_track-color: var(--color-grey_light);--sl-input-label-color: var(--color-text);--file-upload_background-color: hsla(0deg, 0%, 80%, 0.8);--file-upload_single-upload-background-color: var(--color-grey_light);--file-upload_progress-track-color: var(--color-blue_very_light);--file-upload_progress-indicator-color: var(--color-blue_dark);--file-upload_progress-indicator-color-canceled: hsla(0deg, 0%, 60%, 0.8);--file-upload_progress-indicator-color-failed: var(--color-red_medium);--file-upload_progress-indicator-color-invalid: var(--color-red_medium);--file-upload_progress-indicator-color-successful: var(--color-green_medium);--file-upload_progress-indicator-color-upload-finished: var( --color-blue_dark )}html{font-size:13px}body{font-family:"Open Sans","Lucida Grande","Lucida Sans Unicode","Lucida Sans",Verdana,Tahoma,sans-serif;line-height:1.4;margin:1em;color:var(--color-text)}a{color:var(--color-blue_dark)}table{border-collapse:collapse}table td,table th{border:1px solid rgba(176,176,176,.5);padding:.4rem}figure{display:table;margin:1rem auto}figure figcaption{color:var(--color-grey_dark);display:block;margin-top:.25rem;text-align:center}hr{border-color:rgba(176,176,176,.5);border-style:solid;border-width:1px 0 0 0}code{background-color:var(--color-grey_very_light);border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid rgba(176,176,176,.5);margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid rgba(176,176,176,.5);margin-right:1.5rem;padding-right:1rem}/*# sourceMappingURL=content.min.css.map */
@@ -1 +1 @@
1
- {"version":3,"sourceRoot":"","sources":["../../../../../stylesheets/alchemy/custom-properties.css","../../../../../stylesheets/tinymce/skins/content/alchemy/content.scss","../../../../../stylesheets/alchemy/_variables.scss"],"names":[],"mappings":"AAAA,MAEE,iBACA,iBACA,iBACA,kBACA,kBACA,kBACA,kBACA,kBACA,kBAGA,wBACA,yBACA,qBACA,uBACA,uBACA,wBAGA,8FAEA,6GAIA,wBACA,yBACA,wBAEA,0BACA,wBAGA,4BAGA,+CACA,0CACA,2CACA,yCAEA,+CACA,2CACA,4CACA,0CAEA,2CACA,4CACA,0CAEA,6CACA,0CACA,+CAEA,4CACA,uCACA,wCACA,sCAEA,4CACA,uCACA,wCACA,sCACA,2CAEA,mCAEA,0CACA,gDACA,2CAGF,eACE,0CAEA,6CACA,wCAEA,iDACA,4CACA,0CAEA,yDACA,sEACA,iEACA,+DAEA,0EACA,uEACA,wEACA,6EACA,iFCnFF,KACE,eAGF,KACE,YCSoB,0FDRpB,gBACA,WACA,wBAGF,EACE,6BAGF,MACE,yBAGF,kBAEE,sCACA,cAGF,OACE,cACA,iBAGF,kBACE,6BACA,cACA,kBACA,kBAGF,GACE,aCFqB,qBDGrB,mBACA,uBAGF,KACE,8CACA,cCHsB,IDItB,oBAGF,4CACE,2CACA,mBACA,kBAGF,sCACE,4CACA,oBACA","file":"content.min.css"}
1
+ {"version":3,"sourceRoot":"","sources":["../../../../../stylesheets/alchemy/custom-properties.css","../../../../../stylesheets/tinymce/skins/content/alchemy/content.scss","../../../../../stylesheets/alchemy/_variables.scss"],"names":[],"mappings":"AAAA,MAEE,iBACA,iBACA,iBACA,kBACA,kBACA,kBACA,kBACA,kBACA,kBAGA,wBACA,yBACA,qBACA,uBACA,uBACA,wBAGA,8FAEA,6GAIA,wBACA,yBACA,wBAEA,0BACA,wBAGA,4BACA,0BAGA,+CACA,0CACA,2CACA,yCAEA,+CACA,2CACA,4CACA,0CAEA,2CACA,4CACA,0CAEA,6CACA,0CACA,+CAEA,4CACA,uCACA,wCACA,sCAEA,4CACA,uCACA,wCACA,sCACA,2CAEA,mCAEA,0CACA,gDACA,2CAGF,eACE,0CAEA,6CACA,wCAEA,iDACA,4CACA,0CAEA,yDACA,sEACA,iEACA,+DAEA,0EACA,uEACA,wEACA,6EACA,iFCpFF,KACE,eAGF,KACE,YCSoB,0FDRpB,gBACA,WACA,wBAGF,EACE,6BAGF,MACE,yBAGF,kBAEE,sCACA,cAGF,OACE,cACA,iBAGF,kBACE,6BACA,cACA,kBACA,kBAGF,GACE,aCFqB,qBDGrB,mBACA,uBAGF,KACE,8CACA,cCHsB,IDItB,oBAGF,4CACE,2CACA,mBACA,kBAGF,sCACE,4CACA,oBACA","file":"content.min.css"}
@@ -1,11 +1,7 @@
1
1
  //= link alchemy/admin/all.js
2
- //= link alchemy/preview.js
3
- //= link tinymce/plugins/alchemy_link/plugin.min.js
4
- //= link tinymce/icons/remixicons/icons.js
5
2
  //= link_tree ../builds/alchemy/
6
3
  //= link_tree ../builds/tinymce/
7
4
  //= link_tree ../images/alchemy/
8
- //= link_tree ../../../vendor/assets/fonts/
9
5
  //= link_tree ../../../vendor/assets/images/
10
6
  //= link_tree ../../javascript .js
11
7
  //= link_tree ../../../vendor/javascript .js
@@ -1,8 +1,10 @@
1
1
  // Alchemy CMS Sprockets Manifest
2
2
  // ------------------------------
3
- //= require jquery3
4
- //= require_tree ../../../../vendor/assets/javascripts/jquery_plugins/
5
- //= require handlebars
6
- //= require alchemy/templates
7
- //= require alchemy/alchemy.dialog
8
- //= require alchemy/alchemy.image_overlay
3
+ //
4
+ // This manifest file is deprecated and will be removed in Alchemy 8.0.
5
+ //
6
+
7
+ console.warn(
8
+ "The 'alchemy/admin' Sprockets manifest is deprecated and will be removed in 8.0. " +
9
+ "Please remove 'require alchemy/admin' from your 'vendor/assets/javascripts/alchemy/admin/all.js' file."
10
+ )
@@ -1,10 +1,20 @@
1
+ :root {
2
+ --elements-window-width: 0px;
3
+ --elements-window-min-width: #{$elements-window-min-width};
4
+ }
5
+
1
6
  #alchemy_elements_window {
7
+ --width: var(--elements-window-width, 100vw);
2
8
  position: absolute;
3
9
  right: 0;
4
10
  top: $top-menu-height;
5
11
  z-index: 20;
6
12
  display: block;
7
- width: calc(100vw - #{$collapsed-main-menu-width});
13
+ width: var(--width);
14
+ min-width: var(--elements-window-min-width);
15
+ max-width: calc(
16
+ 100vw - var(--main-menu-width) - var(--preview-window-min-width)
17
+ );
8
18
  height: calc(100vh - #{$top-menu-height});
9
19
  border-left: $default-border;
10
20
  background-color: var(--color-grey_very_light);
@@ -14,15 +24,41 @@
14
24
  .elements-window-visible & {
15
25
  transform: translate3d(0, 0, 0);
16
26
  }
27
+ }
17
28
 
18
- // Fix for Tinymce fullscreen window positioning issues (GH#1511)
19
- .tox-fullscreen & {
20
- width: calc(100vw - #{$collapsed-main-menu-width - $default-border-width});
21
- }
29
+ .elements-window-visible {
30
+ --elements-window-width: calc(100vw - var(--main-menu-width));
22
31
 
23
32
  @media screen and (min-width: $large-screen-break-point) {
24
- width: $elements-window-width;
25
- min-width: $elements-window-min-width;
33
+ --elements-window-width: var(--elements-window-min-width);
34
+ }
35
+
36
+ @media screen and (min-width: $xlarge-screen-break-point) {
37
+ --elements-window-min-width: 475px;
38
+ }
39
+
40
+ // 1778px * 0.225 = 400px (the min width of the elements window)
41
+ @media screen and (min-width: 1778px) {
42
+ --elements-window-width: #{$elements-window-width};
43
+ }
44
+ }
45
+
46
+ alchemy-elements-window-handle {
47
+ --width: var(--spacing-1);
48
+ position: absolute;
49
+ left: calc(-1 * var(--width) / 2);
50
+ top: 0;
51
+ z-index: 1500; // tinymce .tox-fullscreen has 1200
52
+ height: inherit;
53
+ width: var(--width);
54
+ transition-duration: $transition-duration;
55
+ transition-property: background-color width left;
56
+ transition-timing-function: ease-in-out;
57
+
58
+ &:hover,
59
+ &.is-dragged {
60
+ background: var(--color-blue_dark);
61
+ cursor: ew-resize;
26
62
  }
27
63
  }
28
64
 
@@ -43,6 +43,10 @@ form {
43
43
  float: right;
44
44
  }
45
45
 
46
+ textarea {
47
+ padding-top: 7px;
48
+ }
49
+
46
50
  .input > select,
47
51
  .input > .select2-container {
48
52
  width: 100%;
@@ -193,6 +193,14 @@
193
193
  }
194
194
  }
195
195
 
196
+ :root {
197
+ --main-menu-width: #{$main-menu-width};
198
+ }
199
+
200
+ .collapsed-menu {
201
+ --main-menu-width: #{$collapsed-main-menu-width};
202
+ }
203
+
196
204
  @media screen and (min-width: $large-screen-break-point) {
197
205
  body:not(.collapsed-menu) {
198
206
  .sub_navigation {
@@ -222,7 +230,7 @@
222
230
  display: flex;
223
231
  flex-grow: 1;
224
232
  flex-wrap: nowrap;
225
- height: $header-height;
233
+ height: $header-height + 1px;
226
234
 
227
235
  label {
228
236
  float: left;
@@ -1,28 +1,33 @@
1
+ :root {
2
+ --preview-window-min-width: 0px;
3
+
4
+ @media screen and (min-width: $large-screen-break-point) {
5
+ --preview-window-min-width: 240px;
6
+ }
7
+ }
8
+
1
9
  #alchemy_preview_window {
2
10
  position: absolute;
3
- left: $main-menu-width;
11
+ left: var(--main-menu-width);
4
12
  top: 75px;
5
- width: calc(100vw - #{$main-menu-width - $default-border-width});
13
+ width: calc(
14
+ 100vw - var(--main-menu-width) - var(--elements-window-width) +
15
+ var(--border-width_small)
16
+ );
17
+ min-width: var(--preview-window-min-width);
18
+ max-width: calc(100vw - var(--main-menu-width));
6
19
  height: calc(100vh - #{$top-menu-height});
7
20
  border: 0 none;
8
21
  background: #fff;
9
22
  border-right: $default-border;
10
- transition: width $transition-duration ease-in-out;
23
+ transition-duration: $transition-duration;
24
+ transition-timing-function: ease-in-out;
25
+ transition-property: width max-width;
11
26
 
12
- .collapsed-menu & {
13
- left: $collapsed-main-menu-width;
14
- width: calc(100vw - #{$collapsed-main-menu-width - $default-border-width});
15
- }
16
-
17
- .collapsed-menu.elements-window-visible & {
18
- width: calc(
19
- 100vw - #{$collapsed-main-menu-width - $default-border-width} - #{$elements-window-min-width}
27
+ .elements-window-visible & {
28
+ max-width: calc(
29
+ 100vw - var(--main-menu-width) - var(--elements-window-min-width) +
30
+ var(--border-width_small)
20
31
  );
21
-
22
- @media screen and (min-width: 1777px) {
23
- width: calc(
24
- 100vw - #{$collapsed-main-menu-width - $default-border-width} - #{$elements-window-width}
25
- );
26
- }
27
32
  }
28
33
  }
@@ -39,4 +39,4 @@
39
39
  @import "alchemy/admin/toolbar";
40
40
  @import "alchemy/admin/typography";
41
41
  @import "alchemy/admin/upload";
42
- @import "jquery.Jcrop.min";
42
+ @import "cropper.min";
@@ -32,8 +32,9 @@
32
32
  --font-weigth_normal: 500;
33
33
  --font-weigth_bold: 700;
34
34
 
35
- /* border-radius */
35
+ /* Borders */
36
36
  --border-radius_medium: 3px;
37
+ --border-width_small: 1px;
37
38
 
38
39
  /* Colors */
39
40
  --color-blue_very_light: hsl(203deg, 32%, 97%);
@@ -1,6 +1,8 @@
1
1
  module Alchemy
2
2
  module Ingredients
3
3
  class LinkView < BaseView
4
+ include LinkTarget
5
+
4
6
  attr_reader :link_text
5
7
 
6
8
  # @param ingredient [Alchemy::Ingredient]
@@ -12,7 +14,11 @@ module Alchemy
12
14
  end
13
15
 
14
16
  def call
15
- link_to(link_text, value, {target: ingredient.link_target.presence}.merge(html_options)).html_safe
17
+ target = ingredient.link_target.presence
18
+ link_to(link_text, value, {
19
+ target: link_target_value(target),
20
+ rel: link_rel_value(target)
21
+ }.merge(html_options)).html_safe
16
22
  end
17
23
  end
18
24
  end
@@ -4,6 +4,8 @@ module Alchemy
4
4
  module Ingredients
5
5
  # Renders a picture ingredient view
6
6
  class PictureView < BaseView
7
+ include LinkTarget
8
+
7
9
  attr_reader :ingredient,
8
10
  :show_caption,
9
11
  :disable_link,
@@ -46,10 +48,11 @@ module Alchemy
46
48
  output = caption ? img_tag + caption : img_tag
47
49
 
48
50
  if is_linked?
51
+ target = ingredient.link_target.presence
49
52
  output = link_to(output, url_for(ingredient.link), {
50
53
  title: ingredient.link_title.presence,
51
- target: (ingredient.link_target == "blank") ? "_blank" : nil,
52
- data: {link_target: ingredient.link_target.presence}
54
+ rel: link_rel_value(target),
55
+ target: link_target_value(target)
53
56
  })
54
57
  end
55
58
 
@@ -1,6 +1,8 @@
1
1
  module Alchemy
2
2
  module Ingredients
3
3
  class TextView < BaseView
4
+ include LinkTarget
5
+
4
6
  attr_reader :disable_link
5
7
 
6
8
  delegate :dom_id, :link, :link_title, :link_target,
@@ -21,7 +23,8 @@ module Alchemy
21
23
  link_to(value, url_for(link), {
22
24
  id: dom_id.presence,
23
25
  title: link_title,
24
- target: link_target
26
+ target: link_target_value(link_target),
27
+ rel: link_rel_value(link_target)
25
28
  }.merge(html_options))
26
29
  end.html_safe
27
30
  end
@@ -0,0 +1,18 @@
1
+ module Alchemy
2
+ module Ingredients
3
+ module LinkTarget
4
+ BLANK_VALUE = "_blank"
5
+ REL_VALUE = "noopener noreferrer"
6
+
7
+ def link_rel_value(target)
8
+ if link_target_value(target) == BLANK_VALUE
9
+ REL_VALUE
10
+ end
11
+ end
12
+
13
+ def link_target_value(target)
14
+ (target == "blank") ? BLANK_VALUE : target
15
+ end
16
+ end
17
+ end
18
+ end
@@ -133,11 +133,16 @@ module Alchemy
133
133
  def do_redirect_to(url_or_path)
134
134
  redirect_path = safe_redirect_path(url_or_path)
135
135
  respond_to do |format|
136
- format.js {
136
+ format.js do
137
137
  @redirect_url = redirect_path
138
138
  render :redirect
139
- }
140
- format.html { redirect_to redirect_path }
139
+ end
140
+ format.turbo_stream do
141
+ redirect_to(redirect_path, allow_other_host: false)
142
+ end
143
+ format.html do
144
+ redirect_to(redirect_path, allow_other_host: false)
145
+ end
141
146
  end
142
147
  end
143
148
 
@@ -41,12 +41,12 @@ module Alchemy
41
41
  end
42
42
  end
43
43
  if @element.save
44
- render :create
44
+ render :create, status: :created
45
45
  else
46
46
  @element.page_version = @page_version
47
47
  @elements = @page.available_element_definitions
48
48
  load_clipboard_items
49
- render :new
49
+ render :new, status: :unprocessable_entity
50
50
  end
51
51
  end
52
52
 
@@ -22,6 +22,7 @@ module Alchemy
22
22
  @page = Page.find(params[:id])
23
23
  if @page.update(page_params)
24
24
  @notice = Alchemy.t("Page saved", name: @page.name)
25
+ @while_page_edit = request.referer.include?("edit")
25
26
  render "alchemy/admin/pages/update"
26
27
  else
27
28
  render :edit, status: :unprocessable_entity
@@ -29,7 +29,7 @@ module Alchemy
29
29
  unless: -> { @page_root },
30
30
  only: [:index]
31
31
 
32
- before_action :set_view, only: [:index]
32
+ before_action :set_view, only: [:index, :update]
33
33
 
34
34
  before_action :set_page_version, only: [:show, :edit]
35
35
 
@@ -131,6 +131,10 @@ module Alchemy
131
131
  @notice = Alchemy.t("Page saved", name: @page.name)
132
132
  @while_page_edit = request.referer.include?("edit")
133
133
 
134
+ if @view == "list"
135
+ flash[:notice] = @notice
136
+ end
137
+
134
138
  unless @while_page_edit
135
139
  @tree = serialized_page_tree
136
140
  end
@@ -16,7 +16,10 @@ module Alchemy
16
16
  # * html
17
17
  # * js (Tries to replace a given +container_id+ with the elements view partial content via jQuery.)
18
18
  #
19
+ # @deprecated This controller action will be removed in Alchemy 8.0.
19
20
  def show
21
+ Alchemy::Deprecation.warn "The elements#show controller action is deprecated and will be removed in Alchemy 8.0."
22
+
20
23
  @page = @element.page
21
24
  @options = params[:options]
22
25
 
@@ -16,7 +16,7 @@ module Alchemy
16
16
  def alchemy_form_for(object, *args, &block)
17
17
  options = args.extract_options!
18
18
  options[:builder] = Alchemy::Forms::Builder
19
- options[:remote] = request.xhr?
19
+ options.key?(:remote) || options[:remote] = request.xhr?
20
20
  options[:html] = {
21
21
  id: options.delete(:id),
22
22
  class: ["alchemy", options.delete(:class)].compact.join(" ")
@@ -11,6 +11,7 @@ module Alchemy
11
11
  # The Hash representing a Alchemy module
12
12
  #
13
13
  def alchemy_main_navigation_entry(alchemy_module)
14
+ validate_controller_existence!(alchemy_module)
14
15
  render(
15
16
  "alchemy/admin/partials/main_navigation_entry",
16
17
  alchemy_module: alchemy_module,
@@ -126,7 +127,7 @@ module Alchemy
126
127
  #
127
128
  def route_from_engine_or_main_app(engine_name, url_options)
128
129
  if engine_name.present?
129
- eval(engine_name).url_for(url_options) # rubocop:disable Security/Eval
130
+ send(engine_name).url_for(url_options)
130
131
  else
131
132
  main_app.url_for(url_options)
132
133
  end
@@ -141,6 +142,26 @@ module Alchemy
141
142
  url_options_for_navigation_entry(alchemy_module["navigation"] || {})
142
143
  end
143
144
 
145
+ # Validates the existence of a given controller configuration.
146
+ #
147
+ # @param String
148
+ # The controller name
149
+ def validate_controller_existence!(definition_hash)
150
+ controllers = [definition_hash["navigation"]["controller"]]
151
+
152
+ if definition_hash["navigation"]["sub_navigation"].is_a?(Array)
153
+ controllers.concat(definition_hash["navigation"]["sub_navigation"].map { |x| x["controller"] })
154
+ end
155
+
156
+ controllers.each do |controller|
157
+ controller_const_name = "#{controller.camelize}Controller"
158
+ controller_const_name.constantize
159
+ rescue NameError
160
+ raise "Error in AlchemyCMS module definition: '#{definition_hash["name"]}'. Could not find the " \
161
+ "matching controller class #{controller_const_name} for the specified controller: '#{controller}'"
162
+ end
163
+ end
164
+
144
165
  # Returns a url options hash for given navigation entry.
145
166
  #
146
167
  # @param [Hash]
@@ -1,4 +1,5 @@
1
1
  import { reloadPreview } from "alchemy_admin/components/preview_window"
2
+ import { closeCurrentDialog } from "alchemy_admin/dialog"
2
3
  import IngredientAnchorLink from "alchemy_admin/ingredient_anchor_link"
3
4
 
4
5
  class Action extends HTMLElement {
@@ -10,7 +11,7 @@ class Action extends HTMLElement {
10
11
  // add a intermediate closeCurrentDialog - action
11
12
  // this will be gone, if all dialogs are working with a promise and
12
13
  // we don't have to implicitly close the dialog
13
- closeCurrentDialog: Alchemy.closeCurrentDialog,
14
+ closeCurrentDialog,
14
15
  reloadPreview,
15
16
  updateAnchorIcon: IngredientAnchorLink.updateIcon
16
17
  }
@@ -1,13 +1,4 @@
1
- export const DEFAULTS = {
2
- header_height: 36,
3
- size: "400x300",
4
- padding: true,
5
- title: "",
6
- modal: true,
7
- overflow: "visible",
8
- ready: () => {},
9
- closed: () => {}
10
- }
1
+ import { Dialog } from "alchemy_admin/dialog"
11
2
 
12
3
  export class DialogLink extends HTMLAnchorElement {
13
4
  constructor() {
@@ -23,10 +14,7 @@ export class DialogLink extends HTMLAnchorElement {
23
14
  }
24
15
 
25
16
  openDialog() {
26
- this.dialog = new Alchemy.Dialog(
27
- this.getAttribute("href"),
28
- this.dialogOptions
29
- )
17
+ this.dialog = new Dialog(this.getAttribute("href"), this.dialogOptions)
30
18
  this.dialog.open()
31
19
  }
32
20
 
@@ -34,10 +22,7 @@ export class DialogLink extends HTMLAnchorElement {
34
22
  const options = this.dataset.dialogOptions
35
23
  ? JSON.parse(this.dataset.dialogOptions)
36
24
  : {}
37
- return {
38
- ...DEFAULTS,
39
- ...options
40
- }
25
+ return options
41
26
  }
42
27
 
43
28
  get disabled() {
@@ -40,6 +40,15 @@ export class ElementEditor extends HTMLElement {
40
40
  return
41
41
  }
42
42
 
43
+ // When newly created, focus the element and refresh the preview
44
+ if (this.hasAttribute("created")) {
45
+ this.focusElement()
46
+ this.previewWindow?.refresh().then(() => {
47
+ this.focusElementPreview()
48
+ })
49
+ this.removeAttribute("created")
50
+ }
51
+
43
52
  // Init GUI elements
44
53
  ImageLoader.init(this)
45
54
  fileEditors(
@@ -2,6 +2,7 @@ import SortableElements from "alchemy_admin/sortable_elements"
2
2
 
3
3
  class ElementsWindow extends HTMLElement {
4
4
  #visible = true
5
+ #turboFrame = null
5
6
 
6
7
  constructor() {
7
8
  super()
@@ -19,6 +20,7 @@ class ElementsWindow extends HTMLElement {
19
20
  ?.trigger("FocusElementEditor.Alchemy")
20
21
  }
21
22
  SortableElements()
23
+ this.resize()
22
24
  }
23
25
 
24
26
  collapseAllElements() {
@@ -38,10 +40,12 @@ class ElementsWindow extends HTMLElement {
38
40
  this.toggleButton
39
41
  .querySelector("alchemy-icon")
40
42
  .setAttribute("name", "menu-unfold")
43
+ this.resize()
41
44
  }
42
45
 
43
46
  hide() {
44
47
  document.body.classList.remove("elements-window-visible")
48
+ document.body.style.removeProperty("--elements-window-width")
45
49
  this.#visible = false
46
50
  this.toggleButton.closest("sl-tooltip").content = Alchemy.t("Show elements")
47
51
  this.toggleButton
@@ -49,6 +53,17 @@ class ElementsWindow extends HTMLElement {
49
53
  .setAttribute("name", "menu-fold")
50
54
  }
51
55
 
56
+ resize(width) {
57
+ if (width === undefined) {
58
+ width = this.widthFromCookie
59
+ }
60
+
61
+ if (width) {
62
+ document.body.style.setProperty("--elements-window-width", `${width}px`)
63
+ document.cookie = `alchemy-elements-window-width=${width}; SameSite=Lax; Path=/;`
64
+ }
65
+ }
66
+
52
67
  get collapseButton() {
53
68
  return this.querySelector("#collapse-all-elements-button")
54
69
  }
@@ -61,6 +76,25 @@ class ElementsWindow extends HTMLElement {
61
76
  return document.getElementById("alchemy_preview_window")
62
77
  }
63
78
 
79
+ get turboFrame() {
80
+ if (!this.#turboFrame) {
81
+ this.#turboFrame = this.closest("turbo-frame")
82
+ }
83
+ return this.#turboFrame
84
+ }
85
+
86
+ get widthFromCookie() {
87
+ return document.cookie
88
+ .split("; ")
89
+ .find((row) => row.startsWith("alchemy-elements-window-width="))
90
+ ?.split("=")[1]
91
+ }
92
+
93
+ set isDragged(dragged) {
94
+ this.turboFrame.style.transitionProperty = dragged ? "none" : null
95
+ this.turboFrame.style.pointerEvents = dragged ? "none" : null
96
+ }
97
+
64
98
  #attachEvents() {
65
99
  this.collapseButton?.addEventListener("click", () => {
66
100
  this.collapseAllElements()