alchemy_cms 7.3.5 → 7.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +56 -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 +57 -40
  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 +19 -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 +39 -91
  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()