alchemy_cms 7.0.11 → 7.1.0.pre.b1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (330) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/backport.yml +36 -0
  3. data/.github/workflows/test.yml +3 -2
  4. data/.gitignore +1 -0
  5. data/.standard.yml +1 -1
  6. data/CHANGELOG.md +144 -15
  7. data/Gemfile +8 -10
  8. data/README.md +10 -8
  9. data/alchemy_cms.gemspec +4 -3
  10. data/app/assets/config/alchemy_manifest.js +0 -1
  11. data/app/assets/javascripts/alchemy/admin.js +1 -19
  12. data/app/assets/javascripts/alchemy/alchemy.confirm_dialog.js.coffee +2 -3
  13. data/app/assets/javascripts/alchemy/alchemy.dialog.js.coffee +19 -34
  14. data/app/assets/javascripts/alchemy/alchemy.elements_window.js.coffee +38 -13
  15. data/app/assets/javascripts/alchemy/alchemy.file_progress.js.coffee +1 -1
  16. data/app/assets/javascripts/alchemy/alchemy.fixed_elements.js +32 -25
  17. data/app/assets/javascripts/alchemy/alchemy.growler.js.coffee +1 -1
  18. data/app/assets/javascripts/alchemy/alchemy.image_overlay.coffee +3 -5
  19. data/app/assets/javascripts/alchemy/alchemy.initializer.js.coffee +0 -57
  20. data/app/assets/javascripts/alchemy/alchemy.link_dialog.js.coffee +22 -63
  21. data/app/assets/javascripts/alchemy/alchemy.list_filter.js.coffee +2 -2
  22. data/app/assets/javascripts/alchemy/alchemy.preview.js.coffee +5 -4
  23. data/app/assets/javascripts/alchemy/alchemy.preview_window.js.coffee +5 -5
  24. data/app/assets/javascripts/alchemy/templates/index.js +0 -2
  25. data/app/assets/javascripts/alchemy/templates/node_folder.hbs +1 -1
  26. data/app/assets/javascripts/alchemy/templates/page.hbs +1 -1
  27. data/app/assets/javascripts/alchemy/templates/page_folder.hbs +2 -2
  28. data/app/assets/stylesheets/alchemy/_custom-properties.scss +82 -0
  29. data/app/assets/stylesheets/alchemy/_mixins.scss +38 -30
  30. data/app/assets/stylesheets/alchemy/_variables.scss +12 -5
  31. data/app/assets/stylesheets/alchemy/admin.scss +3 -4
  32. data/app/assets/stylesheets/alchemy/archive.scss +107 -50
  33. data/app/assets/stylesheets/alchemy/attachments.scss +5 -4
  34. data/app/assets/stylesheets/alchemy/buttons.scss +38 -164
  35. data/app/assets/stylesheets/alchemy/dashboard.scss +31 -6
  36. data/app/assets/stylesheets/alchemy/dialogs.scss +12 -28
  37. data/app/assets/stylesheets/alchemy/elements.scss +273 -282
  38. data/app/assets/stylesheets/alchemy/flash.scss +20 -12
  39. data/app/assets/stylesheets/alchemy/forms.scss +21 -34
  40. data/app/assets/stylesheets/alchemy/frame.scss +11 -32
  41. data/app/assets/stylesheets/alchemy/hints.scss +4 -62
  42. data/app/assets/stylesheets/alchemy/image_library.scss +36 -33
  43. data/app/assets/stylesheets/alchemy/labels.scss +4 -1
  44. data/app/assets/stylesheets/alchemy/menubar.scss +7 -6
  45. data/app/assets/stylesheets/alchemy/navigation.scss +27 -15
  46. data/app/assets/stylesheets/alchemy/nodes.scss +11 -7
  47. data/app/assets/stylesheets/alchemy/notices.scss +16 -4
  48. data/app/assets/stylesheets/alchemy/page-select.scss +10 -2
  49. data/app/assets/stylesheets/alchemy/pagination.scss +22 -13
  50. data/app/assets/stylesheets/alchemy/resource_info.scss +7 -5
  51. data/app/assets/stylesheets/alchemy/selects.scss +49 -42
  52. data/app/assets/stylesheets/alchemy/shoelace.scss +345 -0
  53. data/app/assets/stylesheets/alchemy/sitemap.scss +24 -14
  54. data/app/assets/stylesheets/alchemy/spinner.scss +9 -19
  55. data/app/assets/stylesheets/alchemy/tables.scss +16 -24
  56. data/app/assets/stylesheets/alchemy/tags.scss +4 -0
  57. data/app/assets/stylesheets/alchemy/toolbar.scss +29 -25
  58. data/app/assets/stylesheets/alchemy/upload.scss +140 -89
  59. data/app/assets/stylesheets/tinymce/skins/alchemy/skin.min.css.scss +80 -108
  60. data/app/components/alchemy/admin/node_select.rb +39 -0
  61. data/app/components/alchemy/admin/page_select.rb +42 -0
  62. data/app/controllers/alchemy/admin/base_controller.rb +5 -6
  63. data/app/controllers/alchemy/admin/elements_controller.rb +63 -35
  64. data/app/controllers/alchemy/admin/languages_controller.rb +1 -2
  65. data/app/controllers/alchemy/base_controller.rb +4 -2
  66. data/app/controllers/concerns/alchemy/admin/current_language.rb +1 -5
  67. data/app/controllers/concerns/alchemy/admin/uploader_responses.rb +1 -1
  68. data/app/controllers/concerns/alchemy/site_redirects.rb +1 -1
  69. data/app/decorators/alchemy/element_editor.rb +0 -2
  70. data/app/helpers/alchemy/admin/attachments_helper.rb +6 -5
  71. data/app/helpers/alchemy/admin/base_helper.rb +17 -12
  72. data/app/helpers/alchemy/admin/ingredients_helper.rb +4 -1
  73. data/app/helpers/alchemy/admin/pages_helper.rb +5 -11
  74. data/app/helpers/alchemy/base_helper.rb +47 -13
  75. data/app/javascript/alchemy_admin/components/alchemy_html_element.js +129 -0
  76. data/app/javascript/alchemy_admin/components/button.js +59 -0
  77. data/app/javascript/alchemy_admin/components/char_counter.js +40 -0
  78. data/app/javascript/alchemy_admin/components/datepicker.js +39 -0
  79. data/app/javascript/alchemy_admin/components/dialog_link.js +45 -0
  80. data/app/javascript/alchemy_admin/components/element_editor/publish_element_button.js +36 -0
  81. data/app/javascript/alchemy_admin/components/element_editor.js +553 -0
  82. data/app/javascript/alchemy_admin/components/ingredient_group.js +54 -0
  83. data/app/javascript/alchemy_admin/components/link_buttons/link_button.js +48 -0
  84. data/app/javascript/alchemy_admin/components/link_buttons/unlink_button.js +38 -0
  85. data/app/javascript/alchemy_admin/components/link_buttons.js +79 -0
  86. data/app/javascript/alchemy_admin/components/node_select.js +45 -0
  87. data/app/javascript/alchemy_admin/components/overlay.js +18 -0
  88. data/app/javascript/alchemy_admin/components/page_select.js +63 -0
  89. data/app/javascript/alchemy_admin/components/remote_select.js +134 -0
  90. data/app/javascript/alchemy_admin/components/select.js +12 -0
  91. data/app/javascript/alchemy_admin/components/spinner.js +31 -0
  92. data/app/javascript/alchemy_admin/components/tinymce.js +146 -0
  93. data/app/javascript/alchemy_admin/components/uploader/file_upload.js +266 -0
  94. data/app/javascript/alchemy_admin/components/uploader/progress.js +258 -0
  95. data/app/javascript/alchemy_admin/components/uploader.js +132 -0
  96. data/app/javascript/alchemy_admin/dirty.js +49 -0
  97. data/app/javascript/alchemy_admin/file_editors.js +1 -1
  98. data/app/javascript/alchemy_admin/gui.js +14 -0
  99. data/app/javascript/alchemy_admin/i18n.js +12 -8
  100. data/app/javascript/alchemy_admin/image_cropper.js +6 -3
  101. data/app/javascript/alchemy_admin/image_loader.js +7 -15
  102. data/app/javascript/alchemy_admin/ingredient_anchor_link.js +2 -5
  103. data/app/javascript/alchemy_admin/initializer.js +65 -0
  104. data/app/javascript/alchemy_admin/locales/en.js +31 -0
  105. data/app/javascript/alchemy_admin/picture_editors.js +2 -2
  106. data/app/javascript/alchemy_admin/picture_selector.js +38 -0
  107. data/app/javascript/alchemy_admin/please_wait_overlay.js +8 -0
  108. data/app/javascript/alchemy_admin/sortable_elements.js +78 -0
  109. data/app/javascript/alchemy_admin/spinner.js +36 -0
  110. data/app/javascript/alchemy_admin/tags_autocomplete.js +46 -0
  111. data/app/javascript/alchemy_admin/utils/ajax.js +6 -5
  112. data/app/javascript/alchemy_admin/utils/dom_helpers.js +20 -0
  113. data/app/javascript/alchemy_admin/utils/format.js +11 -0
  114. data/app/javascript/alchemy_admin/utils/string_conversions.js +10 -0
  115. data/app/javascript/alchemy_admin.js +70 -13
  116. data/app/javascript/menubar.js +10 -0
  117. data/app/models/alchemy/attachment.rb +9 -11
  118. data/app/models/alchemy/element.rb +11 -0
  119. data/app/models/alchemy/ingredients/richtext.rb +1 -10
  120. data/app/models/alchemy/node.rb +4 -0
  121. data/app/models/alchemy/page/page_elements.rb +2 -11
  122. data/app/models/alchemy/page/page_natures.rb +10 -2
  123. data/app/models/alchemy/page.rb +9 -49
  124. data/app/models/alchemy/picture/url.rb +1 -9
  125. data/app/serializers/alchemy/page_tree_serializer.rb +2 -1
  126. data/app/services/alchemy/copy_page.rb +98 -0
  127. data/app/views/alchemy/_menubar.html.erb +17 -13
  128. data/app/views/alchemy/admin/attachments/_archive_overlay.html.erb +14 -10
  129. data/app/views/alchemy/admin/attachments/_attachment.html.erb +44 -36
  130. data/app/views/alchemy/admin/attachments/_replace_button.html.erb +15 -21
  131. data/app/views/alchemy/admin/attachments/archive_overlay.js.erb +0 -1
  132. data/app/views/alchemy/admin/attachments/assign.js.erb +1 -1
  133. data/app/views/alchemy/admin/attachments/index.html.erb +6 -4
  134. data/app/views/alchemy/admin/attachments/show.html.erb +8 -8
  135. data/app/views/alchemy/admin/clipboard/clear.js.erb +1 -1
  136. data/app/views/alchemy/admin/clipboard/index.html.erb +3 -7
  137. data/app/views/alchemy/admin/clipboard/insert.js.erb +1 -1
  138. data/app/views/alchemy/admin/crop.html.erb +1 -1
  139. data/app/views/alchemy/admin/dashboard/_locked_pages.html.erb +1 -1
  140. data/app/views/alchemy/admin/dashboard/index.html.erb +13 -11
  141. data/app/views/alchemy/admin/dashboard/info.html.erb +7 -7
  142. data/app/views/alchemy/admin/elements/_add_nested_element_form.html.erb +21 -23
  143. data/app/views/alchemy/admin/elements/_element.html.erb +52 -44
  144. data/app/views/alchemy/admin/elements/_footer.html.erb +1 -1
  145. data/app/views/alchemy/admin/elements/_form.html.erb +1 -1
  146. data/app/views/alchemy/admin/elements/_header.html.erb +11 -12
  147. data/app/views/alchemy/admin/elements/_toolbar.html.erb +33 -45
  148. data/app/views/alchemy/admin/elements/create.js.erb +7 -15
  149. data/app/views/alchemy/admin/elements/destroy.js.erb +0 -2
  150. data/app/views/alchemy/admin/elements/index.html.erb +27 -24
  151. data/app/views/alchemy/admin/elements/new.html.erb +9 -11
  152. data/app/views/alchemy/admin/ingredients/_file_fields.html.erb +2 -2
  153. data/app/views/alchemy/admin/ingredients/_picture_fields.html.erb +3 -3
  154. data/app/views/alchemy/admin/ingredients/_video_fields.html.erb +1 -2
  155. data/app/views/alchemy/admin/languages/_form.html.erb +2 -3
  156. data/app/views/alchemy/admin/languages/_language.html.erb +15 -8
  157. data/app/views/alchemy/admin/languages/_table.html.erb +1 -0
  158. data/app/views/alchemy/admin/layoutpages/_layoutpage.html.erb +28 -16
  159. data/app/views/alchemy/admin/layoutpages/index.html.erb +2 -2
  160. data/app/views/alchemy/admin/legacy_page_urls/_legacy_page_url.html.erb +12 -8
  161. data/app/views/alchemy/admin/legacy_page_urls/_new.html.erb +1 -1
  162. data/app/views/alchemy/admin/nodes/_form.html.erb +20 -21
  163. data/app/views/alchemy/admin/nodes/_node.html.erb +39 -34
  164. data/app/views/alchemy/admin/nodes/index.html.erb +1 -1
  165. data/app/views/alchemy/admin/pages/_anchor_link.html.erb +4 -4
  166. data/app/views/alchemy/admin/pages/_create_language_form.html.erb +2 -2
  167. data/app/views/alchemy/admin/pages/_current_page.html.erb +1 -1
  168. data/app/views/alchemy/admin/pages/_external_link.html.erb +4 -4
  169. data/app/views/alchemy/admin/pages/_file_link.html.erb +5 -5
  170. data/app/views/alchemy/admin/pages/_form.html.erb +10 -21
  171. data/app/views/alchemy/admin/pages/_internal_link.html.erb +4 -4
  172. data/app/views/alchemy/admin/pages/_locked_page.html.erb +2 -2
  173. data/app/views/alchemy/admin/pages/_new_page_form.html.erb +4 -17
  174. data/app/views/alchemy/admin/pages/_page.html.erb +76 -72
  175. data/app/views/alchemy/admin/pages/_page_infos.html.erb +23 -7
  176. data/app/views/alchemy/admin/pages/_page_layout_filter.html.erb +2 -1
  177. data/app/views/alchemy/admin/pages/_page_status.html.erb +11 -21
  178. data/app/views/alchemy/admin/pages/_publication_fields.html.erb +2 -5
  179. data/app/views/alchemy/admin/pages/_table.html.erb +1 -1
  180. data/app/views/alchemy/admin/pages/_table_row.html.erb +43 -39
  181. data/app/views/alchemy/admin/pages/_toolbar.html.erb +43 -38
  182. data/app/views/alchemy/admin/pages/configure.html.erb +12 -14
  183. data/app/views/alchemy/admin/pages/edit.html.erb +80 -103
  184. data/app/views/alchemy/admin/pages/info.html.erb +20 -11
  185. data/app/views/alchemy/admin/pages/link.html.erb +22 -16
  186. data/app/views/alchemy/admin/pages/new.html.erb +9 -11
  187. data/app/views/alchemy/admin/pages/unlock.js.erb +10 -3
  188. data/app/views/alchemy/admin/partials/_language_tree_select.html.erb +15 -13
  189. data/app/views/alchemy/admin/partials/_main_navigation_entry.html.erb +3 -5
  190. data/app/views/alchemy/admin/partials/_routes.html.erb +10 -2
  191. data/app/views/alchemy/admin/partials/_site_select.html.erb +6 -5
  192. data/app/views/alchemy/admin/partials/_toolbar_button.html.erb +28 -23
  193. data/app/views/alchemy/admin/pictures/_archive.html.erb +5 -5
  194. data/app/views/alchemy/admin/pictures/_archive_overlay.html.erb +1 -1
  195. data/app/views/alchemy/admin/pictures/_filter_and_size_bar.html.erb +21 -23
  196. data/app/views/alchemy/admin/pictures/_infos.html.erb +2 -6
  197. data/app/views/alchemy/admin/pictures/_picture.html.erb +15 -17
  198. data/app/views/alchemy/admin/pictures/_picture_to_assign.html.erb +17 -16
  199. data/app/views/alchemy/admin/pictures/_tag_list.html.erb +1 -1
  200. data/app/views/alchemy/admin/pictures/archive_overlay.js.erb +1 -1
  201. data/app/views/alchemy/admin/pictures/assign.js.erb +1 -1
  202. data/app/views/alchemy/admin/pictures/index.html.erb +34 -30
  203. data/app/views/alchemy/admin/pictures/show.html.erb +3 -3
  204. data/app/views/alchemy/admin/resources/_filter.html.erb +2 -2
  205. data/app/views/alchemy/admin/resources/_form.html.erb +2 -2
  206. data/app/views/alchemy/admin/resources/_per_page_select.html.erb +1 -1
  207. data/app/views/alchemy/admin/resources/_resource.html.erb +16 -9
  208. data/app/views/alchemy/admin/resources/_table.html.erb +4 -1
  209. data/app/views/alchemy/admin/resources/index.html.erb +22 -19
  210. data/app/views/alchemy/admin/sites/index.html.erb +2 -1
  211. data/app/views/alchemy/admin/styleguide/index.html.erb +54 -28
  212. data/app/views/alchemy/admin/tags/_tag.html.erb +16 -18
  213. data/app/views/alchemy/admin/tags/index.html.erb +15 -12
  214. data/app/views/alchemy/admin/tinymce/_setup.html.erb +29 -0
  215. data/app/views/alchemy/admin/uploader/_button.html.erb +23 -29
  216. data/app/views/alchemy/admin/uploader/_setup.html.erb +3 -8
  217. data/app/views/alchemy/base/500.html.erb +1 -1
  218. data/app/views/alchemy/base/error_notice.js.erb +0 -1
  219. data/app/views/alchemy/ingredients/_boolean_editor.html.erb +1 -1
  220. data/app/views/alchemy/ingredients/_datetime_editor.html.erb +1 -1
  221. data/app/views/alchemy/ingredients/_file_editor.html.erb +5 -5
  222. data/app/views/alchemy/ingredients/_link_editor.html.erb +1 -1
  223. data/app/views/alchemy/ingredients/_node_editor.html.erb +6 -19
  224. data/app/views/alchemy/ingredients/_page_editor.html.erb +7 -19
  225. data/app/views/alchemy/ingredients/_picture_editor.html.erb +2 -2
  226. data/app/views/alchemy/ingredients/_richtext_editor.html.erb +6 -15
  227. data/app/views/alchemy/ingredients/_select_editor.html.erb +2 -1
  228. data/app/views/alchemy/ingredients/_text_editor.html.erb +1 -1
  229. data/app/views/alchemy/ingredients/shared/_anchor.html.erb +1 -1
  230. data/app/views/alchemy/ingredients/shared/_link_tools.html.erb +10 -20
  231. data/app/views/alchemy/ingredients/shared/_picture_tools.html.erb +42 -49
  232. data/app/views/kaminari/alchemy/_first_page.html.erb +4 -2
  233. data/app/views/kaminari/alchemy/_gap.html.erb +1 -1
  234. data/app/views/kaminari/alchemy/_last_page.html.erb +4 -2
  235. data/app/views/kaminari/alchemy/_next_page.html.erb +4 -2
  236. data/app/views/kaminari/alchemy/_prev_page.html.erb +4 -2
  237. data/app/views/layouts/alchemy/admin.html.erb +10 -29
  238. data/config/alchemy/modules.yml +30 -30
  239. data/config/importmap.rb +10 -1
  240. data/config/initializers/rails_live_reload.rb +13 -0
  241. data/config/locales/alchemy.en.yml +23 -9
  242. data/config/routes.rb +2 -1
  243. data/lib/alchemy/auth_accessors.rb +6 -1
  244. data/lib/alchemy/controller_actions.rb +17 -4
  245. data/lib/alchemy/dev_support/live_reload_watcher.rb +5 -0
  246. data/lib/alchemy/engine.rb +8 -2
  247. data/lib/alchemy/forms/builder.rb +18 -12
  248. data/lib/alchemy/resources_helper.rb +3 -3
  249. data/lib/alchemy/test_support/capybara_helpers.rb +8 -5
  250. data/lib/alchemy/test_support/rspec_matchers.rb +14 -0
  251. data/lib/alchemy/test_support/shared_uploader_examples.rb +1 -1
  252. data/lib/alchemy/tinymce.rb +8 -3
  253. data/lib/alchemy/version.rb +1 -1
  254. data/package.json +14 -5
  255. data/vendor/assets/fonts/remixicon.eot +0 -0
  256. data/vendor/assets/fonts/remixicon.svg +7816 -0
  257. data/vendor/assets/fonts/remixicon.ttf +0 -0
  258. data/vendor/assets/fonts/remixicon.woff +0 -0
  259. data/vendor/assets/fonts/remixicon.woff2 +0 -0
  260. data/vendor/assets/stylesheets/remixicon.scss +10480 -0
  261. metadata +85 -96
  262. data/app/assets/javascripts/alchemy/alchemy.autocomplete.js.coffee +0 -30
  263. data/app/assets/javascripts/alchemy/alchemy.base.js.coffee +0 -53
  264. data/app/assets/javascripts/alchemy/alchemy.buttons.js.coffee +0 -45
  265. data/app/assets/javascripts/alchemy/alchemy.char_counter.js.coffee +0 -19
  266. data/app/assets/javascripts/alchemy/alchemy.dirty.js.coffee +0 -59
  267. data/app/assets/javascripts/alchemy/alchemy.dragndrop.js.coffee +0 -79
  268. data/app/assets/javascripts/alchemy/alchemy.element_editors.js.coffee +0 -267
  269. data/app/assets/javascripts/alchemy/alchemy.gui.js.coffee +0 -27
  270. data/app/assets/javascripts/alchemy/alchemy.spinner.js +0 -32
  271. data/app/assets/javascripts/alchemy/alchemy.tooltips.coffee +0 -10
  272. data/app/assets/javascripts/alchemy/alchemy.uploader.js.coffee +0 -131
  273. data/app/assets/javascripts/alchemy/menubar.js.coffee +0 -8
  274. data/app/assets/javascripts/alchemy/node_select.js +0 -39
  275. data/app/assets/javascripts/alchemy/page_select.js +0 -46
  276. data/app/assets/javascripts/alchemy/templates/node.hbs +0 -16
  277. data/app/assets/javascripts/alchemy/templates/spinner.hbs +0 -7
  278. data/app/assets/stylesheets/alchemy/jquery-ui.scss +0 -435
  279. data/app/javascript/alchemy_admin/datepicker.js +0 -40
  280. data/app/javascript/alchemy_admin/tinymce.js +0 -146
  281. data/app/javascript/alchemy_admin/translations.js +0 -32
  282. data/app/views/alchemy/admin/elements/fold.js.erb +0 -33
  283. data/app/views/alchemy/admin/elements/order.js.erb +0 -11
  284. data/app/views/alchemy/admin/elements/publish.js.erb +0 -21
  285. data/app/views/alchemy/admin/elements/update.js.erb +0 -27
  286. data/vendor/assets/fonts/fa-regular-400.eot +0 -0
  287. data/vendor/assets/fonts/fa-regular-400.svg +0 -803
  288. data/vendor/assets/fonts/fa-regular-400.ttf +0 -0
  289. data/vendor/assets/fonts/fa-regular-400.woff +0 -0
  290. data/vendor/assets/fonts/fa-regular-400.woff2 +0 -0
  291. data/vendor/assets/fonts/fa-solid-900.eot +0 -0
  292. data/vendor/assets/fonts/fa-solid-900.svg +0 -4938
  293. data/vendor/assets/fonts/fa-solid-900.ttf +0 -0
  294. data/vendor/assets/fonts/fa-solid-900.woff +0 -0
  295. data/vendor/assets/fonts/fa-solid-900.woff2 +0 -0
  296. data/vendor/assets/javascripts/fileupload/jquery.fileupload-process.js +0 -178
  297. data/vendor/assets/javascripts/fileupload/jquery.fileupload-validate.js +0 -125
  298. data/vendor/assets/javascripts/fileupload/jquery.fileupload.js +0 -1502
  299. data/vendor/assets/javascripts/fileupload/jquery.iframe-transport.js +0 -224
  300. data/vendor/assets/javascripts/jquery-ui/data.js +0 -45
  301. data/vendor/assets/javascripts/jquery-ui/ie.js +0 -20
  302. data/vendor/assets/javascripts/jquery-ui/keycode.js +0 -51
  303. data/vendor/assets/javascripts/jquery-ui/plugin.js +0 -49
  304. data/vendor/assets/javascripts/jquery-ui/safe-active-element.js +0 -46
  305. data/vendor/assets/javascripts/jquery-ui/safe-blur.js +0 -27
  306. data/vendor/assets/javascripts/jquery-ui/scroll-parent.js +0 -50
  307. data/vendor/assets/javascripts/jquery-ui/unique-id.js +0 -54
  308. data/vendor/assets/javascripts/jquery-ui/version.js +0 -20
  309. data/vendor/assets/javascripts/jquery-ui/widget.js +0 -754
  310. data/vendor/assets/javascripts/jquery-ui/widgets/draggable.js +0 -1268
  311. data/vendor/assets/javascripts/jquery-ui/widgets/mouse.js +0 -241
  312. data/vendor/assets/javascripts/jquery-ui/widgets/sortable.js +0 -1623
  313. data/vendor/assets/javascripts/jquery-ui/widgets/tabs.js +0 -931
  314. data/vendor/assets/javascripts/jquery_plugins/jquery.scrollTo.min.js +0 -7
  315. data/vendor/assets/javascripts/jquery_plugins/jquery.ui.tabspaging.js +0 -296
  316. data/vendor/assets/stylesheets/fontawesome/_animated.scss +0 -20
  317. data/vendor/assets/stylesheets/fontawesome/_bordered-pulled.scss +0 -20
  318. data/vendor/assets/stylesheets/fontawesome/_core.scss +0 -21
  319. data/vendor/assets/stylesheets/fontawesome/_fixed-width.scss +0 -6
  320. data/vendor/assets/stylesheets/fontawesome/_icons.scss +0 -1441
  321. data/vendor/assets/stylesheets/fontawesome/_larger.scss +0 -23
  322. data/vendor/assets/stylesheets/fontawesome/_list.scss +0 -18
  323. data/vendor/assets/stylesheets/fontawesome/_mixins.scss +0 -56
  324. data/vendor/assets/stylesheets/fontawesome/_rotated-flipped.scss +0 -24
  325. data/vendor/assets/stylesheets/fontawesome/_screen-reader.scss +0 -5
  326. data/vendor/assets/stylesheets/fontawesome/_stacked.scss +0 -31
  327. data/vendor/assets/stylesheets/fontawesome/_variables.scss +0 -1458
  328. data/vendor/assets/stylesheets/fontawesome/fontawesome.scss +0 -16
  329. data/vendor/assets/stylesheets/fontawesome/regular.scss +0 -23
  330. data/vendor/assets/stylesheets/fontawesome/solid.scss +0 -24
@@ -0,0 +1,14 @@
1
+ import TagsAutocomplete from "alchemy_admin/tags_autocomplete"
2
+
3
+ function init(scope) {
4
+ if (!scope) {
5
+ Alchemy.watchForDialogs()
6
+ }
7
+ Alchemy.Hotkeys(scope)
8
+ Alchemy.ListFilter(scope)
9
+ TagsAutocomplete(scope)
10
+ }
11
+
12
+ export default {
13
+ init
14
+ }
@@ -1,11 +1,8 @@
1
- const KEY_SEPARATOR = /\./
1
+ import { en } from "alchemy_admin/locales/en"
2
2
 
3
- function currentLocale() {
4
- if (Alchemy.locale == null) {
5
- throw "Alchemy.locale is not set! Please set Alchemy.locale to a locale string in order to translate something."
6
- }
7
- return Alchemy.locale
8
- }
3
+ Alchemy.translations = Object.assign(Alchemy.translations || {}, { en })
4
+
5
+ const KEY_SEPARATOR = /\./
9
6
 
10
7
  function getTranslations() {
11
8
  const locale = currentLocale()
@@ -36,7 +33,14 @@ function getTranslation(key) {
36
33
  return translations[key] || key
37
34
  }
38
35
 
39
- export default function translate(key, replacement) {
36
+ export function currentLocale() {
37
+ if (document.documentElement.lang) {
38
+ return document.documentElement.lang
39
+ }
40
+ return "en"
41
+ }
42
+
43
+ export function translate(key, replacement = undefined) {
40
44
  let translation = getTranslation(key)
41
45
 
42
46
  if (replacement) {
@@ -90,12 +90,15 @@ export default class ImageCropper {
90
90
  }
91
91
 
92
92
  bind() {
93
- this.dialog.dialog_body.find('button[type="submit"]').click(() => {
94
- Alchemy.setElementDirty(`[data-element-id='${this.elementId}']`)
93
+ this.dialog.dialog_body.find('button[type="submit"]').on("click", () => {
94
+ const elementEditor = document.querySelector(
95
+ `[data-element-id='${this.elementId}']`
96
+ )
97
+ elementEditor.setDirty()
95
98
  this.dialog.close()
96
99
  return false
97
100
  })
98
- this.dialog.dialog_body.find('button[type="reset"]').click(() => {
101
+ this.dialog.dialog_body.find('button[type="reset"]').on("click", () => {
99
102
  this.reset()
100
103
  return false
101
104
  })
@@ -1,23 +1,21 @@
1
1
  // Shows spinner while loading images and
2
2
  // fades the image after its been loaded
3
3
 
4
- const DEFAULT_SPINNER_OPTIONS = { fill: "#fff" }
5
-
6
4
  export default class ImageLoader {
7
- static init(scope = document, spinnerOptions = DEFAULT_SPINNER_OPTIONS) {
5
+ static init(scope = document) {
8
6
  if (typeof scope === "string") {
9
7
  scope = document.querySelector(scope)
10
8
  }
11
9
  scope.querySelectorAll("img").forEach((image) => {
12
- const loader = new ImageLoader(image, spinnerOptions)
10
+ const loader = new ImageLoader(image)
13
11
  loader.load()
14
12
  })
15
13
  }
16
14
 
17
- constructor(image, spinnerOptions = DEFAULT_SPINNER_OPTIONS) {
15
+ constructor(image) {
18
16
  this.image = image
19
17
  this.parent = image.parentNode
20
- this.spinner = new Alchemy.Spinner("small", spinnerOptions)
18
+ this.spinner = new Alchemy.Spinner("small")
21
19
  this.bind()
22
20
  }
23
21
 
@@ -34,15 +32,15 @@ export default class ImageLoader {
34
32
  }
35
33
 
36
34
  onLoaded() {
37
- this.removeSpinner()
35
+ this.spinner.stop()
38
36
  this.image.classList.remove("loading")
39
37
  this.unbind()
40
38
  }
41
39
 
42
40
  onError(evt) {
43
41
  const message = `Could not load "${this.image.src}"`
44
- this.removeSpinner()
45
- this.parent.innerHTML = `<span class="icon error fas fa-exclamation-triangle" title="${message}" />`
42
+ this.spinner.stop()
43
+ this.parent.innerHTML = `<span class="icon error ri-alert-line" title="${message}" />`
46
44
  console.error(message, evt)
47
45
  this.unbind()
48
46
  }
@@ -51,10 +49,4 @@ export default class ImageLoader {
51
49
  this.image.removeEventListener("load", this.onLoaded)
52
50
  this.image.removeEventListener("error", this.onError)
53
51
  }
54
-
55
- removeSpinner() {
56
- this.parent.querySelectorAll(".spinner").forEach((spinner) => {
57
- spinner.remove()
58
- })
59
- }
60
52
  }
@@ -7,11 +7,8 @@ export default class IngredientAnchorLink {
7
7
  const icon = ingredientEditor.querySelector(
8
8
  ".edit-ingredient-anchor-link > a > .icon"
9
9
  )
10
- if (icon) {
11
- active
12
- ? icon.classList.replace("far", "fas")
13
- : icon.classList.replace("fas", "far")
14
- }
10
+ icon?.classList.toggle("ri-bookmark-fill", active)
11
+ icon?.classList.toggle("ri-bookmark-line", !active)
15
12
  }
16
13
  }
17
14
  }
@@ -0,0 +1,65 @@
1
+ /**
2
+ * add change listener to select to redirect the user after selecting another locale or site
3
+ * @param {string} selectId
4
+ * @param {string} parameterName
5
+ * @param {boolean} forcedReload
6
+ */
7
+ function selectHandler(selectId, parameterName, forcedReload = false) {
8
+ $(`select#${selectId}`).on("change", function (e) {
9
+ let url = window.location.pathname
10
+ let delimiter = url.match(/\?/) ? "&" : "?"
11
+ const location = `${url}${delimiter}${parameterName}=${$(this).val()}`
12
+
13
+ if (forcedReload) {
14
+ window.location.href = location
15
+ } else {
16
+ Turbo.visit(location, {})
17
+ }
18
+ })
19
+ }
20
+
21
+ function Initialize() {
22
+ // We obviously have javascript enabled.
23
+ $("html").removeClass("no-js")
24
+
25
+ // Initialize the GUI.
26
+ Alchemy.GUI.init()
27
+
28
+ // Fade all growl notifications.
29
+ if ($("#flash_notices").length > 0) {
30
+ Alchemy.Growler.fade()
31
+ }
32
+
33
+ // Add observer for please wait overlay.
34
+ $(".please_wait")
35
+ .not("*[data-alchemy-confirm]")
36
+ .on("click", Alchemy.pleaseWaitOverlay)
37
+
38
+ // Hack for enabling tab focus for <a>'s styled as button.
39
+ $("a.button").attr({ tabindex: 0 })
40
+
41
+ // Locale select handler
42
+ selectHandler("change_locale", "admin_locale", true)
43
+
44
+ // Site select handler
45
+ selectHandler("change_site", "site_id")
46
+
47
+ // Submit forms of selects with `data-autosubmit="true"`
48
+ $('select[data-auto-submit="true"]').on("change", function () {
49
+ $(this.form).submit()
50
+ })
51
+
52
+ // Attaches the image loader on all images
53
+ Alchemy.ImageLoader("#main_content")
54
+
55
+ // Override the filter of keymaster.js so we can blur the fields on esc key.
56
+ key.filter = function (event) {
57
+ let tagName = (event.target || event.srcElement).tagName
58
+ return (
59
+ key.isPressed("esc") ||
60
+ !(tagName === "INPUT" || tagName === "SELECT" || tagName === "TEXTAREA")
61
+ )
62
+ }
63
+ }
64
+
65
+ export default Initialize
@@ -0,0 +1,31 @@
1
+ export const en = {
2
+ allowed_chars: "of %{count} chars",
3
+ cancel: "Cancel",
4
+ cancelled: "Cancelled",
5
+ click_to_edit: "click to edit",
6
+ complete: "Complete",
7
+ element_dirty_notice:
8
+ "This element has unsaved changes. Do you really want to fold it?",
9
+ help: "Help",
10
+ ok: "Ok",
11
+ page_dirty_notice:
12
+ "You have unsaved changes on this page. They will be lost if you continue.",
13
+ page_found: "Page found",
14
+ pages_found: "Pages found",
15
+ url_validation_failed: "The url has no valid format.",
16
+ warning: "Warning!",
17
+ "File is too large": "File is too large",
18
+ "File is too small": "File is too small",
19
+ "File type not allowed": "File type not allowed",
20
+ "Maximum number of files exceeded": "Maximum number of files exceeded",
21
+ "Uploaded bytes exceed file size": "Uploaded bytes exceed file size",
22
+ "Abort upload": "Abort upload",
23
+ "Cancel all uploads": "Cancel all uploads",
24
+ Close: "Close",
25
+ formats: {
26
+ datetime: "Y-m-d H:i",
27
+ date: "Y-m-d",
28
+ time: "H:i",
29
+ time_24hr: false
30
+ }
31
+ }
@@ -4,7 +4,7 @@ import { get } from "alchemy_admin/utils/ajax"
4
4
  import ImageLoader from "alchemy_admin/image_loader"
5
5
 
6
6
  const UPDATE_DELAY = 125
7
- const IMAGE_PLACEHOLDER = '<i class="icon far fa-image fa-fw"></i>'
7
+ const IMAGE_PLACEHOLDER = '<i class="icon ri-image-line ri-fw"></i>'
8
8
  const THUMBNAIL_SIZE = "160x120"
9
9
 
10
10
  class PictureEditor {
@@ -93,7 +93,7 @@ class PictureEditor {
93
93
  this.pictureIdField.value = ""
94
94
  this.image = null
95
95
  this.cropLink.classList.add("disabled")
96
- Alchemy.setElementDirty(this.container.closest(".element-editor"))
96
+ this.container.closest(".element-editor").setDirty()
97
97
  }
98
98
 
99
99
  updateCropLink() {
@@ -0,0 +1,38 @@
1
+ import { on } from "alchemy_admin/utils/events"
2
+
3
+ /**
4
+ * Multiple picture select handler for the picture archive.
5
+ */
6
+ export default function PictureSelector() {
7
+ const selectedItemTools = document.querySelector(".selected_item_tools")
8
+ const checkedInputs = () =>
9
+ document.querySelectorAll("#picture_archive input:checked")
10
+
11
+ // make the item toolbar visible and show the checkbox also if it is not hovered anymore
12
+ on("change", ".picture_tool.select", "input", (event) => {
13
+ selectedItemTools.style.display =
14
+ checkedInputs().length > 0 ? "block" : "none"
15
+
16
+ const parentElementClassList = event.target.parentElement.classList
17
+ const checked = event.target.checked
18
+
19
+ parentElementClassList.toggle("visible", checked)
20
+ parentElementClassList.toggle("hidden", !checked)
21
+ })
22
+
23
+ // open the edit view in a dialog modal
24
+ on("click", ".selected_item_tools", "a#edit_multiple_pictures", (event) => {
25
+ event.preventDefault()
26
+
27
+ const searchParameters = new URLSearchParams()
28
+ checkedInputs().forEach((entry) =>
29
+ searchParameters.append(entry.name, entry.value)
30
+ )
31
+ const url = event.target.href + "?" + searchParameters.toString()
32
+
33
+ Alchemy.openDialog(url, {
34
+ title: event.target.title,
35
+ size: "400x295"
36
+ })
37
+ })
38
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * To show the "Please wait" overlay.
3
+ * Pass false to hide it.
4
+ * @param {boolean} show
5
+ */
6
+ export default function pleaseWaitOverlay(show = true) {
7
+ document.querySelector("alchemy-overlay").show = !!show
8
+ }
@@ -0,0 +1,78 @@
1
+ import Sortable from "sortablejs"
2
+ import { post } from "alchemy_admin/utils/ajax"
3
+
4
+ const SORTABLE_OPTIONS = {
5
+ draggable: ".element-editor",
6
+ handle: ".element-handle",
7
+ ghostClass: "dragged",
8
+ animation: 150,
9
+ swapThreshold: 0.65,
10
+ easing: "cubic-bezier(1, 0, 0, 1)"
11
+ }
12
+
13
+ function onStart(event) {
14
+ const name = event.item.dataset.elementName
15
+ document
16
+ .querySelectorAll(`[data-droppable-elements~="${name}"]`)
17
+ .forEach((dropzone) => dropzone.classList.add("droppable-elements"))
18
+ }
19
+
20
+ function onSort(event) {
21
+ const item = event.item
22
+ const parentElement = event.to.parentElement.closest(".element-editor")
23
+ const params = {
24
+ element_id: item.dataset.elementId,
25
+ position: event.newIndex + 1
26
+ }
27
+
28
+ if (parentElement) {
29
+ params.parent_element_id = parentElement.dataset.elementId
30
+ }
31
+
32
+ post(Alchemy.routes.order_admin_elements_path, params).then((response) => {
33
+ const data = response.data
34
+ Alchemy.growl(data.message)
35
+ Alchemy.PreviewWindow.refresh()
36
+ item.updateTitle(data.preview_text)
37
+ })
38
+ }
39
+
40
+ function onEnd() {
41
+ const dropzones = document.querySelectorAll("[data-droppable-elements]")
42
+ dropzones.forEach((dropzone) =>
43
+ dropzone.classList.remove("droppable-elements")
44
+ )
45
+ }
46
+
47
+ function createSortable(element, options = {}) {
48
+ const group = {
49
+ name: element.dataset.elementName,
50
+ put(to, _from, item) {
51
+ return to.el.dataset.droppableElements
52
+ .split(" ")
53
+ .includes(item.dataset.elementName)
54
+ }
55
+ }
56
+ new Sortable(element, {
57
+ ...SORTABLE_OPTIONS,
58
+ ...options,
59
+ onStart,
60
+ onSort,
61
+ onEnd,
62
+ group
63
+ })
64
+ }
65
+
66
+ export default function SortableElements(selector) {
67
+ if (selector == null) selector = ".sortable-elements"
68
+
69
+ const sortable_areas = document.querySelectorAll(selector, {
70
+ direction: "vertical"
71
+ })
72
+
73
+ sortable_areas.forEach((element) => createSortable(element))
74
+
75
+ document.querySelectorAll(".nested-elements").forEach((nestedElement) => {
76
+ createSortable(nestedElement)
77
+ })
78
+ }
@@ -0,0 +1,36 @@
1
+ import { createHtmlElement } from "alchemy_admin/utils/dom_helpers"
2
+
3
+ export default class Spinner {
4
+ constructor(size, color = "currentColor") {
5
+ this.size = size
6
+ this.color = color
7
+ this.spinner = undefined
8
+ }
9
+
10
+ /**
11
+ * @returns {HTMLElement|undefined}
12
+ */
13
+ get el() {
14
+ return this.spinner
15
+ }
16
+ /**
17
+ * @param {HTMLElement|undefined} parent
18
+ */
19
+ spin(parent) {
20
+ if (typeof parent === "undefined") {
21
+ parent = document.body
22
+ }
23
+ this.spinner = createHtmlElement(
24
+ `<alchemy-spinner size="${this.size}" color="${this.color}"></alchemy-spinner>`
25
+ )
26
+ parent.append(this.spinner)
27
+ return this
28
+ }
29
+
30
+ stop() {
31
+ if (this.spinner) {
32
+ this.spinner.remove()
33
+ this.spinner = undefined
34
+ }
35
+ }
36
+ }
@@ -0,0 +1,46 @@
1
+ function createSearchChoice(term, data) {
2
+ if (
3
+ $(data).filter(function () {
4
+ return this.text.localeCompare(term) === 0
5
+ }).length === 0
6
+ ) {
7
+ return {
8
+ id: term,
9
+ text: term
10
+ }
11
+ }
12
+ }
13
+
14
+ function initSelection(element, callback) {
15
+ const data = []
16
+ $(element.val().split(",")).each(function () {
17
+ data.push({
18
+ id: this.trim(),
19
+ text: this
20
+ })
21
+ })
22
+ callback(data)
23
+ }
24
+
25
+ export default function TagsAutocomplete(scope) {
26
+ const field = $("[data-autocomplete]", scope)
27
+ const url = field.data("autocomplete")
28
+ field.select2({
29
+ tags: true,
30
+ tokenSeparators: [","],
31
+ minimumInputLength: 1,
32
+ openOnEnter: false,
33
+ createSearchChoice,
34
+ ajax: {
35
+ url,
36
+ dataType: "json",
37
+ data: (term) => {
38
+ return { term }
39
+ },
40
+ results: (data) => {
41
+ return { results: data }
42
+ }
43
+ },
44
+ initSelection
45
+ })
46
+ }
@@ -24,7 +24,7 @@ function buildPromise(xhr) {
24
24
  })
25
25
  }
26
26
 
27
- function getToken() {
27
+ export function getToken() {
28
28
  const metaTag = document.querySelector('meta[name="csrf-token"]')
29
29
  return metaTag.attributes.content.textContent
30
30
  }
@@ -37,11 +37,11 @@ export function patch(url, data) {
37
37
  return ajax("PATCH", url, data)
38
38
  }
39
39
 
40
- export function post(url, data) {
41
- return ajax("POST", url, data)
40
+ export function post(url, data, accept = "application/json") {
41
+ return ajax("POST", url, data, accept)
42
42
  }
43
43
 
44
- export default function ajax(method, path, data) {
44
+ export default function ajax(method, path, data, accept = "application/json") {
45
45
  const xhr = new XMLHttpRequest()
46
46
  const promise = buildPromise(xhr)
47
47
  const url = new URL(window.location.origin + path)
@@ -52,7 +52,8 @@ export default function ajax(method, path, data) {
52
52
 
53
53
  xhr.open(method, url.toString())
54
54
  xhr.setRequestHeader("Content-type", "application/json; charset=utf-8")
55
- xhr.setRequestHeader("Accept", "application/json")
55
+ xhr.setRequestHeader("Accept", accept)
56
+ xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest")
56
57
  xhr.setRequestHeader("X-CSRF-Token", getToken())
57
58
 
58
59
  if (data && method.toLowerCase() !== "get") {
@@ -0,0 +1,20 @@
1
+ /**
2
+ * create a HTML element
3
+ * @param {string} text
4
+ * @returns {HTMLElement}
5
+ */
6
+ export function createHtmlElement(text) {
7
+ const element = document.createElement("template")
8
+ element.innerHTML = text
9
+ return element.content.children[0]
10
+ }
11
+
12
+ /**
13
+ * wrap element with wrappingElement
14
+ * @param {HTMLElement} element
15
+ * @param {HTMLElement} wrappingElement
16
+ */
17
+ export function wrap(element, wrappingElement) {
18
+ element.replaceWith(wrappingElement)
19
+ wrappingElement.appendChild(element)
20
+ }
@@ -0,0 +1,11 @@
1
+ export function formatFileSize(bytes) {
2
+ let exponent = bytes === 0 ? 0 : Math.floor(Math.log(bytes) / Math.log(1024))
3
+
4
+ // prevent format higher than GB
5
+ if (exponent > 3) {
6
+ exponent = 3
7
+ }
8
+
9
+ let value = (bytes / Math.pow(1024, exponent)).toFixed(2)
10
+ return value + " " + ["B", "kB", "MB", "GB"][exponent]
11
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * convert dashes and underscore strings into camelCase strings
3
+ * @param {string} str
4
+ * @returns {string}
5
+ */
6
+ export function toCamelCase(str) {
7
+ return str
8
+ .split(/-|_/)
9
+ .reduce((a, b) => a + b.charAt(0).toUpperCase() + b.slice(1))
10
+ }
@@ -1,17 +1,69 @@
1
+ import "@ungap/custom-elements"
1
2
  import "@hotwired/turbo-rails"
3
+ import Rails from "@rails/ujs"
2
4
 
3
- import translate from "alchemy_admin/i18n"
4
- import translationData from "alchemy_admin/translations"
5
- import fileEditors from "alchemy_admin/file_editors"
5
+ import GUI from "alchemy_admin/gui"
6
+ import { translate } from "alchemy_admin/i18n"
7
+ import Dirty from "alchemy_admin/dirty"
6
8
  import IngredientAnchorLink from "alchemy_admin/ingredient_anchor_link"
7
- import pictureEditors from "alchemy_admin/picture_editors"
8
9
  import ImageLoader from "alchemy_admin/image_loader"
9
10
  import ImageCropper from "alchemy_admin/image_cropper"
10
- import Datepicker from "alchemy_admin/datepicker"
11
+ import Initializer from "alchemy_admin/initializer"
12
+ import pictureSelector from "alchemy_admin/picture_selector"
13
+ import pleaseWaitOverlay from "alchemy_admin/please_wait_overlay"
11
14
  import Sitemap from "alchemy_admin/sitemap"
12
- import Tinymce from "alchemy_admin/tinymce"
15
+ import SortableElements from "alchemy_admin/sortable_elements"
16
+ import Spinner from "alchemy_admin/spinner"
13
17
  import PagePublicationFields from "alchemy_admin/page_publication_fields"
14
18
 
19
+ // Setting jQueryUIs global animation duration to something more snappy
20
+ $.fx.speeds._default = 400
21
+
22
+ // Web Components
23
+ import "alchemy_admin/components/button"
24
+ import "alchemy_admin/components/char_counter"
25
+ import "alchemy_admin/components/datepicker"
26
+ import "alchemy_admin/components/dialog_link"
27
+ import "alchemy_admin/components/element_editor"
28
+ import "alchemy_admin/components/ingredient_group"
29
+ import "alchemy_admin/components/link_buttons"
30
+ import "alchemy_admin/components/node_select"
31
+ import "alchemy_admin/components/uploader"
32
+ import "alchemy_admin/components/overlay"
33
+ import "alchemy_admin/components/page_select"
34
+ import "alchemy_admin/components/select"
35
+ import "alchemy_admin/components/spinner"
36
+ import "alchemy_admin/components/tinymce"
37
+ import "@shoelace/progress-bar"
38
+ import "@shoelace/switch"
39
+ import "@shoelace/tab"
40
+ import "@shoelace/tab-group"
41
+ import "@shoelace/tab-panel"
42
+ import "@shoelace/tooltip"
43
+
44
+ import { setDefaultAnimation } from "@shoelace/animation-registry"
45
+
46
+ // Change the default animation for all dialogs
47
+ setDefaultAnimation("tooltip.show", {
48
+ keyframes: [
49
+ { transform: "translateY(10px)", opacity: "0" },
50
+ { transform: "translateY(0)", opacity: "1" }
51
+ ],
52
+ options: {
53
+ duration: 100
54
+ }
55
+ })
56
+
57
+ setDefaultAnimation("tooltip.hide", {
58
+ keyframes: [
59
+ { transform: "translateY(0)", opacity: "1" },
60
+ { transform: "translateY(10px)", opacity: "0" }
61
+ ],
62
+ options: {
63
+ duration: 100
64
+ }
65
+ })
66
+
15
67
  // Global Alchemy object
16
68
  if (typeof window.Alchemy === "undefined") {
17
69
  window.Alchemy = {}
@@ -19,16 +71,21 @@ if (typeof window.Alchemy === "undefined") {
19
71
 
20
72
  // Enhance the global Alchemy object with imported features
21
73
  Object.assign(Alchemy, {
22
- // Global utility method for translating a given string
23
- t: translate,
24
- translations: Object.assign(Alchemy.translations || {}, translationData),
25
- fileEditors,
26
- pictureEditors,
74
+ ...Dirty,
75
+ GUI,
76
+ t: translate, // Global utility method for translating a given string
27
77
  ImageLoader: ImageLoader.init,
28
78
  ImageCropper,
79
+ Initializer,
29
80
  IngredientAnchorLink,
30
- Datepicker,
81
+ pictureSelector,
82
+ pleaseWaitOverlay,
31
83
  Sitemap,
32
- Tinymce,
84
+ SortableElements,
85
+ Spinner,
33
86
  PagePublicationFields
34
87
  })
88
+
89
+ Rails.start()
90
+
91
+ $(document).on("turbo:load", Initializer)
@@ -0,0 +1,10 @@
1
+ class Menubar extends HTMLElement {
2
+ constructor() {
3
+ super()
4
+ const template = this.querySelector("template")
5
+ const attachedShadowRoot = this.attachShadow({ mode: "open" })
6
+ attachedShadowRoot.appendChild(template.content.cloneNode(true))
7
+ }
8
+ }
9
+
10
+ customElements.define("alchemy-menubar", Menubar)