pageflow 17.0.5 → 17.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (636) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +342 -41
  3. data/README.md +3 -5
  4. data/admins/pageflow/accounts.rb +22 -20
  5. data/admins/pageflow/entry.rb +76 -26
  6. data/admins/pageflow/entry_templates.rb +10 -9
  7. data/admins/pageflow/folder.rb +1 -1
  8. data/admins/pageflow/membership.rb +15 -15
  9. data/admins/pageflow/revisions.rb +5 -5
  10. data/admins/pageflow/site_root_entry.rb +64 -0
  11. data/admins/pageflow/sites.rb +12 -3
  12. data/admins/pageflow/translations.rb +75 -0
  13. data/admins/pageflow/user.rb +21 -35
  14. data/app/assets/images/pageflow/admin/icons/comment.svg +1 -0
  15. data/app/assets/javascripts/pageflow/admin/entries.js +30 -5
  16. data/app/assets/javascripts/pageflow/dist/ui.js +4228 -900
  17. data/app/assets/javascripts/pageflow/editor/vendor.js +0 -1
  18. data/app/assets/javascripts/pageflow/ui.js +0 -1
  19. data/app/assets/stylesheets/pageflow/admin/entries/index_table.scss +2 -1
  20. data/app/assets/stylesheets/pageflow/admin/entry_comments_indicator.scss +45 -0
  21. data/app/assets/stylesheets/pageflow/admin/permalink_input.scss +8 -0
  22. data/app/assets/stylesheets/pageflow/admin.scss +1 -0
  23. data/app/assets/stylesheets/pageflow/animations/spin.scss +9 -0
  24. data/app/assets/stylesheets/pageflow/animations.scss +1 -0
  25. data/app/assets/stylesheets/pageflow/editor/background_positioning.scss +27 -5
  26. data/app/assets/stylesheets/pageflow/editor/base.scss +11 -1
  27. data/app/assets/stylesheets/pageflow/editor/drop_down_button.scss +20 -2
  28. data/app/assets/stylesheets/pageflow/editor/edit_configuration_view.scss +5 -0
  29. data/app/assets/stylesheets/pageflow/editor/file_folders.scss +127 -0
  30. data/app/assets/stylesheets/pageflow/editor/file_meta_data.scss +5 -2
  31. data/app/assets/stylesheets/pageflow/editor/file_meta_data_overlay.scss +45 -0
  32. data/app/assets/stylesheets/pageflow/editor/file_preview.scss +138 -0
  33. data/app/assets/stylesheets/pageflow/editor/file_references.scss +68 -0
  34. data/app/assets/stylesheets/pageflow/editor/file_settings_dialog.scss +1 -1
  35. data/app/assets/stylesheets/pageflow/editor/file_stage_icons.scss +17 -0
  36. data/app/assets/stylesheets/pageflow/editor/file_stages.scss +25 -32
  37. data/app/assets/stylesheets/pageflow/editor/file_thumbnails.scss +31 -48
  38. data/app/assets/stylesheets/pageflow/editor/file_type_pills.scss +73 -0
  39. data/app/assets/stylesheets/pageflow/editor/files.scss +242 -50
  40. data/app/assets/stylesheets/pageflow/editor/filtered_files.scss +161 -9
  41. data/app/assets/stylesheets/pageflow/editor/folder_breadcrumb.scss +40 -0
  42. data/app/assets/stylesheets/pageflow/editor/info_box.scss +23 -3
  43. data/app/assets/stylesheets/pageflow/editor/inputs/edit_defaults_button.scss +15 -0
  44. data/app/assets/stylesheets/pageflow/editor/inputs.scss +1 -0
  45. data/app/assets/stylesheets/pageflow/editor/list.scss +89 -37
  46. data/app/assets/stylesheets/pageflow/editor/list_search_field.scss +52 -0
  47. data/app/assets/stylesheets/pageflow/editor/manage_files.scss +9 -0
  48. data/app/assets/stylesheets/pageflow/editor/menu.scss +14 -0
  49. data/app/assets/stylesheets/pageflow/editor/move_to_folder_dialog.scss +83 -0
  50. data/app/assets/stylesheets/pageflow/editor/outline.scss +0 -13
  51. data/app/assets/stylesheets/pageflow/editor/sortable.scss +12 -0
  52. data/app/assets/stylesheets/pageflow/mixins/buttons.scss +4 -4
  53. data/app/assets/stylesheets/pageflow/mixins/pageflow.scss +9 -5
  54. data/app/assets/stylesheets/pageflow/ui/color_picker.scss +230 -0
  55. data/app/assets/stylesheets/pageflow/ui/forms.scss +38 -4
  56. data/app/assets/stylesheets/pageflow/ui/functions.scss +12 -2
  57. data/app/assets/stylesheets/pageflow/ui/input/color_input.scss +9 -8
  58. data/app/assets/stylesheets/pageflow/ui/input/file_name_input.scss +37 -0
  59. data/app/assets/stylesheets/pageflow/ui/input/text_area_input.scss +15 -0
  60. data/app/assets/stylesheets/pageflow/ui/overrides.scss +8 -0
  61. data/app/assets/stylesheets/pageflow/ui/properties.scss +34 -0
  62. data/app/assets/stylesheets/pageflow/ui/tabs_view.scss +8 -3
  63. data/app/assets/stylesheets/pageflow/ui.scss +4 -1
  64. data/app/controllers/concerns/pageflow/controller_delegation.rb +1 -1
  65. data/app/controllers/concerns/pageflow/edit_locking.rb +17 -10
  66. data/app/controllers/concerns/pageflow/entry_password_protection.rb +1 -0
  67. data/app/controllers/concerns/pageflow/public_https_mode.rb +2 -1
  68. data/app/controllers/concerns/pageflow/quota_verification.rb +5 -4
  69. data/app/controllers/pageflow/admin/initial_passwords_controller.rb +1 -0
  70. data/app/controllers/pageflow/application_controller.rb +19 -19
  71. data/app/controllers/pageflow/chapters_controller.rb +3 -2
  72. data/app/controllers/pageflow/edit_locks_controller.rb +3 -2
  73. data/app/controllers/pageflow/editor/encoding_confirmations_controller.rb +1 -0
  74. data/app/controllers/pageflow/editor/entries_controller.rb +3 -1
  75. data/app/controllers/pageflow/editor/entry_publications_controller.rb +1 -0
  76. data/app/controllers/pageflow/editor/file_folders_controller.rb +80 -0
  77. data/app/controllers/pageflow/editor/file_import_controller.rb +4 -3
  78. data/app/controllers/pageflow/editor/files_controller.rb +20 -10
  79. data/app/controllers/pageflow/editor/oembeds_controller.rb +21 -0
  80. data/app/controllers/pageflow/editor/widgets_controller.rb +1 -0
  81. data/app/controllers/pageflow/entries_controller.rb +85 -21
  82. data/app/controllers/pageflow/feeds_controller.rb +1 -1
  83. data/app/controllers/pageflow/files_controller.rb +1 -0
  84. data/app/controllers/pageflow/pages_controller.rb +4 -2
  85. data/app/controllers/pageflow/review/comment_thread_reads_controller.rb +30 -0
  86. data/app/controllers/pageflow/review/comment_threads_controller.rb +60 -0
  87. data/app/controllers/pageflow/review/comments_controller.rb +53 -0
  88. data/app/controllers/pageflow/revisions_controller.rb +5 -1
  89. data/app/controllers/pageflow/sitemaps_controller.rb +1 -1
  90. data/app/controllers/pageflow/storylines_controller.rb +1 -0
  91. data/app/helpers/pageflow/admin/cutoff_modes_helper.rb +12 -0
  92. data/app/helpers/pageflow/admin/entries_helper.rb +41 -1
  93. data/app/helpers/pageflow/admin/entry_translations_helper.rb +18 -0
  94. data/app/helpers/pageflow/admin/features_helper.rb +1 -1
  95. data/app/helpers/pageflow/admin/form_helper.rb +3 -3
  96. data/app/helpers/pageflow/admin/locales_helper.rb +10 -2
  97. data/app/helpers/pageflow/admin/memberships_helper.rb +32 -32
  98. data/app/helpers/pageflow/admin/revisions_helper.rb +1 -1
  99. data/app/helpers/pageflow/admin/sites_helper.rb +22 -0
  100. data/app/helpers/pageflow/admin/users_helper.rb +7 -5
  101. data/app/helpers/pageflow/admin/widgets_helper.rb +5 -5
  102. data/app/helpers/pageflow/asset_urls_helper.rb +1 -1
  103. data/app/helpers/pageflow/audio_files_helper.rb +5 -2
  104. data/app/helpers/pageflow/background_image_helper.rb +7 -6
  105. data/app/helpers/pageflow/common_entry_seed_helper.rb +7 -7
  106. data/app/helpers/pageflow/editor/config_helper.rb +3 -1
  107. data/app/helpers/pageflow/editor/files_helper.rb +1 -1
  108. data/app/helpers/pageflow/embed_code_helper.rb +3 -3
  109. data/app/helpers/pageflow/entries_helper.rb +52 -46
  110. data/app/helpers/pageflow/entry_json_seed_helper.rb +7 -6
  111. data/app/helpers/pageflow/feeds_helper.rb +2 -2
  112. data/app/helpers/pageflow/file_background_images_helper.rb +2 -2
  113. data/app/helpers/pageflow/file_thumbnails_helper.rb +4 -3
  114. data/app/helpers/pageflow/files_helper.rb +5 -4
  115. data/app/helpers/pageflow/folders_helper.rb +8 -5
  116. data/app/helpers/pageflow/help_entries_helper.rb +2 -2
  117. data/app/helpers/pageflow/hreflang_links_helper.rb +37 -0
  118. data/app/helpers/pageflow/info_box_helper.rb +7 -11
  119. data/app/helpers/pageflow/media_query_helper.rb +3 -3
  120. data/app/helpers/pageflow/navigation_bar_helper.rb +1 -1
  121. data/app/helpers/pageflow/overview_helper.rb +1 -1
  122. data/app/helpers/pageflow/page_types_helper.rb +5 -5
  123. data/app/helpers/pageflow/pages_helper.rb +29 -15
  124. data/app/helpers/pageflow/public_i18n_helper.rb +10 -9
  125. data/app/helpers/pageflow/quota_helper.rb +4 -4
  126. data/app/helpers/pageflow/render_json_helper.rb +6 -3
  127. data/app/helpers/pageflow/revision_file_helper.rb +2 -1
  128. data/app/helpers/pageflow/sites_helper.rb +3 -3
  129. data/app/helpers/pageflow/social_share_helper.rb +24 -10
  130. data/app/helpers/pageflow/social_share_links_helper.rb +12 -9
  131. data/app/helpers/pageflow/structured_data_helper.rb +5 -2
  132. data/app/helpers/pageflow/stub_page_configuration.rb +7 -3
  133. data/app/helpers/pageflow/text_direction_helper.rb +1 -1
  134. data/app/helpers/pageflow/themes_helper.rb +2 -4
  135. data/app/helpers/pageflow/video_files_helper.rb +29 -13
  136. data/app/helpers/pageflow/widgets_helper.rb +8 -6
  137. data/app/inputs/pageflow_permalink_input.rb +8 -3
  138. data/app/jobs/pageflow/application_job.rb +1 -0
  139. data/app/jobs/pageflow/entry_export_import/upload_and_publish_file_job.rb +1 -1
  140. data/app/jobs/pageflow/poll_meta_data_from_zencoder_job.rb +1 -0
  141. data/app/jobs/pageflow/poll_zencoder_job.rb +3 -2
  142. data/app/jobs/pageflow/process_image_or_text_track_job.rb +1 -0
  143. data/app/jobs/pageflow/prune_auto_snapshots_job.rb +1 -0
  144. data/app/jobs/pageflow/request_meta_data_from_zencoder_job.rb +1 -0
  145. data/app/jobs/pageflow/submit_file_to_zencoder_job.rb +1 -0
  146. data/app/mailers/pageflow/user_mailer.rb +1 -0
  147. data/app/models/concerns/pageflow/auto_generated_perma_id.rb +20 -1
  148. data/app/models/concerns/pageflow/entry_publication_states.rb +7 -3
  149. data/app/models/concerns/pageflow/feature_target.rb +8 -4
  150. data/app/models/concerns/pageflow/output_source.rb +3 -3
  151. data/app/models/concerns/pageflow/permalinkable.rb +2 -1
  152. data/app/models/concerns/pageflow/reusable_file.rb +24 -24
  153. data/app/models/concerns/pageflow/serialization_blacklist.rb +3 -5
  154. data/app/models/concerns/pageflow/suspendable.rb +5 -3
  155. data/app/models/concerns/pageflow/theme_referencer.rb +1 -1
  156. data/app/models/concerns/pageflow/translatable.rb +62 -0
  157. data/app/models/concerns/pageflow/translated_attributes.rb +101 -0
  158. data/app/models/concerns/pageflow/uploadable_file.rb +6 -6
  159. data/app/models/pageflow/account.rb +6 -5
  160. data/app/models/pageflow/account_member_query.rb +1 -1
  161. data/app/models/pageflow/account_role_query.rb +1 -1
  162. data/app/models/pageflow/application_query.rb +1 -1
  163. data/app/models/pageflow/application_record.rb +1 -1
  164. data/app/models/pageflow/audio_file.rb +4 -4
  165. data/app/models/pageflow/audio_file_url_templates.rb +1 -1
  166. data/app/models/pageflow/authentication_token.rb +2 -2
  167. data/app/models/pageflow/chapter.rb +6 -1
  168. data/app/models/pageflow/chapter_scaffold.rb +2 -4
  169. data/app/models/pageflow/cname_site_request_scope.rb +1 -1
  170. data/app/models/pageflow/comment.rb +30 -0
  171. data/app/models/pageflow/comment_thread.rb +65 -0
  172. data/app/models/pageflow/comment_thread_read.rb +22 -0
  173. data/app/models/pageflow/customized_theme.rb +9 -8
  174. data/app/models/pageflow/draft_entry.rb +49 -9
  175. data/app/models/pageflow/edit_lock.rb +19 -21
  176. data/app/models/pageflow/encoding_confirmation.rb +2 -2
  177. data/app/models/pageflow/entries_feed.rb +2 -2
  178. data/app/models/pageflow/entry.rb +46 -30
  179. data/app/models/pageflow/entry_at_revision.rb +14 -2
  180. data/app/models/pageflow/entry_comment_summary.rb +114 -0
  181. data/app/models/pageflow/entry_duplicate.rb +8 -5
  182. data/app/models/pageflow/entry_publication.rb +2 -2
  183. data/app/models/pageflow/entry_role_query.rb +4 -4
  184. data/app/models/pageflow/entry_template.rb +4 -4
  185. data/app/models/pageflow/entry_title_or_account_name_query.rb +2 -2
  186. data/app/models/pageflow/entry_translation_group.rb +42 -0
  187. data/app/models/pageflow/file_folder.rb +74 -0
  188. data/app/models/pageflow/file_reuse.rb +5 -4
  189. data/app/models/pageflow/file_usage.rb +18 -3
  190. data/app/models/pageflow/folder.rb +2 -2
  191. data/app/models/pageflow/home_button.rb +7 -7
  192. data/app/models/pageflow/image_file.rb +44 -25
  193. data/app/models/pageflow/image_file_url_templates.rb +4 -4
  194. data/app/models/pageflow/invitation_form.rb +2 -1
  195. data/app/models/pageflow/legal_info.rb +38 -0
  196. data/app/models/pageflow/managed_user_query.rb +1 -1
  197. data/app/models/pageflow/membership.rb +5 -5
  198. data/app/models/pageflow/nested_revision_component_copy.rb +263 -0
  199. data/app/models/pageflow/null_user.rb +1 -1
  200. data/app/models/pageflow/overview_button.rb +1 -1
  201. data/app/models/pageflow/page.rb +7 -3
  202. data/app/models/pageflow/permalink.rb +24 -2
  203. data/app/models/pageflow/permalink_directory.rb +7 -0
  204. data/app/models/pageflow/permalink_redirect.rb +7 -0
  205. data/app/models/pageflow/positioned_file.rb +5 -5
  206. data/app/models/pageflow/potential_entry_translations.rb +55 -0
  207. data/app/models/pageflow/potential_memberships.rb +5 -4
  208. data/app/models/pageflow/published_entry.rb +62 -11
  209. data/app/models/pageflow/revision.rb +29 -16
  210. data/app/models/pageflow/roles.rb +14 -18
  211. data/app/models/pageflow/site.rb +46 -3
  212. data/app/models/pageflow/site_root_entry_form.rb +27 -0
  213. data/app/models/pageflow/sitemaps.rb +10 -1
  214. data/app/models/pageflow/storyline.rb +5 -2
  215. data/app/models/pageflow/storyline_scaffold.rb +1 -1
  216. data/app/models/pageflow/text_track_file.rb +1 -1
  217. data/app/models/pageflow/text_track_file_url_templates.rb +1 -1
  218. data/app/models/pageflow/theme_customization_file.rb +3 -2
  219. data/app/models/pageflow/thumbnail_file_resolver.rb +1 -1
  220. data/app/models/pageflow/url_template.rb +1 -1
  221. data/app/models/pageflow/used_file.rb +13 -3
  222. data/app/models/pageflow/user_name_query.rb +2 -2
  223. data/app/models/pageflow/video_file.rb +22 -15
  224. data/app/models/pageflow/video_file_url_templates.rb +6 -4
  225. data/app/models/pageflow/widget.rb +5 -4
  226. data/app/models/pageflow/with_file_usage_extension.rb +1 -1
  227. data/app/models/pageflow/zencoder_attachment.rb +8 -8
  228. data/app/policies/pageflow/account_policy.rb +3 -1
  229. data/app/policies/pageflow/admin/admin_only_tab_policy.rb +1 -0
  230. data/app/policies/pageflow/admin/entry_tab_policy.rb +1 -0
  231. data/app/policies/pageflow/application_policy.rb +2 -0
  232. data/app/policies/pageflow/entry_policy.rb +7 -1
  233. data/app/policies/pageflow/entry_template_policy.rb +2 -1
  234. data/app/policies/pageflow/file_policy.rb +4 -7
  235. data/app/policies/pageflow/folder_policy.rb +18 -8
  236. data/app/policies/pageflow/membership_policy.rb +6 -4
  237. data/app/policies/pageflow/site_policy.rb +10 -3
  238. data/app/policies/pageflow/user_policy.rb +6 -4
  239. data/app/state_machines/pageflow/image_and_text_track_processing_state_machine.rb +3 -2
  240. data/app/state_machines/pageflow/media_encoding_state_machine.rb +5 -4
  241. data/app/views/admin/accounts/_entry_template_details.html.arb +2 -2
  242. data/app/views/admin/entries/_attributes_table.html.arb +6 -5
  243. data/app/views/admin/entries/_form.html.erb +2 -1
  244. data/app/views/admin/entries/_permalink_inputs.html.erb +9 -2
  245. data/app/views/admin/entry_templates/_form.html.erb +1 -3
  246. data/app/views/admin/site_root_entry/choose.html.erb +19 -0
  247. data/app/views/admin/sites/_fields.html.erb +14 -1
  248. data/app/views/admin/translations/_form.html.erb +31 -0
  249. data/app/views/admin/users/_attributes_table.html.arb +13 -0
  250. data/app/views/components/pageflow/admin/add_membership_button.rb +13 -12
  251. data/app/views/components/pageflow/admin/custom_scopes_renderer.rb +1 -0
  252. data/app/views/components/pageflow/admin/embed_code_field.rb +1 -0
  253. data/app/views/components/pageflow/admin/embedded_index_table.rb +9 -10
  254. data/app/views/components/pageflow/admin/entries_tab.rb +1 -0
  255. data/app/views/components/pageflow/admin/entry_publication_state_indicator.rb +6 -5
  256. data/app/views/components/pageflow/admin/entry_templates_tab.rb +2 -1
  257. data/app/views/components/pageflow/admin/entry_translations_tab.rb +102 -0
  258. data/app/views/components/pageflow/admin/entry_user_badge_list.rb +1 -0
  259. data/app/views/components/pageflow/admin/extensible_attributes_table.rb +9 -8
  260. data/app/views/components/pageflow/admin/features_tab.rb +1 -0
  261. data/app/views/components/pageflow/admin/grouped_folder_list.rb +1 -0
  262. data/app/views/components/pageflow/admin/icon_link_to.rb +1 -0
  263. data/app/views/components/pageflow/admin/members_tab.rb +4 -3
  264. data/app/views/components/pageflow/admin/membership_role_with_tooltip.rb +3 -2
  265. data/app/views/components/pageflow/admin/revisions_tab.rb +14 -10
  266. data/app/views/components/pageflow/admin/sites_tab.rb +1 -0
  267. data/app/views/components/pageflow/admin/tabs_view.rb +1 -0
  268. data/app/views/components/pageflow/admin/timestamp.rb +6 -5
  269. data/app/views/components/pageflow/admin/user_account_badge_list.rb +2 -3
  270. data/app/views/components/pageflow/admin/user_accounts_tab.rb +1 -0
  271. data/app/views/components/pageflow/admin/user_entries_tab.rb +1 -0
  272. data/app/views/components/pageflow/admin/users_tab.rb +1 -0
  273. data/app/views/pageflow/audio_files/_audio_file.json.jbuilder +0 -1
  274. data/app/views/pageflow/editor/config/_seeds.json.jbuilder +5 -3
  275. data/app/views/pageflow/editor/entries/_entry.json.jbuilder +2 -1
  276. data/app/views/pageflow/editor/entries/index.json.jbuilder +1 -1
  277. data/app/views/pageflow/editor/entries/seed.json.erb +1 -0
  278. data/app/views/pageflow/editor/entries/show.json.jbuilder +1 -1
  279. data/app/views/pageflow/editor/entry_publications/check.json.jbuilder +2 -2
  280. data/app/views/pageflow/editor/file_folders/_file_folder.json.jbuilder +5 -0
  281. data/app/views/pageflow/editor/file_folders/create.json.jbuilder +1 -0
  282. data/app/views/pageflow/editor/file_folders/index.json.jbuilder +3 -0
  283. data/app/views/pageflow/editor/files/_file.json.jbuilder +7 -14
  284. data/app/views/pageflow/editor/files/create.json.jbuilder +1 -1
  285. data/app/views/pageflow/editor/files/index.json.jbuilder +1 -1
  286. data/app/views/pageflow/editor/image_files/_image_file.json.jbuilder +3 -0
  287. data/app/views/pageflow/editor/sites/_site.json.jbuilder +1 -0
  288. data/app/views/pageflow/editor/video_files/_video_file.json.jbuilder +4 -3
  289. data/app/views/pageflow/entries/share_menu/_bluesky_link.html.erb +8 -0
  290. data/app/views/pageflow/entries/share_menu/_threads_link.html.erb +8 -0
  291. data/app/views/pageflow/files/_file.json.jbuilder +5 -3
  292. data/app/views/pageflow/image_files/_image_file.json.jbuilder +0 -1
  293. data/app/views/pageflow/review/comment_threads/_comment_thread.json.jbuilder +20 -0
  294. data/app/views/pageflow/review/comment_threads/create.json.jbuilder +2 -0
  295. data/app/views/pageflow/review/comment_threads/index.json.jbuilder +13 -0
  296. data/app/views/pageflow/review/comments/_comment.json.jbuilder +13 -0
  297. data/app/views/pageflow/review/comments/create.json.jbuilder +1 -0
  298. data/app/views/pageflow/sitemaps/index.xml.builder +9 -1
  299. data/app/views/pageflow/social_share/_entry_meta_tags.html.erb +1 -1
  300. data/app/views/pageflow/social_share/_page_meta_tags.html.erb +1 -1
  301. data/app/views/pageflow/structured_data/_entry.json.jbuilder +2 -3
  302. data/app/views/pageflow/video_files/_video_file.json.jbuilder +0 -1
  303. data/config/initializers/active_admin_patches.rb +3 -6
  304. data/config/initializers/admin_resource_tabs.rb +3 -0
  305. data/config/initializers/paperclip.rb +1 -0
  306. data/config/initializers/symmetric_encryption.rb +1 -1
  307. data/config/initializers/zencoder.rb +24 -13
  308. data/config/locales/de.yml +256 -12
  309. data/config/locales/en.yml +253 -15
  310. data/config/routes.rb +29 -13
  311. data/config/spring.rb +2 -1
  312. data/db/migrate/20140418225525_setup_schema.rb +2 -2
  313. data/db/migrate/20190306161431_copy_file_attributes_of_failed_uploads.rb +2 -2
  314. data/db/migrate/20190820152900_drop_accounts_themes.rb +2 -1
  315. data/db/migrate/20191202145757_create_pageflow_scrolled_sections.rb +11 -11
  316. data/db/migrate/20191202150657_create_pageflow_scrolled_chapters.rb +1 -1
  317. data/db/migrate/20191202154723_create_pageflow_scrolled_content_elements.rb +9 -9
  318. data/db/migrate/20191219143450_add_position_to_content_elements.rb +2 -1
  319. data/db/migrate/20200117133200_change_revision_appearance_option_default_and_null.rb +2 -1
  320. data/db/migrate/20200122115400_create_pageflow_entry_templates.rb +25 -25
  321. data/db/migrate/20200206134400_convert_legacy_scrolled_content_element_types.rb +3 -3
  322. data/db/migrate/20221215120856_associate_entry_templates_with_sites.rb +2 -2
  323. data/db/migrate/20230120092923_create_other_files.rb +2 -1
  324. data/db/migrate/20230419083307_create_pageflow_entry_translation_group.rb +9 -0
  325. data/db/migrate/20240612110434_add_cutoff_mode_name_to_sites.rb +5 -0
  326. data/db/migrate/20240918084059_create_pageflow_permalink_redirects.rb +14 -0
  327. data/db/migrate/20250508172234_ensure_scrolled_entries_have_main_storyline.rb +14 -0
  328. data/db/migrate/20250617090048_add_custom404_entry_to_sites.rb +5 -0
  329. data/db/migrate/20250617100000_add_perma_id_counter_to_entries.rb +28 -0
  330. data/db/migrate/20250722174123_add_perma_id_to_chapters.rb +10 -0
  331. data/db/migrate/20250725080603_add_perma_id_indexes_to_revision_components.rb +13 -0
  332. data/db/migrate/20250726000000_add_display_name_to_file_usages.rb +5 -0
  333. data/db/migrate/20251015000000_add_structured_data_type_name_to_revisions.rb +5 -0
  334. data/db/migrate/20251029142849_convert_legacy_social_embeds_to_unified_social_embed.rb +38 -0
  335. data/db/migrate/20251119083347_fix_main_storyline_positions.rb +16 -0
  336. data/db/migrate/20251119083348_ensure_scrolled_entries_have_excursion_storyline.rb +15 -0
  337. data/db/migrate/20260303000000_add_layout_version_to_revisions.rb +6 -0
  338. data/db/migrate/20260323000000_create_comment_threads_and_comments.rb +30 -0
  339. data/db/migrate/20260414000000_add_subject_range_to_comment_threads.rb +5 -0
  340. data/db/migrate/20260415000000_add_section_perma_id_to_comment_threads.rb +5 -0
  341. data/db/migrate/20260727000000_add_quote_to_comments.rb +5 -0
  342. data/db/migrate/20260728000000_create_file_folders.rb +17 -0
  343. data/db/migrate/20260805000000_add_attribute_translations_to_sites.rb +5 -0
  344. data/db/migrate/20260806000000_add_edited_at_to_comments.rb +5 -0
  345. data/db/migrate/20260810000000_create_pageflow_scrolled_lottie_files.rb +24 -0
  346. data/db/migrate/20260817000000_create_comment_thread_reads.rb +16 -0
  347. data/db/migrate/20260819000000_add_unread_comments_since_at_to_users.rb +18 -0
  348. data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/editor.js +12599 -5398
  349. data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/frontend.js +1275 -4560
  350. data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/react-client.js +20204 -22
  351. data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/react-server.js +18657 -19
  352. data/entry_types/paged/app/controllers/pageflow_paged/entries_controller.rb +1 -0
  353. data/entry_types/paged/app/helpers/pageflow_paged/page_background_asset_helper.rb +1 -1
  354. data/entry_types/paged/app/helpers/pageflow_paged/third_party_embed_consent_helper.rb +7 -7
  355. data/entry_types/paged/app/views/pageflow_paged/editor/entries/_seed.json.jbuilder +1 -0
  356. data/entry_types/paged/app/views/pageflow_paged/entries/show.html.erb +1 -0
  357. data/entry_types/paged/lib/pageflow_paged/plugin.rb +4 -0
  358. data/entry_types/paged/lib/pageflow_paged/react/page_type.rb +1 -1
  359. data/entry_types/paged/lib/pageflow_paged/react/widget_type.rb +3 -3
  360. data/entry_types/paged/lib/pageflow_paged.rb +1 -1
  361. data/entry_types/scrolled/app/assets/stylesheets/pageflow_scrolled/ui.scss +2 -0
  362. data/entry_types/scrolled/app/controllers/pageflow_scrolled/editor/chapters_controller.rb +5 -3
  363. data/entry_types/scrolled/app/controllers/pageflow_scrolled/editor/content_elements_controller.rb +35 -5
  364. data/entry_types/scrolled/app/controllers/pageflow_scrolled/editor/sections_controller.rb +4 -5
  365. data/entry_types/scrolled/app/controllers/pageflow_scrolled/entries_controller.rb +23 -2
  366. data/entry_types/scrolled/app/helpers/pageflow_scrolled/cache_helper.rb +3 -3
  367. data/entry_types/scrolled/app/helpers/pageflow_scrolled/editor/entry_json_seed_helper.rb +8 -5
  368. data/entry_types/scrolled/app/helpers/pageflow_scrolled/editor/seed_html_helper.rb +7 -3
  369. data/entry_types/scrolled/app/helpers/pageflow_scrolled/entry_json_seed_helper.rb +72 -10
  370. data/entry_types/scrolled/app/helpers/pageflow_scrolled/i18n_helper.rb +28 -13
  371. data/entry_types/scrolled/app/helpers/pageflow_scrolled/packs_helper.rb +41 -12
  372. data/entry_types/scrolled/app/helpers/pageflow_scrolled/react_server_side_rendering_helper.rb +23 -25
  373. data/entry_types/scrolled/app/helpers/pageflow_scrolled/sprockets_helper.rb +16 -0
  374. data/entry_types/scrolled/app/helpers/pageflow_scrolled/themes_helper.rb +189 -3
  375. data/entry_types/scrolled/app/models/pageflow_scrolled/chapter.rb +15 -14
  376. data/entry_types/scrolled/app/models/pageflow_scrolled/content_element.rb +61 -7
  377. data/entry_types/scrolled/app/models/pageflow_scrolled/lottie_file.rb +6 -0
  378. data/entry_types/scrolled/app/models/pageflow_scrolled/lottie_file_url_templates.rb +16 -0
  379. data/entry_types/scrolled/app/models/pageflow_scrolled/section.rb +12 -1
  380. data/entry_types/scrolled/app/models/pageflow_scrolled/storyline.rb +20 -1
  381. data/entry_types/scrolled/app/views/pageflow_scrolled/editor/entries/_head.html.erb +1 -0
  382. data/entry_types/scrolled/app/views/pageflow_scrolled/editor/sections/_section_with_content_elements.json.jbuilder +2 -2
  383. data/entry_types/scrolled/app/views/pageflow_scrolled/entries/show.html.erb +15 -12
  384. data/entry_types/scrolled/app/views/pageflow_scrolled/entry_json_seed/_entry.json.jbuilder +45 -17
  385. data/entry_types/scrolled/app/views/pageflow_scrolled/entry_json_seed/_entry_translations.json.jbuilder +14 -0
  386. data/entry_types/scrolled/app/views/pageflow_scrolled/entry_json_seed/_theme.json.jbuilder +34 -5
  387. data/entry_types/scrolled/app/views/pageflow_scrolled/favicons/_entry.html.erb +1 -1
  388. data/entry_types/scrolled/app/views/pageflow_scrolled/storylines/_storyline.json.jbuilder +7 -0
  389. data/entry_types/scrolled/config/configuration_schemas/pageflow-scrolled.json +414 -0
  390. data/entry_types/scrolled/config/locales/de.yml +1094 -78
  391. data/entry_types/scrolled/config/locales/en.yml +1083 -78
  392. data/entry_types/scrolled/config/routes.rb +18 -8
  393. data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/install_generator.rb +11 -11
  394. data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/templates/theme/logoDarkVariantDesktop.svg +56 -0
  395. data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/templates/theme/logoDarkVariantMobile.svg +22 -0
  396. data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/templates/themes_plugin.rb.tt +26 -11
  397. data/entry_types/scrolled/lib/pageflow_scrolled/additional_packs.rb +27 -8
  398. data/entry_types/scrolled/lib/pageflow_scrolled/additional_seed_data.rb +2 -2
  399. data/entry_types/scrolled/lib/pageflow_scrolled/additional_theme_assets.rb +27 -0
  400. data/entry_types/scrolled/lib/pageflow_scrolled/configuration.rb +67 -10
  401. data/entry_types/scrolled/lib/pageflow_scrolled/configuration_schemas.rb +91 -0
  402. data/entry_types/scrolled/lib/pageflow_scrolled/content_element_consent_vendors.rb +1 -1
  403. data/entry_types/scrolled/lib/pageflow_scrolled/engine.rb +2 -1
  404. data/entry_types/scrolled/lib/pageflow_scrolled/entry_file_reference_locations.rb +71 -0
  405. data/entry_types/scrolled/lib/pageflow_scrolled/entry_structured_data_types/faq_page.rb +58 -0
  406. data/entry_types/scrolled/lib/pageflow_scrolled/file_reference_locations.rb +69 -0
  407. data/entry_types/scrolled/lib/pageflow_scrolled/plugin.rb +222 -19
  408. data/entry_types/scrolled/lib/pageflow_scrolled/react_widget_type.rb +2 -4
  409. data/entry_types/scrolled/lib/pageflow_scrolled/seeds.rb +76 -54
  410. data/entry_types/scrolled/lib/pageflow_scrolled/theme_options_default_scale.rb +35 -0
  411. data/entry_types/scrolled/lib/pageflow_scrolled.rb +14 -1
  412. data/entry_types/scrolled/lib/tasks/pageflow_scrolled/storybook.rake +24 -5
  413. data/entry_types/scrolled/package/config/configurationSchemas.js +70 -0
  414. data/entry_types/scrolled/package/config/rollup/configurationSchemas.js +19 -0
  415. data/entry_types/scrolled/package/config/webpack.js +94 -0
  416. data/entry_types/scrolled/package/contentElements/hotspots-frontend.css +1 -0
  417. data/entry_types/scrolled/package/contentElements/hotspots-frontend.js +1795 -0
  418. data/entry_types/scrolled/package/contentElements/inlineBeforeAfter-frontend.css +1 -0
  419. data/entry_types/scrolled/package/contentElements/inlineBeforeAfter-frontend.js +219 -0
  420. data/entry_types/scrolled/package/contentElements/lottieAnimation-frontend.css +1 -0
  421. data/entry_types/scrolled/package/contentElements/lottieAnimation-frontend.js +244 -0
  422. data/entry_types/scrolled/package/contentElements/socialEmbed-frontend.css +1 -0
  423. data/entry_types/scrolled/package/contentElements/socialEmbed-frontend.js +823 -0
  424. data/entry_types/scrolled/package/contentElements/tikTokEmbed-frontend.css +1 -0
  425. data/entry_types/scrolled/package/contentElements/tikTokEmbed-frontend.js +109 -0
  426. data/entry_types/scrolled/package/contentElements/twitterEmbed-frontend.css +1 -0
  427. data/entry_types/scrolled/package/contentElements/twitterEmbed-frontend.js +277 -0
  428. data/entry_types/scrolled/package/contentElements/videoEmbed-frontend.css +1 -0
  429. data/entry_types/scrolled/package/contentElements/videoEmbed-frontend.js +244 -0
  430. data/entry_types/scrolled/package/contentElements-editor.js +3155 -583
  431. data/entry_types/scrolled/package/contentElements-frontend.css +1 -1
  432. data/entry_types/scrolled/package/contentElements-frontend.js +3375 -1585
  433. data/entry_types/scrolled/package/editor.css +1 -0
  434. data/entry_types/scrolled/package/editor.js +8452 -2867
  435. data/entry_types/scrolled/package/entryState.js +1600 -0
  436. data/entry_types/scrolled/package/frontend/FloatingPortalRootProvider-20c600de.js +1979 -0
  437. data/entry_types/scrolled/package/frontend/FloatingPortalRootProvider-58189220.js +2538 -0
  438. data/entry_types/scrolled/package/frontend/{PhonePlatformContext-4ec6b2de.js → PhonePlatformContext-035a99fa.js} +9 -15
  439. data/entry_types/scrolled/package/frontend/PhonePlatformContext-9da43797.js +33 -0
  440. data/entry_types/scrolled/package/frontend/Placeholder.module-bf0966b4.js +5267 -0
  441. data/entry_types/scrolled/package/frontend/Placeholder.module-d22a9335.js +4180 -0
  442. data/entry_types/scrolled/package/frontend/ThemeIcon-ab834849.js +754 -0
  443. data/entry_types/scrolled/package/frontend/ThemeIcon-f6cb3a8f.js +773 -0
  444. data/entry_types/scrolled/package/frontend/ToggleFullscreenCornerButton-30fd1124.js +39 -0
  445. data/entry_types/scrolled/package/frontend/ToggleFullscreenCornerButton-61c25224.js +72 -0
  446. data/entry_types/scrolled/package/frontend/Viewer-1074fd59.js +147 -0
  447. data/entry_types/scrolled/package/frontend/Viewer-1482ca34.js +480 -0
  448. data/entry_types/scrolled/package/frontend/Viewer-70504231.js +210 -0
  449. data/entry_types/scrolled/package/frontend/{Viewer-1bb5597c.js → Viewer-cc8d4072.js} +100 -135
  450. data/entry_types/scrolled/package/frontend/Wavesurfer-656e3c36.js +302 -0
  451. data/entry_types/scrolled/package/frontend/Wavesurfer-b753b838.js +385 -0
  452. data/entry_types/scrolled/package/frontend/commenting.css +1 -0
  453. data/entry_types/scrolled/package/frontend/extensions-167ae143.js +1455 -0
  454. data/entry_types/scrolled/package/frontend/extensions-2318f92b.js +5918 -0
  455. data/entry_types/scrolled/package/frontend/extensions-a461fd13.js +4890 -0
  456. data/entry_types/scrolled/package/frontend/extensions-c98269fd.js +1982 -0
  457. data/entry_types/scrolled/package/frontend/i18n-493cd2a6.js +93 -0
  458. data/entry_types/scrolled/package/frontend/i18n-e06cac14.js +100 -0
  459. data/entry_types/scrolled/package/frontend/{index-11f32f10.js → index-2e5546f7.js} +39 -54
  460. data/entry_types/scrolled/package/frontend/index-de2b418d.js +130 -0
  461. data/entry_types/scrolled/package/frontend/index.css +1 -1
  462. data/entry_types/scrolled/package/frontend/index.js +1976 -1367
  463. data/entry_types/scrolled/package/frontend/inlineEditing.css +1 -0
  464. data/entry_types/scrolled/package/frontend/useContentElementEditorState-a084912e.js +25 -0
  465. data/entry_types/scrolled/package/frontend/useDelayedBoolean-a387d85b.js +24 -0
  466. data/entry_types/scrolled/package/frontend/usePhonePlatform-4ecb96d4.js +8 -0
  467. data/entry_types/scrolled/package/frontend/usePhonePlatform-ce9ff08d.js +8 -0
  468. data/entry_types/scrolled/package/frontend-server.js +20 -210
  469. data/entry_types/scrolled/package/package.json +22 -12
  470. data/entry_types/scrolled/package/review.css +1 -0
  471. data/entry_types/scrolled/package/review.js +3306 -0
  472. data/entry_types/scrolled/package/testHelpers.js +952 -239
  473. data/entry_types/scrolled/package/values/widgets.module.css +18 -0
  474. data/entry_types/scrolled/package/widgets/consentBar.css +1 -1
  475. data/entry_types/scrolled/package/widgets/consentBar.js +275 -315
  476. data/entry_types/scrolled/package/widgets/defaultNavigation.css +2 -2
  477. data/entry_types/scrolled/package/widgets/defaultNavigation.js +961 -432
  478. data/entry_types/scrolled/package/widgets/excursionSheet.css +1 -0
  479. data/entry_types/scrolled/package/widgets/excursionSheet.js +225 -0
  480. data/entry_types/scrolled/package/widgets/iconInlineFileRights.css +1 -1
  481. data/entry_types/scrolled/package/widgets/iconInlineFileRights.js +62 -32
  482. data/entry_types/scrolled/package/widgets/iconScrollIndicator.css +1 -0
  483. data/entry_types/scrolled/package/widgets/iconScrollIndicator.js +67 -0
  484. data/entry_types/scrolled/package/widgets/mainStorylineSheet.css +1 -0
  485. data/entry_types/scrolled/package/widgets/mainStorylineSheet.js +100 -0
  486. data/entry_types/scrolled/package/widgets/textInlineFileRights.css +1 -1
  487. data/entry_types/scrolled/package/widgets/textInlineFileRights.js +48 -26
  488. data/entry_types/scrolled/package/widgets-server.js +2 -0
  489. data/entry_types/scrolled/spec/factories/chapters.rb +14 -1
  490. data/entry_types/scrolled/spec/factories/content_elements.rb +1 -1
  491. data/entry_types/scrolled/spec/factories/lottie_files.rb +29 -0
  492. data/entry_types/scrolled/spec/fixtures/animation.lottie +0 -0
  493. data/entry_types/scrolled/spec/fixtures/font.woff +0 -0
  494. data/entry_types/scrolled/spec/fixtures/font.woff2 +0 -0
  495. data/lib/generators/pageflow/active_admin_initializer/active_admin_initializer_generator.rb +5 -3
  496. data/lib/generators/pageflow/assets/assets_generator.rb +7 -5
  497. data/lib/generators/pageflow/cancan/cancan_generator.rb +2 -1
  498. data/lib/generators/pageflow/cancan/templates/ability.rb +1 -1
  499. data/lib/generators/pageflow/error_pages/error_pages_generator.rb +2 -1
  500. data/lib/generators/pageflow/initializer/initializer_generator.rb +3 -2
  501. data/lib/generators/pageflow/install/install_generator.rb +2 -2
  502. data/lib/generators/pageflow/procfile/procfile_generator.rb +2 -1
  503. data/lib/generators/pageflow/resque/resque_generator.rb +4 -4
  504. data/lib/generators/pageflow/resque/templates/resque.rake +1 -1
  505. data/lib/generators/pageflow/routes/routes_generator.rb +4 -2
  506. data/lib/generators/pageflow/seeds/seeds_generator.rb +3 -2
  507. data/lib/generators/pageflow/seeds/templates/seeds.rb +6 -6
  508. data/lib/generators/pageflow/theme/theme_generator.rb +2 -1
  509. data/lib/generators/pageflow/user/user_generator.rb +2 -1
  510. data/lib/pageflow/ability_mixin.rb +25 -15
  511. data/lib/pageflow/active_admin_patches/views/attributes_table.rb +1 -0
  512. data/lib/pageflow/active_admin_patches/views/pages/base.rb +3 -2
  513. data/lib/pageflow/active_admin_patches/views/table_for.rb +1 -0
  514. data/lib/pageflow/additional_headers.rb +27 -0
  515. data/lib/pageflow/admin/attributes_table_rows.rb +3 -3
  516. data/lib/pageflow/admin/tabs.rb +1 -1
  517. data/lib/pageflow/built_in_file_type.rb +1 -1
  518. data/lib/pageflow/built_in_page_types_plugin.rb +1 -1
  519. data/lib/pageflow/built_in_widget_type.rb +2 -2
  520. data/lib/pageflow/built_in_widget_types_plugin.rb +2 -1
  521. data/lib/pageflow/configuration.rb +183 -18
  522. data/lib/pageflow/cutoff_modes.rb +39 -0
  523. data/lib/pageflow/deprecation.rb +19 -0
  524. data/lib/pageflow/editor_controller.rb +6 -10
  525. data/lib/pageflow/engine.rb +5 -6
  526. data/lib/pageflow/entries_controller_env_helper.rb +32 -2
  527. data/lib/pageflow/entry_export_import/attachment_files.rb +1 -1
  528. data/lib/pageflow/entry_export_import/entry_serialization.rb +9 -8
  529. data/lib/pageflow/entry_export_import/file_mappings.rb +1 -0
  530. data/lib/pageflow/entry_export_import/page_type_versions.rb +2 -2
  531. data/lib/pageflow/entry_export_import/revision_serialization/import.rb +11 -1
  532. data/lib/pageflow/entry_export_import/revision_serialization.rb +3 -0
  533. data/lib/pageflow/entry_export_import.rb +3 -3
  534. data/lib/pageflow/entry_structured_data_types.rb +43 -0
  535. data/lib/pageflow/entry_type_configuration.rb +1 -0
  536. data/lib/pageflow/entry_types.rb +2 -2
  537. data/lib/pageflow/feature.rb +1 -1
  538. data/lib/pageflow/features.rb +4 -6
  539. data/lib/pageflow/file_importers.rb +4 -4
  540. data/lib/pageflow/file_type.rb +5 -5
  541. data/lib/pageflow/file_types.rb +4 -4
  542. data/lib/pageflow/global_config_api.rb +5 -6
  543. data/lib/pageflow/help_entries.rb +7 -7
  544. data/lib/pageflow/help_entry.rb +1 -1
  545. data/lib/pageflow/hooks.rb +1 -1
  546. data/lib/pageflow/nested_revision_component.rb +9 -27
  547. data/lib/pageflow/news_item_api.rb +1 -1
  548. data/lib/pageflow/oembed_providers.rb +42 -0
  549. data/lib/pageflow/page_type.rb +2 -3
  550. data/lib/pageflow/page_types.rb +3 -3
  551. data/lib/pageflow/paperclip_interpolations/support.rb +1 -1
  552. data/lib/pageflow/paperclip_processors/vtt.rb +1 -0
  553. data/lib/pageflow/paperclip_processors/webp.rb +2 -2
  554. data/lib/pageflow/partial_editor_fragment_renderer.rb +2 -2
  555. data/lib/pageflow/plugin.rb +1 -2
  556. data/lib/pageflow/primary_domain_entry_redirect.rb +6 -0
  557. data/lib/pageflow/quota.rb +9 -5
  558. data/lib/pageflow/quotas.rb +1 -1
  559. data/lib/pageflow/rails_version.rb +14 -2
  560. data/lib/pageflow/react.rb +1 -1
  561. data/lib/pageflow/revision_component.rb +8 -40
  562. data/lib/pageflow/revision_components.rb +16 -6
  563. data/lib/pageflow/seeds.rb +12 -16
  564. data/lib/pageflow/theme.rb +1 -1
  565. data/lib/pageflow/theme_customizations.rb +10 -10
  566. data/lib/pageflow/themes.rb +44 -3
  567. data/lib/pageflow/user_mixin.rb +18 -6
  568. data/lib/pageflow/version.rb +1 -1
  569. data/lib/pageflow/widget_type.rb +4 -4
  570. data/lib/pageflow/widget_types.rb +9 -9
  571. data/lib/pageflow/zencoder_api.rb +32 -42
  572. data/lib/pageflow/zencoder_audio_output_definition.rb +14 -13
  573. data/lib/pageflow/zencoder_meta_data_output_definition.rb +3 -2
  574. data/lib/pageflow/zencoder_output_definition.rb +16 -14
  575. data/lib/pageflow/zencoder_video_output_definition.rb +140 -88
  576. data/lib/pageflow.rb +8 -2
  577. data/lib/tasks/pageflow_tasks.rake +1 -1
  578. data/package/config/eslint-rules/documented-in-toc.js +125 -0
  579. data/package/config/jest/index.js +0 -1
  580. data/package/config/webpack.js +0 -1
  581. data/package/config/webpack5.js +0 -1
  582. data/package/editor.js +4880 -2313
  583. data/package/frontend.js +710 -1223
  584. data/package/package.json +3 -1
  585. data/package/review.js +384 -0
  586. data/package/testHelpers.js +257 -243
  587. data/package/ui.js +1487 -813
  588. data/package/vendor/stubs/wysihtml5.js +2 -0
  589. data/spec/factories/accounts.rb +37 -22
  590. data/spec/factories/audio_files.rb +2 -2
  591. data/spec/factories/authentication_tokens.rb +4 -4
  592. data/spec/factories/chapters.rb +4 -4
  593. data/spec/factories/comment_thread_reads.rb +10 -0
  594. data/spec/factories/comment_threads.rb +10 -0
  595. data/spec/factories/comments.rb +9 -0
  596. data/spec/factories/draft_entries.rb +14 -6
  597. data/spec/factories/edit_locks.rb +1 -1
  598. data/spec/factories/entries.rb +28 -19
  599. data/spec/factories/entry_translation_groups.rb +6 -0
  600. data/spec/factories/file_folders.rb +8 -0
  601. data/spec/factories/file_usages.rb +2 -1
  602. data/spec/factories/folders.rb +1 -1
  603. data/spec/factories/image_files.rb +2 -2
  604. data/spec/factories/pages.rb +3 -3
  605. data/spec/factories/published_entries.rb +28 -8
  606. data/spec/factories/revisions.rb +1 -1
  607. data/spec/factories/sites.rb +6 -0
  608. data/spec/factories/test_multi_attachment_files.rb +1 -1
  609. data/spec/factories/text_track_files.rb +1 -1
  610. data/spec/factories/uploadable_files.rb +1 -1
  611. data/spec/factories/users.rb +6 -6
  612. data/spec/factories/video_files.rb +2 -2
  613. data/spec/factories/widgets.rb +1 -1
  614. data/spec/fixtures/7x15_rotated.jpg +0 -0
  615. data/vendor/assets/javascripts/wysihtml-toolbar.js +19288 -0
  616. metadata +266 -92
  617. data/app/assets/stylesheets/pageflow/editor/select_button.scss +0 -51
  618. data/config/initializers/revision_components.rb +0 -5
  619. data/config/locales/twitter_to_x.de.yml +0 -6
  620. data/config/locales/twitter_to_x.en.yml +0 -6
  621. data/entry_types/scrolled/app/helpers/pageflow_scrolled/generated_media_queries_helper.rb +0 -55
  622. data/entry_types/scrolled/config/locales/twitter_to_x.de.yml +0 -12
  623. data/entry_types/scrolled/config/locales/twitter_to_x.en.yml +0 -12
  624. data/entry_types/scrolled/config/locales/vr_image_projection.de.yml +0 -24
  625. data/entry_types/scrolled/config/locales/vr_image_projection.en.yml +0 -24
  626. data/entry_types/scrolled/package/frontend/EditableInlineText.module-ebd22921.js +0 -5497
  627. data/entry_types/scrolled/package/frontend/ToggleFullscreenCornerButton-b79159cc.js +0 -107
  628. data/entry_types/scrolled/package/frontend/Viewer-1ecf3375.js +0 -154
  629. data/entry_types/scrolled/package/frontend/Wavesurfer-7d9cf1b7.js +0 -333
  630. data/entry_types/scrolled/package/frontend/arrowRight-62998af9.js +0 -77
  631. data/entry_types/scrolled/package/frontend/components-024a9893.js +0 -2853
  632. data/entry_types/scrolled/package/frontend/createSuper-d0f30da3.js +0 -115
  633. data/entry_types/scrolled/package/frontend/i18n-ce13a8bf.js +0 -1129
  634. data/entry_types/scrolled/package/frontend/useContentElementEditorState-4f4c3cf6.js +0 -52
  635. data/lib/generators/pageflow/resque/templates/resque_enqueue_after_commit_patch.rb +0 -25
  636. data/package/vendor/jquery.minicolors.js +0 -1108
@@ -1,60 +1,19 @@
1
1
  import I18n from 'i18n-js';
2
- import { editor, InlineFileRightsMenuItem, NoOptionsHintView, buttonStyles } from 'pageflow-scrolled/editor';
3
- import { contentElementWidths, utils } from 'pageflow-scrolled/frontend';
4
- import { SelectInputView, SeparatorView, LabelOnlyView, ColorInputView, UrlInputView, CheckBoxInputView as CheckBoxInputView$1, TextInputView, SliderInputView, ConfigurationEditorView, cssModulesUtils, NumberInputView } from 'pageflow/ui';
5
- import { InfoBoxView, FileInputView, CheckBoxInputView, ColorInputView as ColorInputView$1, editor as editor$1, transientReferences, ListView, SliderInputView as SliderInputView$1, SelectInputView as SelectInputView$1, EnumTableCellView } from 'pageflow/editor';
6
- import Marionette from 'backbone.marionette';
2
+ import { editor, InlineFileRightsMenuItem, ImageModifierListInputView, EditMotifAreaDialogView, buttonStyles, dialogViewStyles, dialogView, PlaybackStartSelectInputView, ScrollRangeSelectInputView } from 'pageflow-scrolled/editor';
3
+ import { contentElementWidths, utils, processImageModifiers, paletteColor } from 'pageflow-scrolled/frontend';
4
+ import { SelectInputView, SeparatorView, CheckBoxInputView, LabelOnlyView, ColorInputView, UrlInputView, TextInputView, SliderInputView, cssModulesUtils, TabsView, inputView, NumberInputView } from 'pageflow/ui';
5
+ import { InfoBoxView, FileInputView, CheckBoxInputView as CheckBoxInputView$1, ColorInputView as ColorInputView$1, EditConfigurationView, DestroyMenuItem, transientReferences, ListView, cssModulesUtils as cssModulesUtils$1, app, SelectInputView as SelectInputView$1, SeparatorView as SeparatorView$1, SliderInputView as SliderInputView$1, EnumTableCellView, editor as editor$1, UploadableFile, altMetaDataAttribute, altConfigurationEditorInput, OembedUrlInputView } from 'pageflow/editor';
6
+ import { Point, Node } from 'slate';
7
7
  import Backbone from 'backbone';
8
+ import Marionette from 'backbone.marionette';
8
9
  import _ from 'underscore';
9
-
10
- function _defineProperty(obj, key, value) {
11
- if (key in obj) {
12
- Object.defineProperty(obj, key, {
13
- value: value,
14
- enumerable: true,
15
- configurable: true,
16
- writable: true
17
- });
18
- } else {
19
- obj[key] = value;
20
- }
21
-
22
- return obj;
23
- }
24
-
25
- function ownKeys(object, enumerableOnly) {
26
- var keys = Object.keys(object);
27
-
28
- if (Object.getOwnPropertySymbols) {
29
- var symbols = Object.getOwnPropertySymbols(object);
30
- if (enumerableOnly) symbols = symbols.filter(function (sym) {
31
- return Object.getOwnPropertyDescriptor(object, sym).enumerable;
32
- });
33
- keys.push.apply(keys, symbols);
34
- }
35
-
36
- return keys;
37
- }
38
-
39
- function _objectSpread2(target) {
40
- for (var i = 1; i < arguments.length; i++) {
41
- var source = arguments[i] != null ? arguments[i] : {};
42
-
43
- if (i % 2) {
44
- ownKeys(Object(source), true).forEach(function (key) {
45
- _defineProperty(target, key, source[key]);
46
- });
47
- } else if (Object.getOwnPropertyDescriptors) {
48
- Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
49
- } else {
50
- ownKeys(Object(source)).forEach(function (key) {
51
- Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
52
- });
53
- }
54
- }
55
-
56
- return target;
57
- }
10
+ import React, { useReducer, useEffect, useRef } from 'react';
11
+ import ReactDOM from 'react-dom';
12
+ import classNames from 'classnames';
13
+ import { DraggableCore } from 'react-draggable';
14
+ import { DotLottie } from '@lottiefiles/dotlottie-web';
15
+ import wasmUrl from '@lottiefiles/dotlottie-web/dotlottie-player.wasm';
16
+ import { review } from 'pageflow-scrolled/review';
58
17
 
59
18
  var img = "data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512'%3e%3c!--! Font Awesome Pro 6.1.1 by %40fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons%2c Inc. --%3e%3cpath fill='white' d='M448 448c0 17.69-14.33 32-32 32h-96c-17.67 0-32-14.31-32-32s14.33-32 32-32h16v-144h-224v144H128c17.67 0 32 14.31 32 32s-14.33 32-32 32H32c-17.67 0-32-14.31-32-32s14.33-32 32-32h16v-320H32c-17.67 0-32-14.31-32-32s14.33-32 32-32h96c17.67 0 32 14.31 32 32s-14.33 32-32 32H112v112h224v-112H320c-17.67 0-32-14.31-32-32s14.33-32 32-32h96c17.67 0 32 14.31 32 32s-14.33 32-32 32h-16v320H416C433.7 416 448 430.3 448 448z'/%3e%3c/svg%3e";
60
19
 
@@ -66,29 +25,34 @@ editor.contentElementTypes.register('heading', {
66
25
  width: contentElementWidths.xl,
67
26
  marginTop: 'none'
68
27
  },
69
- configurationEditor: function configurationEditor(_ref) {
70
- var entry = _ref.entry;
28
+ defaultsInputs() {
29
+ this.input('hyphens', SelectInputView, {
30
+ values: ['auto', 'manual']
31
+ });
32
+ },
33
+ configurationEditor({
34
+ entry
35
+ }) {
71
36
  this.listenTo(this.model, 'change:hyphens', this.refresh);
72
- var modelDelegator = entry.createLegacyTypographyVariantDelegator({
37
+ const modelDelegator = entry.createLegacyTypographyVariantDelegator({
73
38
  model: this.model,
74
39
  paletteColorPropertyName: 'color'
75
40
  });
76
41
  this.tab('general', function () {
77
- this.input('textSize', SelectInputView, {
78
- values: ['auto', 'large', 'medium', 'small']
79
- });
80
42
  this.group('ContentElementTypographyVariant', {
81
- entry: entry,
43
+ entry,
82
44
  model: modelDelegator,
83
- getPreviewConfiguration: function getPreviewConfiguration(configuration, typographyVariant) {
84
- return _objectSpread2(_objectSpread2({}, configuration), {}, {
85
- textSize: 'small',
86
- typographyVariant: typographyVariant
87
- });
88
- }
45
+ getPreviewConfiguration: (configuration, typographyVariant) => ({
46
+ ...configuration,
47
+ textSize: 'small',
48
+ typographyVariant
49
+ })
50
+ });
51
+ this.input('textSize', SelectInputView, {
52
+ values: ['auto', 'large', 'medium', 'small']
89
53
  });
90
54
  this.group('PaletteColor', {
91
- entry: entry,
55
+ entry,
92
56
  model: modelDelegator,
93
57
  propertyName: 'color'
94
58
  });
@@ -98,15 +62,15 @@ editor.contentElementTypes.register('heading', {
98
62
  this.input('hyphens', SelectInputView, {
99
63
  values: ['auto', 'manual']
100
64
  });
101
-
102
65
  if (this.model.get('hyphens') === 'manual') {
103
66
  this.view(InfoBoxView, {
104
67
  text: I18n.t('pageflow_scrolled.editor.content_elements.heading.help_texts.shortcuts')
105
68
  });
106
69
  }
107
-
108
70
  this.view(SeparatorView);
109
- this.group('ContentElementPosition');
71
+ this.group('ContentElementPosition', {
72
+ entry
73
+ });
110
74
  });
111
75
  }
112
76
  });
@@ -116,84 +80,176 @@ var img$1 = "data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBo
116
80
  editor.contentElementTypes.register('textBlock', {
117
81
  pictogram: img$1,
118
82
  supportedPositions: ['inline'],
119
- configurationEditor: function configurationEditor(_ref) {
120
- var _this = this;
121
-
122
- var entry = _ref.entry,
123
- contentElement = _ref.contentElement;
124
- this.listenTo(contentElement.transientState, 'change:exampleNode', function () {
125
- return _this.refresh();
83
+ configurationEditor({
84
+ entry,
85
+ contentElement
86
+ }) {
87
+ var _contentElement$trans;
88
+ let lastExampleNodeType = (_contentElement$trans = contentElement.transientState.get('exampleNode')) === null || _contentElement$trans === void 0 ? void 0 : _contentElement$trans.type;
89
+ this.listenTo(contentElement.transientState, 'change:exampleNode', () => {
90
+ var _contentElement$trans2;
91
+ const exampleNodeType = (_contentElement$trans2 = contentElement.transientState.get('exampleNode')) === null || _contentElement$trans2 === void 0 ? void 0 : _contentElement$trans2.type;
92
+ if (exampleNodeType !== lastExampleNodeType) {
93
+ lastExampleNodeType = exampleNodeType;
94
+ this.refresh();
95
+ }
126
96
  });
127
97
  this.tab('general', function () {
128
- var exampleNode = ensureTextContent(contentElement.transientState.get('exampleNode'));
129
- var modelDelegator = entry.createLegacyTypographyVariantDelegator({
98
+ const exampleNode = contentElement.transientState.get('exampleNode');
99
+ const modelDelegator = entry.createLegacyTypographyVariantDelegator({
130
100
  model: contentElement.transientState,
131
101
  paletteColorPropertyName: 'color'
132
102
  });
103
+ const getPreviewConfiguration = (configuration, properties) => {
104
+ const currentExampleNode = ensureTextContent(contentElement.transientState.get('exampleNode'));
105
+ return currentExampleNode ? {
106
+ ...configuration,
107
+ value: [{
108
+ ...currentExampleNode,
109
+ // Ensure size in preview is not overridden by legacy variant
110
+ variant: modelDelegator.get('typographyVariant'),
111
+ ...properties
112
+ },
113
+ // Ensure content spans whole preview viewport if
114
+ // section uses "cards" appearance.
115
+ {
116
+ type: 'paragraph',
117
+ children: [{
118
+ text: ''
119
+ }]
120
+ }, {
121
+ type: 'paragraph',
122
+ children: [{
123
+ text: ''
124
+ }]
125
+ }]
126
+ } : configuration;
127
+ };
133
128
  this.group('ContentElementTypographyVariant', {
134
- entry: entry,
129
+ entry,
135
130
  model: modelDelegator,
136
131
  prefix: exampleNode ? utils.camelize(exampleNode.type) : 'none',
137
- getPreviewConfiguration: function getPreviewConfiguration(configuration, variant) {
138
- return exampleNode ? _objectSpread2(_objectSpread2({}, configuration), {}, {
139
- value: [_objectSpread2(_objectSpread2({}, exampleNode), {}, {
140
- variant: variant
141
- }), // Ensure content spans whole preview viewport if
142
- // section uses "cards" appearance.
143
- {
144
- type: 'paragraph',
145
- children: [{
146
- text: ''
147
- }]
148
- }, {
149
- type: 'paragraph',
150
- children: [{
151
- text: ''
152
- }]
153
- }]
154
- }) : configuration;
132
+ previewConfigurationBindingModel: contentElement.transientState,
133
+ previewConfigurationBinding: 'exampleNode',
134
+ getPreviewConfiguration(configuration, variant) {
135
+ return getPreviewConfiguration(configuration, {
136
+ variant
137
+ });
138
+ }
139
+ });
140
+ this.group('ContentElementTypographySize', {
141
+ entry,
142
+ model: modelDelegator,
143
+ prefix: exampleNode ? utils.camelize(exampleNode.type) : 'none',
144
+ previewConfigurationBindingModel: contentElement.transientState,
145
+ previewConfigurationBinding: 'exampleNode',
146
+ getPreviewConfiguration(configuration, size) {
147
+ return getPreviewConfiguration(configuration, {
148
+ size
149
+ });
155
150
  }
156
151
  });
157
152
  this.group('PaletteColor', {
158
- entry: entry,
153
+ entry,
159
154
  model: modelDelegator,
160
155
  propertyName: 'color'
161
156
  });
157
+ this.input('textAlign', SelectInputView, {
158
+ model: contentElement.transientState,
159
+ values: ['ragged', 'justify']
160
+ });
162
161
  this.view(SeparatorView);
163
162
  this.view(InfoBoxView, {
164
163
  text: I18n.t('pageflow_scrolled.editor.content_elements.textBlock.help_texts.shortcuts')
165
164
  });
166
165
  });
167
166
  },
168
- split: function split(configuration, insertIndex) {
169
- var value = getValue(configuration);
170
- return [_objectSpread2(_objectSpread2({}, configuration), {}, {
171
- value: value.slice(0, insertIndex)
172
- }), _objectSpread2(_objectSpread2({}, configuration), {}, {
173
- value: value.slice(insertIndex)
174
- })];
167
+ split(configuration, at, {
168
+ ranges
169
+ }) {
170
+ const value = getValue(configuration);
171
+ const beforeValue = value.slice(0, at);
172
+ const afterValue = value.slice(at);
173
+ const beforeRanges = {};
174
+ const afterRanges = {};
175
+ Object.entries(ranges).forEach(([id, range]) => {
176
+ const startPath = Math.min(range.anchor.path[0], range.focus.path[0]);
177
+ const endPath = Math.max(range.anchor.path[0], range.focus.path[0]);
178
+ if (endPath < at) {
179
+ beforeRanges[id] = range;
180
+ } else if (startPath >= at) {
181
+ afterRanges[id] = shiftRange(range, -at);
182
+ } else {
183
+ const start = Point.isBefore(range.anchor, range.focus) ? range.anchor : range.focus;
184
+ beforeRanges[id] = {
185
+ anchor: start,
186
+ focus: endOfBlock(beforeValue, at - 1)
187
+ };
188
+ }
189
+ });
190
+ return {
191
+ before: {
192
+ configuration: {
193
+ ...configuration,
194
+ value: beforeValue
195
+ },
196
+ ranges: beforeRanges
197
+ },
198
+ after: {
199
+ configuration: {
200
+ ...configuration,
201
+ value: afterValue
202
+ },
203
+ ranges: afterRanges
204
+ }
205
+ };
175
206
  },
176
- merge: function merge(configurationA, configurationB) {
177
- var value = getValue(configurationA).concat(getValue(configurationB));
178
- return _objectSpread2(_objectSpread2({}, configurationA), {}, {
179
- value: value
207
+ merge(configurationA, configurationB, {
208
+ rangesA,
209
+ rangesB
210
+ }) {
211
+ const valueA = getValue(configurationA);
212
+ const valueB = getValue(configurationB);
213
+ const ranges = {
214
+ ...rangesA
215
+ };
216
+ Object.entries(rangesB).forEach(([id, range]) => {
217
+ ranges[id] = shiftRange(range, valueA.length);
180
218
  });
219
+ return {
220
+ configuration: {
221
+ ...configurationA,
222
+ value: valueA.concat(valueB)
223
+ },
224
+ ranges
225
+ };
181
226
  },
182
- getLength: function getLength(configuration) {
227
+ getLength(configuration) {
183
228
  return getValue(configuration).length;
184
229
  },
185
- handleDestroy: function handleDestroy(contentElement) {
186
- var transientState = contentElement.get('transientState') || {};
187
-
230
+ handleDestroy(contentElement) {
231
+ const transientState = contentElement.get('transientState') || {};
188
232
  if (!transientState.editableTextIsSingleBlock) {
189
233
  contentElement.postCommand({
190
234
  type: 'REMOVE'
191
235
  });
192
236
  return false;
193
237
  }
238
+ },
239
+ handleDuplicate(contentElement) {
240
+ contentElement.postCommand({
241
+ type: 'DUPLICATE'
242
+ });
243
+ },
244
+ handleMove(contentElement, to) {
245
+ contentElement.postCommand({
246
+ type: 'MOVE_TO',
247
+ payload: {
248
+ to
249
+ }
250
+ });
194
251
  }
195
252
  });
196
-
197
253
  function getValue(configuration) {
198
254
  // Value might still be empty if text block has not been edited
199
255
  return configuration.value || [{
@@ -203,14 +259,35 @@ function getValue(configuration) {
203
259
  }]
204
260
  }];
205
261
  }
206
-
262
+ function shiftRange(range, delta) {
263
+ return {
264
+ anchor: shiftPoint(range.anchor, delta),
265
+ focus: shiftPoint(range.focus, delta)
266
+ };
267
+ }
268
+ function shiftPoint(point, delta) {
269
+ return {
270
+ ...point,
271
+ path: [point.path[0] + delta, ...point.path.slice(1)]
272
+ };
273
+ }
274
+ function endOfBlock(value, blockIndex) {
275
+ const [lastNode, lastPath] = Node.last({
276
+ children: value
277
+ }, [blockIndex]);
278
+ return {
279
+ path: lastPath,
280
+ offset: lastNode.text.length
281
+ };
282
+ }
207
283
  function ensureTextContent(node) {
208
284
  if (node && node.children.length === 1 && node.children[0].text === '') {
209
- return _objectSpread2(_objectSpread2({}, node), {}, {
285
+ return {
286
+ ...node,
210
287
  children: [{
211
288
  text: 'Lorem ipsum dolor sit amet'
212
289
  }]
213
- });
290
+ };
214
291
  } else {
215
292
  return node;
216
293
  }
@@ -221,110 +298,133 @@ var img$2 = "data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBo
221
298
  editor.contentElementTypes.register('inlineImage', {
222
299
  pictogram: img$2,
223
300
  category: 'media',
224
- supportedPositions: ['inline', 'sticky', 'standAlone', 'left', 'right'],
301
+ supportedPositions: ['inline', 'side', 'sticky', 'standAlone', 'left', 'right'],
225
302
  supportedWidthRange: ['xxs', 'full'],
226
- configurationEditor: function configurationEditor(_ref) {
227
- var contentElement = _ref.contentElement;
303
+ supportedCaptions: true,
304
+ supportedStyles: ['boxShadow', 'outline'],
305
+ defaultsInputs() {
306
+ this.input('enableFullscreen', CheckBoxInputView);
307
+ },
308
+ configurationEditor({
309
+ entry,
310
+ contentElement
311
+ }) {
228
312
  this.tab('general', function () {
229
313
  this.input('id', FileInputView, {
230
314
  collection: 'image_files',
231
315
  fileSelectionHandler: 'contentElementConfiguration',
232
- positioning: false,
316
+ positioning: imageModifiers => !!processImageModifiers(imageModifiers).aspectRatio,
317
+ positioningBinding: 'imageModifiers',
318
+ positioningOptions: () => {
319
+ const {
320
+ aspectRatio
321
+ } = processImageModifiers(this.model.get('imageModifiers'));
322
+ return {
323
+ preview: aspectRatio && 1 / entry.getAspectRatio(aspectRatio)
324
+ };
325
+ },
233
326
  dropDownMenuItems: [InlineFileRightsMenuItem]
234
327
  });
328
+ this.input('imageModifiers', ImageModifierListInputView, {
329
+ entry,
330
+ visibleBinding: 'id',
331
+ visible: () => this.model.getReference('id', 'image_files')
332
+ });
235
333
  this.input('portraitId', FileInputView, {
236
334
  collection: 'image_files',
237
335
  fileSelectionHandler: 'contentElementConfiguration',
238
- positioning: false
336
+ positioning: imageModifiers => !!processImageModifiers(imageModifiers).aspectRatio,
337
+ positioningBinding: 'portraitImageModifiers',
338
+ positioningOptions: () => {
339
+ const {
340
+ aspectRatio
341
+ } = processImageModifiers(this.model.get('portraitImageModifiers'));
342
+ return {
343
+ preview: aspectRatio && 1 / entry.getAspectRatio(aspectRatio)
344
+ };
345
+ }
346
+ });
347
+ this.input('portraitImageModifiers', ImageModifierListInputView, {
348
+ entry,
349
+ visibleBinding: 'portraitId',
350
+ visible: () => this.model.getReference('portraitId', 'image_files')
239
351
  });
240
352
  this.input('enableFullscreen', CheckBoxInputView, {
241
353
  disabledBinding: ['position', 'width'],
242
- disabled: function disabled() {
243
- return contentElement.getWidth() === contentElementWidths.full;
244
- },
354
+ disabled: () => contentElement.getWidth() === contentElementWidths.full,
245
355
  displayUncheckedIfDisabled: true
246
356
  });
247
- this.group('ContentElementPosition');
357
+ this.group('ContentElementPosition', {
358
+ entry
359
+ });
360
+ this.view(SeparatorView);
361
+ this.group('ContentElementCaption', {
362
+ entry
363
+ });
364
+ this.group('ContentElementInlineFileRightsSettings');
248
365
  });
249
366
  }
250
367
  });
251
368
 
252
- function _arrayWithHoles(arr) {
253
- if (Array.isArray(arr)) return arr;
254
- }
255
-
256
- function _iterableToArrayLimit(arr, i) {
257
- if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return;
258
- var _arr = [];
259
- var _n = true;
260
- var _d = false;
261
- var _e = undefined;
262
-
263
- try {
264
- for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
265
- _arr.push(_s.value);
266
-
267
- if (i && _arr.length === i) break;
268
- }
269
- } catch (err) {
270
- _d = true;
271
- _e = err;
272
- } finally {
273
- try {
274
- if (!_n && _i["return"] != null) _i["return"]();
275
- } finally {
276
- if (_d) throw _e;
277
- }
278
- }
279
-
280
- return _arr;
281
- }
282
-
283
- function _arrayLikeToArray(arr, len) {
284
- if (len == null || len > arr.length) len = arr.length;
285
-
286
- for (var i = 0, arr2 = new Array(len); i < len; i++) {
287
- arr2[i] = arr[i];
288
- }
289
-
290
- return arr2;
291
- }
292
-
293
- function _unsupportedIterableToArray(o, minLen) {
294
- if (!o) return;
295
- if (typeof o === "string") return _arrayLikeToArray(o, minLen);
296
- var n = Object.prototype.toString.call(o).slice(8, -1);
297
- if (n === "Object" && o.constructor) n = o.constructor.name;
298
- if (n === "Map" || n === "Set") return Array.from(n);
299
- if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
300
- }
301
-
302
- function _nonIterableRest() {
303
- throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
304
- }
305
-
306
- function _slicedToArray(arr, i) {
307
- return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
308
- }
309
-
310
369
  var img$3 = "data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3c!--! Font Awesome Pro 6.1.1 by %40fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons%2c Inc. --%3e%3cpath fill='white' d='M463.1 32h-416C21.49 32-.0001 53.49-.0001 80v352c0 26.51 21.49 48 47.1 48h416c26.51 0 48-21.49 48-48v-352C511.1 53.49 490.5 32 463.1 32zM111.1 408c0 4.418-3.582 8-8 8H55.1c-4.418 0-8-3.582-8-8v-48c0-4.418 3.582-8 8-8h47.1c4.418 0 8 3.582 8 8L111.1 408zM111.1 280c0 4.418-3.582 8-8 8H55.1c-4.418 0-8-3.582-8-8v-48c0-4.418 3.582-8 8-8h47.1c4.418 0 8 3.582 8 8V280zM111.1 152c0 4.418-3.582 8-8 8H55.1c-4.418 0-8-3.582-8-8v-48c0-4.418 3.582-8 8-8h47.1c4.418 0 8 3.582 8 8L111.1 152zM351.1 400c0 8.836-7.164 16-16 16H175.1c-8.836 0-16-7.164-16-16v-96c0-8.838 7.164-16 16-16h160c8.836 0 16 7.162 16 16V400zM351.1 208c0 8.836-7.164 16-16 16H175.1c-8.836 0-16-7.164-16-16v-96c0-8.838 7.164-16 16-16h160c8.836 0 16 7.162 16 16V208zM463.1 408c0 4.418-3.582 8-8 8h-47.1c-4.418 0-7.1-3.582-7.1-8l0-48c0-4.418 3.582-8 8-8h47.1c4.418 0 8 3.582 8 8V408zM463.1 280c0 4.418-3.582 8-8 8h-47.1c-4.418 0-8-3.582-8-8v-48c0-4.418 3.582-8 8-8h47.1c4.418 0 8 3.582 8 8V280zM463.1 152c0 4.418-3.582 8-8 8h-47.1c-4.418 0-8-3.582-8-8l0-48c0-4.418 3.582-8 7.1-8h47.1c4.418 0 8 3.582 8 8V152z'/%3e%3c/svg%3e";
311
370
 
371
+ const EditMotifAreaMenuItem = Backbone.Model.extend({
372
+ defaults: {
373
+ name: 'editMotifArea'
374
+ },
375
+ initialize(attributes, {
376
+ inputModel,
377
+ propertyName,
378
+ file
379
+ }) {
380
+ this.set('label', I18n.t('pageflow_scrolled.editor.edit_motif_area_menu_item'));
381
+ const update = () => {
382
+ this.set('hidden', inputModel.get('position') !== 'backdrop');
383
+ };
384
+ this.listenTo(inputModel, `change:position`, update);
385
+ update();
386
+ this.selected = () => {
387
+ EditMotifAreaDialogView.show({
388
+ model: inputModel,
389
+ propertyName,
390
+ file
391
+ });
392
+ };
393
+ }
394
+ });
312
395
  editor.contentElementTypes.register('inlineVideo', {
313
396
  pictogram: img$3,
314
397
  category: 'media',
315
- supportedPositions: ['inline', 'sticky', 'standAlone', 'left', 'right'],
398
+ supportedPositions: ['inline', 'side', 'sticky', 'standAlone', 'left', 'right', 'backdrop'],
316
399
  supportedWidthRange: ['xxs', 'full'],
317
- configurationEditor: function configurationEditor() {
400
+ supportedCaptions: true,
401
+ supportedStyles: ['boxShadow', 'outline'],
402
+ defaultsInputs() {
403
+ this.input('playbackMode', SelectInputView, {
404
+ values: ['manual', 'autoplay', 'autoplayIfUnmuted', 'loop']
405
+ });
406
+ this.input('enableFullscreen', CheckBoxInputView$1);
407
+ },
408
+ configurationEditor({
409
+ entry
410
+ }) {
318
411
  migrateLegacyAutoplay(this.model);
319
412
  this.tab('general', function () {
320
- var _this = this;
321
-
322
413
  this.input('id', FileInputView, {
323
414
  collection: 'video_files',
324
415
  fileSelectionHandler: 'contentElementConfiguration',
325
- positioning: false,
416
+ positioning: imageModifiers => !!processImageModifiers(imageModifiers).aspectRatio,
417
+ positioningBinding: 'imageModifiers',
418
+ positioningOptions: () => {
419
+ const {
420
+ aspectRatio
421
+ } = processImageModifiers(this.model.get('imageModifiers'));
422
+ return {
423
+ preview: aspectRatio && 1 / entry.getAspectRatio(aspectRatio)
424
+ };
425
+ },
326
426
  defaultTextTrackFilePropertyName: 'defaultTextTrackFileId',
327
- dropDownMenuItems: [InlineFileRightsMenuItem]
427
+ dropDownMenuItems: [EditMotifAreaMenuItem, InlineFileRightsMenuItem]
328
428
  });
329
429
  this.input('posterId', FileInputView, {
330
430
  collection: 'image_files',
@@ -332,47 +432,56 @@ editor.contentElementTypes.register('inlineVideo', {
332
432
  positioning: false,
333
433
  dropDownMenuItems: [InlineFileRightsMenuItem]
334
434
  });
435
+ this.input('imageModifiers', ImageModifierListInputView, {
436
+ entry,
437
+ visibleBinding: 'id',
438
+ visible: () => this.model.getReference('id', 'video_files')
439
+ });
335
440
  this.input('portraitId', FileInputView, {
336
441
  collection: 'video_files',
337
442
  fileSelectionHandler: 'contentElementConfiguration',
338
- positioning: false,
443
+ positioning: imageModifiers => !!processImageModifiers(imageModifiers).aspectRatio,
444
+ positioningBinding: 'portraitImageModifiers',
445
+ positioningOptions: () => {
446
+ const {
447
+ aspectRatio
448
+ } = processImageModifiers(this.model.get('portraitImageModifiers'));
449
+ return {
450
+ preview: aspectRatio && 1 / entry.getAspectRatio(aspectRatio)
451
+ };
452
+ },
339
453
  defaultTextTrackFilePropertyName: 'defaultTextTrackFileId',
340
- dropDownMenuItems: [InlineFileRightsMenuItem]
454
+ dropDownMenuItems: [EditMotifAreaMenuItem, InlineFileRightsMenuItem]
341
455
  });
342
456
  this.input('portraitPosterId', FileInputView, {
343
457
  collection: 'image_files',
344
458
  fileSelectionHandler: 'contentElementConfiguration',
345
459
  positioning: false,
346
460
  visibleBinding: 'portraitId',
347
- visible: function visible() {
348
- return _this.model.getReference('portraitId', 'video_files');
349
- },
461
+ visible: () => this.model.getReference('portraitId', 'video_files'),
350
462
  dropDownMenuItems: [InlineFileRightsMenuItem]
351
463
  });
464
+ this.input('portraitImageModifiers', ImageModifierListInputView, {
465
+ entry,
466
+ visibleBinding: 'portraitId',
467
+ visible: () => this.model.getReference('portraitId', 'video_files')
468
+ });
352
469
  this.view(SeparatorView);
353
470
  this.input('playbackMode', SelectInputView, {
354
- values: ['manual', 'autoplay', 'loop']
471
+ values: ['manual', 'autoplay', 'autoplayIfUnmuted', 'loop']
355
472
  });
356
- this.input('hideControlBar', CheckBoxInputView, {
357
- disabledBinding: 'playbackMode',
358
- disabled: function disabled(playbackMode) {
359
- return playbackMode === 'loop';
360
- },
473
+ this.input('hideControlBar', CheckBoxInputView$1, {
474
+ disabledBinding: ['playbackMode', 'imageModifiers'],
475
+ disabled: ([playbackMode, imageModifiers]) => playbackMode === 'loop' || processImageModifiers(imageModifiers).rounded === 'circle',
361
476
  displayCheckedIfDisabled: true
362
477
  });
363
478
  this.input('unmuteLabel', LabelOnlyView);
364
- this.input('unmute', CheckBoxInputView, {
479
+ this.input('unmute', CheckBoxInputView$1, {
365
480
  storeInverted: 'keepMuted'
366
481
  });
367
- this.input('rewindOnUnmute', CheckBoxInputView, {
482
+ this.input('rewindOnUnmute', CheckBoxInputView$1, {
368
483
  disabledBinding: ['playbackMode', 'keepMuted'],
369
- disabled: function disabled(_ref) {
370
- var _ref2 = _slicedToArray(_ref, 2),
371
- playbackMode = _ref2[0],
372
- keepMuted = _ref2[1];
373
-
374
- return playbackMode !== 'autoplay' || keepMuted;
375
- },
484
+ disabled: ([playbackMode, keepMuted]) => playbackMode !== 'autoplay' || keepMuted,
376
485
  displayUncheckedIfDisabled: true
377
486
  });
378
487
  this.view(SeparatorView);
@@ -380,11 +489,22 @@ editor.contentElementTypes.register('inlineVideo', {
380
489
  values: ['play', 'mute', 'turnDown']
381
490
  });
382
491
  this.view(SeparatorView);
383
- this.group('ContentElementPosition');
492
+ this.input('enableFullscreen', CheckBoxInputView$1, {
493
+ disabledBinding: ['position', 'playbackMode'],
494
+ disabled: ([position, playbackMode]) => position === 'backdrop' || playbackMode === 'loop',
495
+ displayUncheckedIfDisabled: true
496
+ });
497
+ this.group('ContentElementPosition', {
498
+ entry
499
+ });
500
+ this.view(SeparatorView);
501
+ this.group('ContentElementCaption', {
502
+ entry
503
+ });
504
+ this.group('ContentElementInlineFileRightsSettings');
384
505
  });
385
506
  }
386
507
  });
387
-
388
508
  function migrateLegacyAutoplay(model) {
389
509
  if (!model.has('playbackMode') && model.get('autoplay')) {
390
510
  model.set('playbackMode', 'autoplay', {
@@ -393,19 +513,45 @@ function migrateLegacyAutoplay(model) {
393
513
  }
394
514
  }
395
515
 
516
+ const defaultRemainingWaveformColor = '#828282ed';
517
+ const defaultRemainingWaveformColorInverted = 'rgba(0, 0, 0, 0.5)';
518
+ const defaultWaveformCursorColor = '#fff';
519
+ const defaultWaveformCursorColorInverted = '#888';
520
+
396
521
  var img$4 = "data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 384 512'%3e%3c!--! Font Awesome Pro 6.1.1 by %40fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons%2c Inc. --%3e%3cpath fill='white' d='M192 352c53.03 0 96-42.97 96-96v-160c0-53.03-42.97-96-96-96s-96 42.97-96 96v160C96 309 138.1 352 192 352zM344 192C330.7 192 320 202.7 320 215.1V256c0 73.33-61.97 132.4-136.3 127.7c-66.08-4.169-119.7-66.59-119.7-132.8L64 215.1C64 202.7 53.25 192 40 192S16 202.7 16 215.1v32.15c0 89.66 63.97 169.6 152 181.7V464H128c-18.19 0-32.84 15.18-31.96 33.57C96.43 505.8 103.8 512 112 512h160c8.222 0 15.57-6.216 15.96-14.43C288.8 479.2 274.2 464 256 464h-40v-33.77C301.7 418.5 368 344.9 368 256V215.1C368 202.7 357.3 192 344 192z'/%3e%3c/svg%3e";
397
522
 
398
523
  editor.contentElementTypes.register('inlineAudio', {
399
524
  pictogram: img$4,
400
525
  category: 'media',
401
- supportedPositions: ['inline', 'sticky', 'standAlone', 'left', 'right'],
526
+ supportedPositions: ['inline', 'side', 'sticky', 'standAlone', 'left', 'right'],
402
527
  supportedWidthRange: ['xxs', 'full'],
528
+ supportedCaptions: true,
529
+ supportedStyles: [{
530
+ name: 'boxShadow',
531
+ when: posterId => !!posterId,
532
+ binding: 'posterId'
533
+ }, {
534
+ name: 'outline',
535
+ when: posterId => !!posterId,
536
+ binding: 'posterId'
537
+ }],
403
538
  defaultConfig: {
404
539
  playerControlVariant: 'waveformBars'
405
540
  },
406
- configurationEditor: function configurationEditor(_ref) {
407
- var entry = _ref.entry;
541
+ defaultsInputs() {
542
+ this.input('autoplay', CheckBoxInputView$1);
543
+ this.input('playerControlVariant', SelectInputView, {
544
+ values: ['waveformBars', 'waveformLines', 'waveform', 'classic']
545
+ });
546
+ },
547
+ configurationEditor({
548
+ entry,
549
+ contentElement
550
+ }) {
551
+ const themeProperties = entry.getThemeProperties();
552
+ const invert = contentElement.section.configuration.get('invert');
408
553
  this.tab('general', function () {
554
+ var _themeProperties$root, _themeProperties$colo;
409
555
  this.input('id', FileInputView, {
410
556
  collection: 'audio_files',
411
557
  fileSelectionHandler: 'contentElementConfiguration',
@@ -420,7 +566,7 @@ editor.contentElementTypes.register('inlineAudio', {
420
566
  dropDownMenuItems: [InlineFileRightsMenuItem]
421
567
  });
422
568
  this.view(SeparatorView);
423
- this.input('autoplay', CheckBoxInputView);
569
+ this.input('autoplay', CheckBoxInputView$1);
424
570
  this.input('atmoDuringPlayback', SelectInputView, {
425
571
  values: ['play', 'mute', 'turnDown']
426
572
  });
@@ -430,14 +576,41 @@ editor.contentElementTypes.register('inlineAudio', {
430
576
  ensureValueDefined: true
431
577
  });
432
578
  this.input('waveformColor', ColorInputView, {
579
+ alpha: true,
433
580
  visibleBinding: 'playerControlVariant',
434
- visible: function visible(variant) {
435
- return variant === null || variant === void 0 ? void 0 : variant.startsWith('waveform');
436
- },
437
- defaultValue: entry.getTheme().get('options').colors.accent
581
+ visible: variant => variant === null || variant === void 0 ? void 0 : variant.startsWith('waveform'),
582
+ defaultValue: ((_themeProperties$root = themeProperties.root) === null || _themeProperties$root === void 0 ? void 0 : _themeProperties$root.accentColor) || ((_themeProperties$colo = themeProperties.colors) === null || _themeProperties$colo === void 0 ? void 0 : _themeProperties$colo.accent),
583
+ swatches: entry.getUsedContentElementColors('waveformColor')
584
+ });
585
+ this.input('remainingWaveformColor', ColorInputView, {
586
+ alpha: true,
587
+ visibleBinding: 'playerControlVariant',
588
+ visible: variant => variant === null || variant === void 0 ? void 0 : variant.startsWith('waveform'),
589
+ placeholder: I18n.t('pageflow_scrolled.editor.content_elements.inlineAudio.attributes.remainingWaveformColor.auto'),
590
+ placeholderColor: invert ? defaultRemainingWaveformColorInverted : defaultRemainingWaveformColor,
591
+ swatches: entry.getUsedContentElementColors('remainingWaveformColor')
592
+ });
593
+ this.input('waveformCursorColor', ColorInputView, {
594
+ alpha: true,
595
+ visibleBinding: 'playerControlVariant',
596
+ visible: variant => variant === null || variant === void 0 ? void 0 : variant.startsWith('waveform'),
597
+ placeholder: I18n.t('pageflow_scrolled.editor.content_elements.inlineAudio.attributes.waveformCursorColor.auto'),
598
+ placeholderColor: invert ? defaultWaveformCursorColorInverted : defaultWaveformCursorColor,
599
+ swatches: entry.getUsedContentElementColors('waveformCursorColor')
600
+ });
601
+ this.input('invertPlayButton', CheckBoxInputView$1, {
602
+ visibleBinding: 'playerControlVariant',
603
+ visible: variant => variant === null || variant === void 0 ? void 0 : variant.startsWith('waveform')
438
604
  });
439
605
  this.view(SeparatorView);
440
- this.group('ContentElementPosition');
606
+ this.group('ContentElementPosition', {
607
+ entry
608
+ });
609
+ this.view(SeparatorView);
610
+ this.group('ContentElementCaption', {
611
+ entry
612
+ });
613
+ this.group('ContentElementInlineFileRightsSettings');
441
614
  });
442
615
  }
443
616
  });
@@ -447,9 +620,13 @@ var img$5 = "data:image/svg+xml,%3c%3fxml version='1.0' encoding='utf-8'%3f%3e%3
447
620
  editor.contentElementTypes.register('videoEmbed', {
448
621
  pictogram: img$5,
449
622
  category: 'media',
450
- supportedPositions: ['inline', 'sticky', 'standAlone', 'left', 'right'],
623
+ supportedPositions: ['inline', 'side', 'sticky', 'standAlone', 'left', 'right'],
451
624
  supportedWidthRange: ['xxs', 'full'],
452
- configurationEditor: function configurationEditor() {
625
+ supportedCaptions: true,
626
+ supportedStyles: ['boxShadow', 'outline'],
627
+ configurationEditor({
628
+ entry
629
+ }) {
453
630
  this.tab('general', function () {
454
631
  this.input('videoSource', UrlInputView, {
455
632
  supportedHosts: ['http://youtu.be', 'https://youtu.be', 'http://www.youtube.com', 'https://www.youtube.com', 'http://vimeo.com', 'https://vimeo.com', 'http://www.facebook.com', 'https://www.facebook.com'],
@@ -462,8 +639,8 @@ editor.contentElementTypes.register('videoEmbed', {
462
639
  fileSelectionHandler: 'contentElementConfiguration',
463
640
  positioning: false
464
641
  });
465
- this.input('hideInfo', CheckBoxInputView$1);
466
- this.input('hideControls', CheckBoxInputView$1);
642
+ this.input('hideInfo', CheckBoxInputView);
643
+ this.input('hideControls', CheckBoxInputView);
467
644
  this.input('aspectRatio', SelectInputView, {
468
645
  values: ['wide', 'narrow', 'square', 'portrait']
469
646
  });
@@ -472,7 +649,13 @@ editor.contentElementTypes.register('videoEmbed', {
472
649
  values: ['play', 'mute', 'turnDown']
473
650
  });
474
651
  this.view(SeparatorView);
475
- this.group('ContentElementPosition');
652
+ this.group('ContentElementPosition', {
653
+ entry
654
+ });
655
+ this.view(SeparatorView);
656
+ this.group('ContentElementCaption', {
657
+ entry
658
+ });
476
659
  });
477
660
  }
478
661
  });
@@ -483,17 +666,31 @@ editor.contentElementTypes.register('soundDisclaimer', {
483
666
  pictogram: img$6,
484
667
  category: 'media',
485
668
  supportedPositions: ['inline'],
486
- configurationEditor: function configurationEditor() {
669
+ configurationEditor({
670
+ entry
671
+ }) {
487
672
  this.tab('general', function () {
488
- this.view(NoOptionsHintView);
673
+ this.input('mutedText', TextInputView, {
674
+ placeholder: I18n.t('pageflow_scrolled.public.sound_disclaimer.help_muted', {
675
+ locale: entry.metadata.get('locale')
676
+ })
677
+ });
678
+ this.input('unmutedText', TextInputView, {
679
+ placeholder: I18n.t('pageflow_scrolled.public.sound_disclaimer.help_unmuted', {
680
+ locale: entry.metadata.get('locale')
681
+ })
682
+ });
489
683
  });
490
684
  }
491
685
  });
492
686
 
493
- var DatawrapperAdView = Marionette.ItemView.extend({
494
- template: function template(data) {
495
- return "\n <form action=\"https://datawrapper.de/chart/create\" method=\"POST\" target=\"_blank\">\n <input type=\"hidden\" name=\"theme\" value=\"pageflow\" />\n <input type=\"submit\" value=\"".concat(I18n.t('pageflow_scrolled.editor.content_elements.dataWrapperChart.attributes.create_chart.label'), "\" />\n </form>\n ");
496
- },
687
+ const DatawrapperAdView = Marionette.ItemView.extend({
688
+ template: data => `
689
+ <form action="https://app.datawrapper.de/create/chart" method="GET" target="_blank">
690
+ <input type="hidden" name="theme" value="pageflow" />
691
+ <input type="submit" value="${I18n.t('pageflow_scrolled.editor.content_elements.dataWrapperChart.attributes.create_chart.label')}" />
692
+ </form>
693
+ `,
497
694
  className: 'datawrapper_ad'
498
695
  });
499
696
 
@@ -502,9 +699,13 @@ var img$7 = "data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBo
502
699
  editor.contentElementTypes.register('dataWrapperChart', {
503
700
  category: 'data',
504
701
  pictogram: img$7,
505
- supportedPositions: ['inline', 'sticky', 'standAlone', 'left', 'right'],
702
+ supportedPositions: ['inline', 'side', 'sticky', 'standAlone', 'left', 'right'],
506
703
  supportedWidthRange: ['xxs', 'full'],
507
- configurationEditor: function configurationEditor() {
704
+ supportedCaptions: true,
705
+ supportedStyles: ['boxShadow', 'outline'],
706
+ configurationEditor({
707
+ entry
708
+ }) {
508
709
  this.tab('general', function () {
509
710
  this.input('url', UrlInputView, {
510
711
  supportedHosts: ['cf.datawrapper.de', 'charts.datawrapper.de', 'datawrapper.dwcdn.de', 'datawrapper.dwcdn.net'],
@@ -519,7 +720,13 @@ editor.contentElementTypes.register('dataWrapperChart', {
519
720
  this.input('backgroundColor', ColorInputView, {
520
721
  defaultValue: '#323d4d'
521
722
  });
522
- this.group('ContentElementPosition');
723
+ this.group('ContentElementPosition', {
724
+ entry
725
+ });
726
+ this.view(SeparatorView);
727
+ this.group('ContentElementCaption', {
728
+ entry
729
+ });
523
730
  });
524
731
  }
525
732
  });
@@ -529,9 +736,13 @@ var img$8 = "data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBo
529
736
  editor.contentElementTypes.register('inlineBeforeAfter', {
530
737
  pictogram: img$8,
531
738
  category: 'interactive',
532
- supportedPositions: ['inline', 'sticky', 'standAlone', 'left', 'right'],
739
+ supportedPositions: ['inline', 'side', 'sticky', 'standAlone', 'left', 'right', 'backdrop'],
533
740
  supportedWidthRange: ['xxs', 'full'],
534
- configurationEditor: function configurationEditor() {
741
+ supportedCaptions: true,
742
+ supportedStyles: ['boxShadow', 'outline'],
743
+ configurationEditor({
744
+ entry
745
+ }) {
535
746
  this.tab('general', function () {
536
747
  this.input('before_id', FileInputView, {
537
748
  collection: 'image_files',
@@ -549,7 +760,14 @@ editor.contentElementTypes.register('inlineBeforeAfter', {
549
760
  this.input('after_label', TextInputView);
550
761
  this.input('initial_slider_position', SliderInputView);
551
762
  this.input('slider_color', ColorInputView$1);
552
- this.group('ContentElementPosition');
763
+ this.group('ContentElementPosition', {
764
+ entry
765
+ });
766
+ this.view(SeparatorView);
767
+ this.group('ContentElementCaption', {
768
+ entry
769
+ });
770
+ this.group('ContentElementInlineFileRightsSettings');
553
771
  });
554
772
  },
555
773
  defaultConfig: {
@@ -557,142 +775,183 @@ editor.contentElementTypes.register('inlineBeforeAfter', {
557
775
  }
558
776
  });
559
777
 
560
- var SidebarRouter = Marionette.AppRouter.extend({
778
+ const SidebarRouter = Marionette.AppRouter.extend({
561
779
  appRoutes: {
562
780
  'scrolled/external_links/:id/:link_id': 'link'
563
781
  }
564
782
  });
565
783
 
566
- var SidebarEditLinkView = Marionette.Layout.extend({
567
- template: function template(data) {
568
- return "\n <a class=\"back\">".concat(I18n.t('pageflow_scrolled.editor.content_elements.externalLinkList.back'), "</a>\n <a class=\"destroy\">").concat(I18n.t('pageflow_scrolled.editor.content_elements.externalLinkList.destroy'), "</a>\n\n <div class='form_container'></div>\n ");
784
+ const SidebarEditLinkView = EditConfigurationView.extend({
785
+ translationKeyPrefix: 'pageflow_scrolled.editor.content_elements.externalLinkList',
786
+ containingCollection() {
787
+ return this.options.collection;
569
788
  },
570
- className: 'edit_external_link',
571
- regions: {
572
- formContainer: '.form_container'
789
+ getConfigurationModel() {
790
+ return this.model;
573
791
  },
574
- events: {
575
- 'click a.back': 'goBack',
576
- 'click a.destroy': 'destroyLink'
792
+ goBackPath() {
793
+ return `/scrolled/content_elements/${this.options.contentElement.get('id')}`;
577
794
  },
578
- initialize: function initialize(options) {},
579
- onRender: function onRender() {
580
- var configurationEditor = new ConfigurationEditorView({
581
- model: this.model,
582
- attributeTranslationKeyPrefixes: ['pageflow_scrolled.editor.content_elements.externalLinkList.attributes'],
583
- tabTranslationKeyPrefix: 'pageflow_scrolled.editor.content_elements.externalLinkList.tabs'
795
+ goBack() {
796
+ this.options.contentElement.postCommand({
797
+ type: 'SET_SELECTED_ITEM',
798
+ index: -1
584
799
  });
585
- var self = this;
800
+ EditConfigurationView.prototype.goBack.call(this);
801
+ },
802
+ getActionsMenuItems() {
803
+ return [new DestroyLinkMenuItem({}, {
804
+ collection: this.options.collection,
805
+ model: this.model
806
+ })];
807
+ },
808
+ configure(configurationEditor) {
809
+ const contentElement = this.options.contentElement;
810
+ const thumbnailAspectRatio = contentElement.configuration.get('thumbnailAspectRatio');
811
+ const previewAspectRatio = this.options.entry.getAspectRatio(thumbnailAspectRatio);
812
+ const thumbnailFit = contentElement.configuration.get('thumbnailFit');
586
813
  configurationEditor.tab('edit_link', function () {
587
- this.input('url', TextInputView, {
588
- required: true
589
- });
590
- this.input('open_in_new_tab', CheckBoxInputView$1);
591
814
  this.input('thumbnail', FileInputView, {
592
815
  collection: 'image_files',
593
816
  fileSelectionHandler: 'contentElement.externalLinks.link',
594
817
  fileSelectionHandlerOptions: {
595
- contentElementId: self.options.contentElement.get('id')
818
+ contentElementId: contentElement.get('id')
596
819
  },
597
- positioning: false
820
+ positioning: previewAspectRatio && thumbnailFit !== 'contain',
821
+ positioningOptions: {
822
+ preview: previewAspectRatio && 1 / previewAspectRatio
823
+ },
824
+ dropDownMenuItems: [InlineFileRightsMenuItem]
598
825
  });
599
- this.input('title', TextInputView, {
600
- required: true
826
+ this.input('thumbnailBackgroundColor', ColorInputView);
827
+ this.view(SeparatorView);
828
+ this.view(InfoBoxView, {
829
+ text: I18n.t('pageflow_scrolled.editor.content_elements.textBlock.help_texts.shortcuts')
601
830
  });
602
- this.input('description', TextInputView);
603
- });
604
- this.formContainer.show(configurationEditor);
605
- },
606
- goBack: function goBack() {
607
- editor$1.navigate("/scrolled/content_elements/".concat(this.options.contentElement.get('id')), {
608
- trigger: true
609
831
  });
610
- },
611
- destroyLink: function destroyLink() {
612
- if (window.confirm(I18n.t('pageflow_scrolled.editor.content_elements.externalLinkList.confirm_delete_link'))) {
613
- this.options.collection.remove(this.model);
614
- this.goBack();
615
- }
832
+ }
833
+ });
834
+ const DestroyLinkMenuItem = DestroyMenuItem.extend({
835
+ translationKeyPrefix: 'pageflow_scrolled.editor.content_elements.externalLinkList',
836
+ destroyModel() {
837
+ this.options.collection.remove(this.options.model);
616
838
  }
617
839
  });
618
840
 
619
- function _arrayWithoutHoles(arr) {
620
- if (Array.isArray(arr)) return _arrayLikeToArray(arr);
621
- }
622
-
623
- function _iterableToArray(iter) {
624
- if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter);
625
- }
626
-
627
- function _nonIterableSpread() {
628
- throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
629
- }
630
-
631
- function _toConsumableArray(arr) {
632
- return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
633
- }
634
-
635
- var ExternalLinkModel = Backbone.Model.extend({
841
+ const ExternalLinkModel = Backbone.Model.extend({
636
842
  modelName: 'ExternalLink',
637
843
  i18nKey: 'external_link',
638
844
  mixins: [transientReferences],
639
- thumbnailUrl: function thumbnailUrl() {
640
- var image = this.collection.entry.imageFiles.getByPermaId(this.get('thumbnail'));
641
- return image ? image.get('thumbnail_url') : '';
845
+ thumbnailFile: function () {
846
+ var _this$thumbnail;
847
+ return (_this$thumbnail = this.thumbnail()) === null || _this$thumbnail === void 0 ? void 0 : _this$thumbnail.thumbnailFile();
848
+ },
849
+ thumbnail: function () {
850
+ return this.collection.entry.getFileCollection('image_files').getByPermaId(this.get('thumbnail'));
851
+ },
852
+ title: function () {
853
+ const configuration = this.collection.contentElement.configuration;
854
+ if (configuration.get('textPosition') === 'none') {
855
+ var _this$thumbnail2;
856
+ return (_this$thumbnail2 = this.thumbnail()) === null || _this$thumbnail2 === void 0 ? void 0 : _this$thumbnail2.configuration.get('alt');
857
+ } else {
858
+ var _itemTexts$this$id, _itemTexts$this$id2, _itemTexts$this$id2$t, _itemTexts$this$id2$t2, _itemTexts$this$id2$t3;
859
+ const itemTexts = configuration.get('itemTexts');
860
+ return (itemTexts === null || itemTexts === void 0 ? void 0 : (_itemTexts$this$id = itemTexts[this.id]) === null || _itemTexts$this$id === void 0 ? void 0 : _itemTexts$this$id.title) ? itemTexts === null || itemTexts === void 0 ? void 0 : (_itemTexts$this$id2 = itemTexts[this.id]) === null || _itemTexts$this$id2 === void 0 ? void 0 : (_itemTexts$this$id2$t = _itemTexts$this$id2.title[0]) === null || _itemTexts$this$id2$t === void 0 ? void 0 : (_itemTexts$this$id2$t2 = _itemTexts$this$id2$t.children) === null || _itemTexts$this$id2$t2 === void 0 ? void 0 : (_itemTexts$this$id2$t3 = _itemTexts$this$id2$t2[0]) === null || _itemTexts$this$id2$t3 === void 0 ? void 0 : _itemTexts$this$id2$t3.text : this.get('title');
861
+ }
862
+ },
863
+ getFilePosition: function (attribute, coord) {
864
+ const cropPosition = this.get('thumbnailCropPosition');
865
+ return cropPosition ? cropPosition[coord] : 50;
866
+ },
867
+ setFilePosition: function (attribute, coord, value) {
868
+ this.set('thumbnailCropPosition', {
869
+ ...this.get('thumbnailCropPosition'),
870
+ [coord]: value
871
+ });
872
+ },
873
+ setFilePositions: function (attribute, x, y) {
874
+ this.set('thumbnailCropPosition', {
875
+ x,
876
+ y
877
+ });
878
+ },
879
+ highlight() {
880
+ this.collection.contentElement.postCommand({
881
+ type: 'HIGHLIGHT_ITEM',
882
+ index: this.collection.indexOf(this)
883
+ });
642
884
  },
643
- title: function title() {
644
- return this.get('title');
885
+ resetHighlight() {
886
+ this.collection.contentElement.postCommand({
887
+ type: 'RESET_ITEM_HIGHLIGHT'
888
+ });
645
889
  }
646
890
  });
647
891
 
648
- var ExternalLinkCollection = Backbone.Collection.extend({
892
+ const ExternalLinkCollection = Backbone.Collection.extend({
649
893
  model: ExternalLinkModel,
650
894
  comparator: 'position',
651
- initialize: function initialize(models, options) {
895
+ initialize: function (models, options) {
652
896
  this.entry = options.entry;
653
- this.configuration = options.configuration;
654
- this.listenTo(this, 'add remove sort change', this.updateConfiguration);
897
+ this.contentElement = options.contentElement;
898
+ this.listenTo(this, 'add sort change', this.updateConfiguration);
899
+ this.listenTo(this, 'remove', () => this.updateConfiguration({
900
+ prune: true
901
+ }));
655
902
  },
656
- modelId: function modelId(attrs) {
903
+ modelId: function (attrs) {
657
904
  return attrs.id;
658
905
  },
659
- updateConfiguration: function updateConfiguration() {
660
- this.configuration.set('links', this.toJSON());
906
+ updateConfiguration: function ({
907
+ prune
908
+ }) {
909
+ let updatedAttributes = {
910
+ links: this.toJSON()
911
+ };
912
+ if (prune) {
913
+ updatedAttributes = {
914
+ ...updatedAttributes,
915
+ ...this.getPrunedProperty('itemTexts'),
916
+ ...this.getPrunedProperty('itemLinks')
917
+ };
918
+ }
919
+ this.contentElement.configuration.set(updatedAttributes);
920
+ },
921
+ getPrunedProperty(propertyName) {
922
+ return {
923
+ [propertyName]: _.pick(this.contentElement.configuration.get(propertyName) || {}, ...this.pluck('id'))
924
+ };
661
925
  },
662
- addNewLink: function addNewLink() {
663
- var id = this.length ? Math.max.apply(Math, _toConsumableArray(this.pluck('id'))) + 1 : 1;
926
+ addNewLink() {
927
+ const id = this.length ? Math.max(...this.pluck('id')) + 1 : 1;
664
928
  this.add({
665
- id: id,
666
- title: '',
667
- url: '',
668
- thumbnail: '',
669
- description: '',
670
- open_in_new_tab: 1
929
+ id
671
930
  });
672
931
  return this.get(id);
673
932
  },
674
- saveOrder: function saveOrder() {}
933
+ saveOrder() {}
675
934
  });
676
-
677
935
  ExternalLinkCollection.forContentElement = function (contentElement, entry) {
678
936
  return new ExternalLinkCollection(contentElement.configuration.get('links') || [], {
679
- entry: entry,
680
- configuration: contentElement.configuration
937
+ entry,
938
+ contentElement
681
939
  });
682
940
  };
683
941
 
684
- var SidebarController = Marionette.Controller.extend({
685
- initialize: function initialize(options) {
942
+ const SidebarController = Marionette.Controller.extend({
943
+ initialize: function (options) {
686
944
  this.entry = options.entry;
687
945
  this.region = options.region;
688
946
  },
689
- link: function link(id, linkId) {
690
- var contentElement = this.entry.contentElements.get(id);
691
- var linksCollection = ExternalLinkCollection.forContentElement(contentElement, this.entry);
947
+ link: function (id, linkId) {
948
+ const contentElement = this.entry.contentElements.get(id);
949
+ const linksCollection = ExternalLinkCollection.forContentElement(contentElement, this.entry);
692
950
  this.region.show(new SidebarEditLinkView({
693
951
  model: linksCollection.get(linkId),
694
952
  collection: linksCollection,
695
- contentElement: contentElement
953
+ entry: this.entry,
954
+ contentElement
696
955
  }));
697
956
  }
698
957
  });
@@ -728,91 +987,1671 @@ var css = ".SidebarListView-module_linksContainer__HvWq- {\n}\n";
728
987
  var styles = {"linksContainer":"SidebarListView-module_linksContainer__HvWq-"};
729
988
  styleInject(css);
730
989
 
731
- var SidebarListView = Marionette.Layout.extend({
732
- template: function template(data) {
733
- return "\n <label>Links</label>\n <div class='".concat(styles.linksContainer, "'></div>\n <button class=\"").concat(buttonStyles.addButton, "\">\n ").concat(I18n.t('pageflow_scrolled.editor.content_elements.externalLinkList.add'), "\n </button>\n ");
734
- },
990
+ const SidebarListView = Marionette.Layout.extend({
991
+ template: data => `
992
+ <label>${I18n.t('pageflow_scrolled.editor.content_elements.externalLinkList.items')}</label>
993
+ <div class='${styles.linksContainer}'></div>
994
+ <button class="${buttonStyles.addButton}">
995
+ ${I18n.t('pageflow_scrolled.editor.content_elements.externalLinkList.add')}
996
+ </button>
997
+ `,
735
998
  regions: cssModulesUtils.ui(styles, 'linksContainer'),
736
999
  events: cssModulesUtils.events(buttonStyles, {
737
1000
  'click addButton': 'addElement'
738
1001
  }),
739
- onRender: function onRender() {
1002
+ onRender: function () {
1003
+ this.listenTo(this.options.contentElement.configuration, 'change:textPosition', this.renderListView);
1004
+ this.renderListView();
1005
+ },
1006
+ renderListView() {
740
1007
  this.linksContainer.show(new ListView({
741
1008
  collection: this.collection,
742
1009
  sortable: true,
1010
+ highlight: true,
743
1011
  onEdit: _.bind(this.onEdit, this),
744
1012
  onRemove: _.bind(this.onRemove, this)
745
1013
  }));
746
1014
  },
747
- addElement: function addElement() {
748
- var newModel = this.collection.addNewLink();
749
- this.onEdit(newModel);
1015
+ addElement: function () {
1016
+ this.collection.addNewLink();
750
1017
  },
751
- onEdit: function onEdit(linkModel) {
752
- editor.navigate("/scrolled/external_links/".concat(this.options.contentElement.id, "/").concat(linkModel.id), {
1018
+ onEdit: function (linkModel) {
1019
+ this.options.contentElement.postCommand({
1020
+ type: 'SET_SELECTED_ITEM',
1021
+ index: this.collection.indexOf(linkModel)
1022
+ });
1023
+ editor.navigate(`/scrolled/external_links/${this.options.contentElement.id}/${linkModel.id}`, {
753
1024
  trigger: true
754
1025
  });
755
1026
  },
756
- onRemove: function onRemove(linkModel) {
757
- if (window.confirm(I18n.t('pageflow_scrolled.editor.content_elements.externalLinkList.confirm_delete_link'))) {
1027
+ onRemove: function (linkModel) {
1028
+ if (window.confirm(I18n.t('pageflow_scrolled.editor.content_elements.externalLinkList.confirm_delete_item'))) {
758
1029
  this.collection.remove(linkModel);
759
1030
  }
760
1031
  }
761
1032
  });
762
1033
 
1034
+ const linkWidths = {
1035
+ xs: -2,
1036
+ sm: -1,
1037
+ md: 0,
1038
+ lg: 1,
1039
+ xl: 2,
1040
+ xxl: 3
1041
+ };
1042
+ function maxLinkWidth({
1043
+ layout,
1044
+ textPosition,
1045
+ width
1046
+ }) {
1047
+ width = width || contentElementWidths.md;
1048
+ if (layout === 'center' || layout === 'centerRagged') {
1049
+ if (textPosition === 'right') {
1050
+ return {
1051
+ [contentElementWidths.md]: linkWidths.md,
1052
+ [contentElementWidths.lg]: linkWidths.lg,
1053
+ [contentElementWidths.xl]: linkWidths.xl,
1054
+ [contentElementWidths.full]: linkWidths.xl
1055
+ }[width];
1056
+ } else {
1057
+ return {
1058
+ [contentElementWidths.md]: linkWidths.lg,
1059
+ [contentElementWidths.lg]: linkWidths.xl,
1060
+ [contentElementWidths.xl]: linkWidths.xxl,
1061
+ [contentElementWidths.full]: linkWidths.xxl
1062
+ }[width];
1063
+ }
1064
+ } else {
1065
+ if (textPosition === 'right') {
1066
+ return {
1067
+ [contentElementWidths.md]: linkWidths.sm,
1068
+ [contentElementWidths.lg]: linkWidths.md,
1069
+ [contentElementWidths.xl]: linkWidths.xl,
1070
+ [contentElementWidths.full]: linkWidths.xl
1071
+ }[width];
1072
+ } else {
1073
+ return {
1074
+ [contentElementWidths.md]: linkWidths.lg,
1075
+ [contentElementWidths.lg]: linkWidths.lg,
1076
+ [contentElementWidths.xl]: linkWidths.xxl,
1077
+ [contentElementWidths.full]: linkWidths.xxl
1078
+ }[width];
1079
+ }
1080
+ }
1081
+ }
1082
+
763
1083
  var img$9 = "data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512'%3e%3c!--! Font Awesome Pro 6.1.1 by %40fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons%2c Inc. --%3e%3cpath fill='white' d='M384 32H64C28.65 32 0 60.66 0 96v320c0 35.34 28.65 64 64 64h320c35.35 0 64-28.66 64-64V96C448 60.66 419.3 32 384 32zM344 312c0 17.69-14.31 32-32 32s-32-14.31-32-32V245.3l-121.4 121.4C152.4 372.9 144.2 376 136 376s-16.38-3.125-22.62-9.375c-12.5-12.5-12.5-32.75 0-45.25L234.8 200H168c-17.69 0-32-14.31-32-32s14.31-32 32-32h144c17.69 0 32 14.31 32 32V312z'/%3e%3c/svg%3e";
764
1084
 
1085
+ //register sidebar router to handle multiple sidebar views of this content element
765
1086
  //router defines the URL hash path mapping and controller provides functions for the paths
766
-
767
1087
  editor.registerSideBarRouting({
768
1088
  router: SidebarRouter,
769
1089
  controller: SidebarController
770
- }); // register external link list content element configuration editor for sidebar
1090
+ });
771
1091
 
1092
+ // register external link list content element configuration editor for sidebar
772
1093
  editor.contentElementTypes.register('externalLinkList', {
773
1094
  pictogram: img$9,
774
- category: 'links',
775
- supportedPositions: ['inline'],
776
- configurationEditor: function configurationEditor(_ref) {
777
- var entry = _ref.entry;
1095
+ category: 'tilesAndLinks',
1096
+ supportedPositions: ['inline', 'standAlone'],
1097
+ supportedWidthRange: ['m', 'full'],
1098
+ supportedStyles: ['boxShadow', 'outline'],
1099
+ defaultConfig: {
1100
+ thumbnailAspectRatio: 'square'
1101
+ },
1102
+ editorPath(contentElement) {
1103
+ const selectedItemId = contentElement.transientState.get('selectedItemId');
1104
+ if (selectedItemId) {
1105
+ return `/scrolled/external_links/${contentElement.id}/${selectedItemId}`;
1106
+ }
1107
+ },
1108
+ configurationPlace(contentElement, path) {
1109
+ const [propertyName, index, linkProperty] = path;
1110
+ if (propertyName !== 'links') {
1111
+ return;
1112
+ }
1113
+ const link = contentElement.configuration.get('links')[index];
1114
+ return {
1115
+ label: attributeLabel(linkProperty),
1116
+ select() {
1117
+ contentElement.postCommand({
1118
+ type: 'SET_SELECTED_ITEM',
1119
+ index: Number(index)
1120
+ });
1121
+ contentElement.select({
1122
+ navigate: false
1123
+ });
1124
+ editor.navigate(`/scrolled/external_links/${contentElement.id}/${link.id}`, {
1125
+ trigger: true
1126
+ });
1127
+ }
1128
+ };
1129
+ },
1130
+ configurationEditor({
1131
+ entry,
1132
+ contentElement
1133
+ }) {
778
1134
  this.tab('general', function () {
779
- this.group('ContentElementVariant', {
780
- entry: entry
781
- });
1135
+ const layout = contentElement.section.configuration.get('layout');
782
1136
  this.view(SidebarListView, {
783
1137
  contentElement: this.model.parent,
784
1138
  collection: ExternalLinkCollection.forContentElement(this.model.parent, entry)
785
1139
  });
1140
+ this.input('textPosition', SelectInputView, {
1141
+ values: ['below', 'right', 'overlay', 'none']
1142
+ });
1143
+ this.group('ContentElementVariant', {
1144
+ entry
1145
+ });
1146
+ this.input('overlayOpacity', SliderInputView, {
1147
+ defaultValue: 70,
1148
+ visibleBinding: 'textPosition',
1149
+ visibleBindingValue: 'overlay'
1150
+ });
1151
+ this.view(SeparatorView);
1152
+ this.group('ContentElementPosition', {
1153
+ entry
1154
+ });
1155
+ this.view(SeparatorView);
1156
+ this.input('enableScroller', SelectInputView, {
1157
+ values: ['never', 'always']
1158
+ });
1159
+ this.input('linkWidth', SliderInputView, {
1160
+ displayText: value => ['XS', 'S', 'M', 'L', 'XL', 'XXL'][value + 2],
1161
+ saveOnSlide: true,
1162
+ minValue: -2,
1163
+ maxValueBinding: ['width', 'textPosition'],
1164
+ maxValue: ([width, textPosition]) => maxLinkWidth({
1165
+ width,
1166
+ layout,
1167
+ textPosition
1168
+ }),
1169
+ defaultValue: -1
1170
+ });
1171
+ this.input('linkAlignment', SelectInputView, {
1172
+ values: ['spaceEvenly', 'left', 'right', 'center'],
1173
+ visibleBinding: ['textPosition', 'enableScroller'],
1174
+ visible: ([textPosition, enableScroller]) => textPosition !== 'right' && enableScroller !== 'always'
1175
+ });
1176
+ this.input('linkAlignment', SelectInputView, {
1177
+ values: ['left'],
1178
+ disabled: true,
1179
+ visibleBinding: ['textPosition', 'enableScroller'],
1180
+ visible: ([textPosition, enableScroller]) => textPosition !== 'right' && enableScroller === 'always'
1181
+ });
1182
+ this.input('thumbnailSize', SelectInputView, {
1183
+ values: ['small', 'medium', 'large'],
1184
+ visibleBinding: 'textPosition',
1185
+ visibleBindingValue: 'right'
1186
+ });
1187
+ const [aspectRatios, aspectRatiosTexts] = entry.getAspectRatios({
1188
+ includeOriginal: true
1189
+ });
1190
+ this.input('thumbnailAspectRatio', SelectInputView, {
1191
+ values: aspectRatios,
1192
+ texts: aspectRatiosTexts
1193
+ });
1194
+ this.input('thumbnailFit', SelectInputView, {
1195
+ values: ['cover', 'contain']
1196
+ });
1197
+ this.input('textSize', SelectInputView, {
1198
+ values: ['small', 'medium', 'large']
1199
+ });
1200
+ this.input('textAlign', SelectInputView, {
1201
+ values: ['left', 'right', 'center']
1202
+ });
1203
+ this.input('backfaces', CheckBoxInputView);
1204
+ this.input('displayButtons', CheckBoxInputView, {
1205
+ disabledBinding: 'backfaces',
1206
+ displayCheckedIfDisabled: true
1207
+ });
1208
+ this.group('LinkButtonVariant', {
1209
+ entry,
1210
+ visibleBinding: ['displayButtons', 'backfaces'],
1211
+ visible: ([displayButtons, backfaces]) => displayButtons || backfaces
1212
+ });
1213
+ this.group('ContentElementInlineFileRightsSettings');
786
1214
  });
787
1215
  }
788
- }); // register file handler for thumbnail of external link
1216
+ });
789
1217
 
1218
+ // register file handler for thumbnail of external link
790
1219
  editor.registerFileSelectionHandler('contentElement.externalLinks.link', function (options) {
791
- var contentElement = options.entry.contentElements.get(options.contentElementId);
792
- var links = ExternalLinkCollection.forContentElement(contentElement, options.entry);
793
-
1220
+ const contentElement = options.entry.contentElements.get(options.contentElementId);
1221
+ const links = ExternalLinkCollection.forContentElement(contentElement, options.entry);
794
1222
  this.call = function (file) {
795
- var link = links.get(options.id);
1223
+ const link = links.get(options.id);
796
1224
  link.setReference('thumbnail', file);
797
1225
  };
798
-
799
1226
  this.getReferer = function () {
800
1227
  return '/scrolled/external_links/' + contentElement.id + '/' + options.id;
801
1228
  };
802
1229
  });
1230
+ function attributeLabel(propertyName) {
1231
+ return I18n.t(`${propertyName}.label`, {
1232
+ scope: 'pageflow_scrolled.editor.content_elements.externalLinkList.attributes'
1233
+ });
1234
+ }
803
1235
 
804
- var img$a = "data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 640 512'%3e%3c!--! Font Awesome Pro 6.1.1 by %40fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons%2c Inc. --%3e%3cpath fill='white' d='M578.2 66.06C409.8 116.6 230.2 116.6 61.8 66.06C31 56.82 0 79.88 0 112v319.9c0 32.15 30.1 55.21 61.79 45.97c168.4-50.53 347.1-50.53 516.4-.002C608.1 487.2 640 464.1 640 431.1V112C640 79.88 609 56.82 578.2 66.06zM128 224C110.3 224 96 209.7 96 192s14.33-32 32-32c17.68 0 32 14.33 32 32S145.7 224 128 224zM474.3 388.6C423.4 380.3 371.8 376 320 376c-50.45 0-100.7 4.043-150.3 11.93c-14.14 2.246-24.11-13.19-15.78-24.84l49.18-68.56C206.1 290.4 210.9 288 216 288s9.916 2.441 12.93 6.574l32.46 44.51l93.3-139.1C357.7 194.7 362.7 192 368 192s10.35 2.672 13.31 7.125l109.1 165.1C498.1 375.9 488.1 390.8 474.3 388.6z'/%3e%3c/svg%3e";
805
-
806
- editor.contentElementTypes.register('vrImage', {
807
- pictogram: img$a,
808
- category: 'interactive',
809
- supportedPositions: ['inline', 'sticky', 'standAlone', 'left', 'right'],
810
- supportedWidthRange: ['xxs', 'full'],
811
- configurationEditor: function configurationEditor() {
812
- this.tab('general', function () {
813
- this.input('image', FileInputView, {
814
- collection: 'image_files',
815
- fileSelectionHandler: 'contentElementConfiguration',
1236
+ const SET_MODE = 'SET_MODE';
1237
+ const DRAG = 'DRAG';
1238
+ const CLICK_HANDLE = 'CLICK_HANDLE';
1239
+ const DRAG_HANDLE = 'DRAG_HANDLE';
1240
+ const DRAG_HANDLE_STOP = 'DRAG_HANDLE_STOP';
1241
+ const DOUBLE_CLICK_HANDLE = 'DOUBLE_CLICK_HANDLE';
1242
+ const MOUSE_MOVE = 'MOUSE_MOVE';
1243
+ const DRAG_POTENTIAL_POINT = 'DRAG_POTENTIAL_POINT';
1244
+ const DRAG_POTENTIAL_POINT_STOP = 'DRAG_POTENTIAL_POINT_STOP';
1245
+ const CLICK_INDICATOR = 'CLICK_INDICATOR';
1246
+ const DRAG_INDICATOR = 'DRAG_INDICATOR';
1247
+ const CENTER_INDICATOR = 'CENTER_INDICATOR';
1248
+ const UPDATE_SELECTION_POSITION = 'UPDATE_SELECTION_POSITION';
1249
+ const BLUR_SELECTION_POSITION = 'BLUR_SELECTION_POSITION';
1250
+ function reducer(state, action) {
1251
+ var _state$selection, _state$selection2, _state$selection3;
1252
+ switch (action.type) {
1253
+ case SET_MODE:
1254
+ if (action.value === state.mode) {
1255
+ return state;
1256
+ } else if (action.value === 'rect') {
1257
+ return {
1258
+ ...state,
1259
+ mode: 'rect',
1260
+ previousPolygonPoints: state.points,
1261
+ points: getBoundingBox(state.points),
1262
+ selection: null
1263
+ };
1264
+ } else {
1265
+ return {
1266
+ ...state,
1267
+ mode: 'polygon',
1268
+ points: state.previousPolygonPoints || state.points,
1269
+ selection: null
1270
+ };
1271
+ }
1272
+ case DRAG:
1273
+ let [deltaX, deltaY] = action.delta;
1274
+ state.points.forEach(point => {
1275
+ if (point[0] + deltaX > 100) {
1276
+ deltaX = 100 - point[0];
1277
+ }
1278
+ if (point[0] + deltaX < 0) {
1279
+ deltaX = -point[0];
1280
+ }
1281
+ if (point[1] + deltaY > 100) {
1282
+ deltaY = 100 - point[1];
1283
+ }
1284
+ if (point[1] + deltaY < 0) {
1285
+ deltaY = -point[1];
1286
+ }
1287
+ });
1288
+ return {
1289
+ ...state,
1290
+ points: state.points.map(point => [point[0] + deltaX, point[1] + deltaY]),
1291
+ indicatorPosition: [state.indicatorPosition[0] + deltaX, state.indicatorPosition[1] + deltaY]
1292
+ };
1293
+ case CLICK_HANDLE:
1294
+ if (state.mode === 'polygon') {
1295
+ return {
1296
+ ...state,
1297
+ selection: {
1298
+ type: 'handle',
1299
+ index: action.index,
1300
+ position: round(state.points[action.index])
1301
+ }
1302
+ };
1303
+ } else {
1304
+ return {
1305
+ ...state,
1306
+ selection: rectHandleSelection(action.index, state.points)
1307
+ };
1308
+ }
1309
+ case DRAG_HANDLE:
1310
+ state = updatePoints(state, action.index, action.cursor);
1311
+ return {
1312
+ ...state,
1313
+ indicatorPosition: ensureInPolygon(state.points, state.indicatorPosition)
1314
+ };
1315
+ case DRAG_HANDLE_STOP:
1316
+ return {
1317
+ ...state,
1318
+ startPoints: null
1319
+ };
1320
+ case DOUBLE_CLICK_HANDLE:
1321
+ if (state.mode !== 'polygon' || state.points.length <= 3) {
1322
+ return state;
1323
+ }
1324
+ const points = [...state.points.slice(0, action.index), ...state.points.slice(action.index + 1)];
1325
+ return {
1326
+ ...state,
1327
+ points,
1328
+ potentialPoint: null,
1329
+ indicatorPosition: ensureInPolygon(points, state.indicatorPosition),
1330
+ selection: null
1331
+ };
1332
+ case MOUSE_MOVE:
1333
+ if (state.mode !== 'polygon' || state.draggingPotentialPoint) {
1334
+ return state;
1335
+ }
1336
+ const [index, potentialPoint] = closestPointOnPolygon(state.points, action.cursor);
1337
+ return {
1338
+ ...state,
1339
+ potentialPointInsertIndex: index,
1340
+ potentialPoint
1341
+ };
1342
+ case DRAG_POTENTIAL_POINT:
1343
+ return {
1344
+ ...state,
1345
+ draggingPotentialPoint: true,
1346
+ potentialPoint: action.cursor,
1347
+ selection: {
1348
+ type: 'potentialPoint',
1349
+ position: round(action.cursor)
1350
+ }
1351
+ };
1352
+ case DRAG_POTENTIAL_POINT_STOP:
1353
+ const newPoints = withPotentialPoint(state);
1354
+ return {
1355
+ ...state,
1356
+ points: newPoints,
1357
+ draggingPotentialPoint: false,
1358
+ potentialPoint: null,
1359
+ selection: {
1360
+ type: 'handle',
1361
+ index: state.potentialPointInsertIndex,
1362
+ position: round(newPoints[state.potentialPointInsertIndex])
1363
+ }
1364
+ };
1365
+ case CLICK_INDICATOR:
1366
+ return {
1367
+ ...state,
1368
+ selection: {
1369
+ type: 'indicator',
1370
+ position: round(state.indicatorPosition)
1371
+ }
1372
+ };
1373
+ case DRAG_INDICATOR:
1374
+ const indicatorPosition = ensureInPolygon(state.points, action.cursor);
1375
+ return {
1376
+ ...state,
1377
+ indicatorPosition,
1378
+ selection: {
1379
+ type: 'indicator',
1380
+ position: round(indicatorPosition)
1381
+ }
1382
+ };
1383
+ case CENTER_INDICATOR:
1384
+ return {
1385
+ ...state,
1386
+ indicatorPosition: polygonCentroid(state.points)
1387
+ };
1388
+ case UPDATE_SELECTION_POSITION:
1389
+ if (((_state$selection = state.selection) === null || _state$selection === void 0 ? void 0 : _state$selection.type) === 'indicator') {
1390
+ return {
1391
+ ...state,
1392
+ indicatorPosition: ensureInPolygon(state.points, action.position),
1393
+ selection: {
1394
+ ...state.selection,
1395
+ position: action.position
1396
+ }
1397
+ };
1398
+ } else if (((_state$selection2 = state.selection) === null || _state$selection2 === void 0 ? void 0 : _state$selection2.type) === 'handle') {
1399
+ return updatePoints(state, state.selection.index, ensureInBounds(action.position), action.position);
1400
+ } else {
1401
+ return state;
1402
+ }
1403
+ case BLUR_SELECTION_POSITION:
1404
+ if (((_state$selection3 = state.selection) === null || _state$selection3 === void 0 ? void 0 : _state$selection3.type) === 'indicator') {
1405
+ return {
1406
+ ...state,
1407
+ selection: {
1408
+ ...state.selection,
1409
+ position: state.indicatorPosition
1410
+ }
1411
+ };
1412
+ } else if (state.selection) {
1413
+ return {
1414
+ ...state,
1415
+ startPoints: null,
1416
+ selection: {
1417
+ ...state.selection,
1418
+ position: handles(state)[state.selection.index].point
1419
+ },
1420
+ indicatorPosition: ensureInPolygon(state.points, state.indicatorPosition)
1421
+ };
1422
+ } else {
1423
+ return state;
1424
+ }
1425
+ default:
1426
+ throw new Error(`Unknown action ${action.type}.`);
1427
+ }
1428
+ }
1429
+ function drawnOutlinePoints(state) {
1430
+ if (state.draggingPotentialPoint) {
1431
+ return withPotentialPoint(state);
1432
+ } else {
1433
+ return state.points;
1434
+ }
1435
+ }
1436
+ const rectCursors = ['nwse-resize', 'ns-resize', 'nesw-resize', 'ew-resize'];
1437
+ function handles(state) {
1438
+ if (state.mode === 'rect') {
1439
+ return state.points.flatMap((point, index) => [point, midpoint(point, state.points[(index + 1) % state.points.length])]).map((point, index) => ({
1440
+ point,
1441
+ axis: index % 4 === 1 ? 'y' : index % 4 === 3 ? 'x' : null,
1442
+ cursor: rectCursors[index % 4],
1443
+ deletable: false
1444
+ }));
1445
+ } else {
1446
+ return state.points.map(point => ({
1447
+ point,
1448
+ circle: true,
1449
+ cursor: 'move',
1450
+ deletable: state.points.length > 3
1451
+ }));
1452
+ }
1453
+ }
1454
+ function updatePoints(state, index, position, selectionPosition) {
1455
+ if (state.mode === 'polygon') {
1456
+ return {
1457
+ ...state,
1458
+ points: [...state.points.slice(0, index), position, ...state.points.slice(index + 1)],
1459
+ selection: {
1460
+ type: 'handle',
1461
+ index: index,
1462
+ position: selectionPosition || round(position)
1463
+ }
1464
+ };
1465
+ } else {
1466
+ const startPoints = state.startPoints || (rectHandleAxis(index) === 'both' ? [state.points[(index / 2 + 2) % 4]] : [state.points[(index + 3) / 2 % 4], state.points[(index + 5) / 2 % 4]]);
1467
+ position = constrainToAxis(index, position, state.points);
1468
+ const points = getBoundingBox([position, ...startPoints]);
1469
+ return {
1470
+ ...state,
1471
+ startPoints,
1472
+ previousPolygonPoints: null,
1473
+ points,
1474
+ selection: rectHandleSelection(mapIndexOfRectHandleCrossingOver(index, position, startPoints), points, selectionPosition)
1475
+ };
1476
+ }
1477
+ }
1478
+ function rectHandleSelection(index, points, selectionPosition) {
1479
+ return {
1480
+ type: 'handle',
1481
+ index: index,
1482
+ axis: rectHandleAxis(index),
1483
+ position: selectionPosition || round(index % 2 === 0 ? points[index / 2] : midpoint(points[(index - 1) / 2], points[(index + 1) / 2 % 4]))
1484
+ };
1485
+ }
1486
+ function constrainToAxis(index, cursor, points) {
1487
+ const axis = rectHandleAxis(index);
1488
+ if (axis === 'x') {
1489
+ return [cursor[0], points[(index - 1) / 2][1]];
1490
+ } else if (axis === 'y') {
1491
+ return [points[(index - 1) / 2][0], cursor[1]];
1492
+ } else {
1493
+ return cursor;
1494
+ }
1495
+ }
1496
+ function rectHandleAxis(index) {
1497
+ return index % 2 === 0 ? 'both' : (index - 1) / 2 % 2 === 0 ? 'y' : 'x';
1498
+ }
1499
+ function mapIndexOfRectHandleCrossingOver(index, position, startPoints) {
1500
+ if (index >= 0 && index <= 3 && position[1] > startPoints[0][1] || index >= 4 && index <= 6 && position[1] < startPoints[0][1]) {
1501
+ index = 6 - index;
1502
+ }
1503
+ if ((index === 0 || index >= 6) && position[0] > startPoints[0][0] || index >= 2 && index <= 4 && position[0] < startPoints[0][0]) {
1504
+ index = (10 - index) % 8;
1505
+ }
1506
+ return index;
1507
+ }
1508
+ function withPotentialPoint(state) {
1509
+ return [...state.points.slice(0, state.potentialPointInsertIndex), state.potentialPoint, ...state.points.slice(state.potentialPointInsertIndex)];
1510
+ }
1511
+ function midpoint(p1, p2) {
1512
+ return [(p1[0] + p2[0]) / 2, (p1[1] + p2[1]) / 2];
1513
+ }
1514
+ function getBoundingBox(polygon) {
1515
+ if (polygon.length === 0) {
1516
+ return null;
1517
+ }
1518
+ let minX = polygon[0][0];
1519
+ let minY = polygon[0][1];
1520
+ let maxX = polygon[0][0];
1521
+ let maxY = polygon[0][1];
1522
+ for (let i = 1; i < polygon.length; i++) {
1523
+ let [x, y] = polygon[i];
1524
+ if (x < minX) minX = x;
1525
+ if (x > maxX) maxX = x;
1526
+ if (y < minY) minY = y;
1527
+ if (y > maxY) maxY = y;
1528
+ }
1529
+ return [[minX, minY], [maxX, minY], [maxX, maxY], [minX, maxY]];
1530
+ }
1531
+ function ensureInBounds(point) {
1532
+ return point.map(coord => Math.min(100, Math.max(0, coord)));
1533
+ }
1534
+ function ensureInPolygon(polygon, point) {
1535
+ return isPointInPolygon(polygon, point) ? point : closestPointOnPolygon(polygon, point)[1];
1536
+ }
1537
+ function isPointInPolygon(polygon, point) {
1538
+ let x = point[0],
1539
+ y = point[1];
1540
+ let inside = false;
1541
+ for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
1542
+ let xi = polygon[i][0],
1543
+ yi = polygon[i][1];
1544
+ let xj = polygon[j][0],
1545
+ yj = polygon[j][1];
1546
+ let intersect = yi > y !== yj > y && x < (xj - xi) * (y - yi) / (yj - yi) + xi;
1547
+ if (intersect) inside = !inside;
1548
+ }
1549
+ return inside;
1550
+ }
1551
+ function closestPointOnPolygon(polygon, c, maxDistance = 5) {
1552
+ function distance(p1, p2) {
1553
+ return Math.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2);
1554
+ }
1555
+ function closestPoint(A, B, C) {
1556
+ const AB = [B[0] - A[0], B[1] - A[1]];
1557
+ const AC = [C[0] - A[0], C[1] - A[1]];
1558
+ const abLength = AB[0] * AB[0] + AB[1] * AB[1]; // Dot product of AB with itself
1559
+
1560
+ if (abLength === 0) return A; // A and B are the same points
1561
+
1562
+ const proj = (AC[0] * AB[0] + AC[1] * AB[1]) / abLength; // Projection ratio of AC on AB
1563
+
1564
+ if (proj < 0) return A; // Closer to A
1565
+ else if (proj > 1) return B; // Closer to B
1566
+ else return [A[0] + proj * AB[0], A[1] + proj * AB[1]]; // Point on the segment
1567
+ }
1568
+ let closest = null;
1569
+ let minDistance = Infinity;
1570
+ for (let i = 0; i < polygon.length; i++) {
1571
+ const A = polygon[i];
1572
+ const B = polygon[(i + 1) % polygon.length];
1573
+ const point = closestPoint(A, B, c);
1574
+ const dist = distance(c, point);
1575
+ if (dist < minDistance) {
1576
+ minDistance = dist;
1577
+ closest = [i + 1, point];
1578
+ }
1579
+ }
1580
+ return closest;
1581
+ }
1582
+ function polygonCentroid(points) {
1583
+ let centroidX = 0;
1584
+ let centroidY = 0;
1585
+ let signedArea = 0;
1586
+ let x0 = 0;
1587
+ let y0 = 0;
1588
+ let x1 = 0;
1589
+ let y1 = 0;
1590
+ let a = 0;
1591
+ for (let i = 0; i < points.length - 1; i++) {
1592
+ x0 = points[i][0];
1593
+ y0 = points[i][1];
1594
+ x1 = points[i + 1][0];
1595
+ y1 = points[i + 1][1];
1596
+ a = x0 * y1 - x1 * y0;
1597
+ signedArea += a;
1598
+ centroidX += (x0 + x1) * a;
1599
+ centroidY += (y0 + y1) * a;
1600
+ }
1601
+ x0 = points[points.length - 1][0];
1602
+ y0 = points[points.length - 1][1];
1603
+ x1 = points[0][0];
1604
+ y1 = points[0][1];
1605
+ a = x0 * y1 - x1 * y0;
1606
+ signedArea += a;
1607
+ centroidX += (x0 + x1) * a;
1608
+ centroidY += (y0 + y1) * a;
1609
+ signedArea *= 0.5;
1610
+ centroidX /= 6 * signedArea;
1611
+ centroidY /= 6 * signedArea;
1612
+ return [centroidX, centroidY];
1613
+ }
1614
+ function round(point) {
1615
+ return point.map(coord => Math.round(coord * 10) / 10);
1616
+ }
1617
+
1618
+ var css$1 = ".DraggableEditorView-module_wrapper__J8JLO {\n position: relative;\n display: inline-block;\n overflow: hidden;\n\n background-image:\n linear-gradient(45deg, var(--ui-on-surface-color-lighter) 25%, transparent 25%),\n linear-gradient(135deg, var(--ui-on-surface-color-lighter) 25%, transparent 25%),\n linear-gradient(45deg, transparent 75%, var(--ui-on-surface-color-lighter) 75%),\n linear-gradient(135deg, transparent 75%, var(--ui-on-surface-color-lighter) 75%);\n background-size: 16px 16px;\n background-position:0 0, 8px 0, 8px -8px, 0px 8px;\n}\n\n.DraggableEditorView-module_buttons__1Xob0 {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin: 10px 0;\n gap: 15px;\n}\n\n.DraggableEditorView-module_buttons__1Xob0 button {\n white-space: nowrap;\n}\n\n.DraggableEditorView-module_coordinates__3dVEt,\n.DraggableEditorView-module_coordinates__3dVEt label {\n display: flex;\n align-items: center;\n margin: 0;\n}\n\n.DraggableEditorView-module_coordinates__3dVEt {\n flex-wrap: wrap;\n justify-content: flex-end;\n}\n\n.DraggableEditorView-module_coordinates__3dVEt {\n gap: 10px;\n}\n\n.DraggableEditorView-module_coordinates__3dVEt label {\n gap: 5px;\n}\n\n.DraggableEditorView-module_coordinates__3dVEt input[disabled] {\n background-color: var(--ui-on-surface-color-lightest);\n}\n\n.DraggableEditorView-module_modeButtons__4wZBu {\n flex: 1;\n white-space: nowrap;\n}\n\n.DraggableEditorView-module_modeButtons__4wZBu button:first-child {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n\n.DraggableEditorView-module_modeButtons__4wZBu button:last-child {\n margin-left: -1px;\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n\n.DraggableEditorView-module_modeButtons__4wZBu button[aria-pressed=true] {\n background-color: var(--ui-selection-color-light);\n}\n\n.DraggableEditorView-module_buttons__1Xob0 img {\n vertical-align: middle;\n margin-right: 6px;\n}\n\n.DraggableEditorView-module_placeholderImage__JyyId {\n aspect-ratio: 16 / 9;\n background-color: #000;\n}\n\n.DraggableEditorView-module_image__1Ockp {\n display: block;\n height: calc(100vh - 250px);\n max-height: 600px;\n min-height: 200px;\n}\n\n.DraggableEditorView-module_portraitImage__2lYIE {\n max-height: 1200px;\n}\n\n.DraggableEditorView-module_overlay__3QLpM {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n}\n\n.DraggableEditorView-module_overlay__3QLpM svg {\n position: absolute;\n width: 100%;\n height: 100%;\n}\n\n.DraggableEditorView-module_overlay__3QLpM polygon {\n vector-effect: non-scaling-stroke;\n stroke-width: 1px;\n stroke-linejoin: round;\n stroke: #fff;\n fill: transparent;\n opacity: 0.9;\n cursor: move;\n}\n\n.DraggableEditorView-module_handle__9LHSy {\n position: absolute;\n width: 10px;\n height: 10px;\n background-color: #fff;\n transform: translate(-50%, -50%);\n border: solid 1px var(--ui-primary-color);\n border-radius: 2px;\n opacity: 0.9;\n z-index: 2;\n}\n\n.DraggableEditorView-module_handle__9LHSy::before {\n content: \"\";\n position: absolute;\n top: 0;\n left: 0;\n width: 30px;\n height: 30px;\n margin: -10px 0 0 -10px;\n border-radius: 100%;\n z-index: 1;\n}\n\n.DraggableEditorView-module_circle__35Pba {\n border-radius: 100%;\n cursor: move;\n}\n\n.DraggableEditorView-module_potential__vxrma {\n opacity: 0;\n z-index: 1;\n cursor: default;\n}\n\n.DraggableEditorView-module_handle__9LHSy:hover {\n opacity: 1;\n}\n\n.DraggableEditorView-module_indicator__23yQO {\n --size: 15px;\n position: absolute;\n left: var(--center-x);\n top: var(--center-y);\n margin: calc(var(--size) / -2) 0 0 calc(var(--size) / -2);\n border-radius: 50%;\n width: var(--size);\n height: var(--size);\n background-color: var(--color, #fff);\n transition: transform 0.2s ease;\n cursor: move;\n z-index: 3;\n}\n\n.DraggableEditorView-module_indicator__23yQO:hover {\n transform: scale(1.2);\n}\n\n.DraggableEditorView-module_indicator__23yQO::before {\n content: \"\";\n position: absolute;\n top: 0;\n left: 0;\n width: var(--size);\n height: var(--size);\n border-radius: 50%;\n background-color: #fff;\n animation: DraggableEditorView-module_blink__1SdQI 1s infinite;\n opacity: 0.3;\n z-index: -1;\n}\n\n.DraggableEditorView-module_selected__2bQtv {\n box-shadow: 0 0 0 3px var(--ui-selection-color),\n 0 0 0 4px var(--ui-primary-color-light);\n}\n\n@keyframes DraggableEditorView-module_blink__1SdQI {\n 0% {\n transform: scale(1.7);\n }\n\n 50% {\n transform: scale(2);\n }\n\n 100% {\n transform: scale(1.7);\n }\n}\n";
1619
+ var styles$1 = {"wrapper":"DraggableEditorView-module_wrapper__J8JLO","buttons":"DraggableEditorView-module_buttons__1Xob0","coordinates":"DraggableEditorView-module_coordinates__3dVEt","modeButtons":"DraggableEditorView-module_modeButtons__4wZBu","placeholderImage":"DraggableEditorView-module_placeholderImage__JyyId","image":"DraggableEditorView-module_image__1Ockp","portraitImage":"DraggableEditorView-module_portraitImage__2lYIE","overlay":"DraggableEditorView-module_overlay__3QLpM","handle":"DraggableEditorView-module_handle__9LHSy","circle":"DraggableEditorView-module_circle__35Pba","potential":"DraggableEditorView-module_potential__vxrma","indicator":"DraggableEditorView-module_indicator__23yQO","blink":"DraggableEditorView-module_blink__1SdQI","selected":"DraggableEditorView-module_selected__2bQtv"};
1620
+ styleInject(css$1);
1621
+
1622
+ var img$a = "data:image/svg+xml,%3c%3fxml version='1.0' encoding='UTF-8' standalone='no'%3f%3e%3csvg xmlns='http://www.w3.org/2000/svg' id='svg4' version='1.1' viewBox='0 0 448 512'%3e %3cpath d='M 61.345703 63.888672 C 44.725703 63.888672 31.345703 77.268672 31.345703 93.888672 L 31.345703 417.57031 C 31.345703 434.19031 44.725703 447.57031 61.345703 447.57031 L 385.02734 447.57031 C 401.64734 447.57031 415.02734 434.19031 415.02734 417.57031 L 415.02734 93.888672 C 415.02734 77.268672 401.64734 63.888672 385.02734 63.888672 L 61.345703 63.888672 z M 106 127.80078 L 341.13867 127.80078 C 346.67867 127.80078 351.13867 132.26078 351.13867 137.80078 L 351.13867 372.93945 C 351.13867 378.47945 346.67867 382.93945 341.13867 382.93945 L 106 382.93945 C 100.46 382.93945 96 378.47945 96 372.93945 L 96 137.80078 C 96 132.26078 100.46 127.80078 106 127.80078 z ' fill='hsla(197%2c 26%25%2c 23%25%2c 0.8)' /%3e%3c/svg%3e";
1623
+
1624
+ var img$b = "data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512'%3e%3c!--!Font Awesome Free 6.5.2 by %40fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons%2c Inc.--%3e%3cpath d='M96 151.4V360.6c9.7 5.6 17.8 13.7 23.4 23.4H328.6c0-.1 .1-.2 .1-.3l-4.5-7.9-32-56 0 0c-1.4 .1-2.8 .1-4.2 .1c-35.3 0-64-28.7-64-64s28.7-64 64-64c1.4 0 2.8 0 4.2 .1l0 0 32-56 4.5-7.9-.1-.3H119.4c-5.6 9.7-13.7 17.8-23.4 23.4zM384.3 352c35.2 .2 63.7 28.7 63.7 64c0 35.3-28.7 64-64 64c-23.7 0-44.4-12.9-55.4-32H119.4c-11.1 19.1-31.7 32-55.4 32c-35.3 0-64-28.7-64-64c0-23.7 12.9-44.4 32-55.4V151.4C12.9 140.4 0 119.7 0 96C0 60.7 28.7 32 64 32c23.7 0 44.4 12.9 55.4 32H328.6c11.1-19.1 31.7-32 55.4-32c35.3 0 64 28.7 64 64c0 35.3-28.5 63.8-63.7 64l-4.5 7.9-32 56-2.3 4c4.2 8.5 6.5 18 6.5 28.1s-2.3 19.6-6.5 28.1l2.3 4 32 56 4.5 7.9z' fill='hsla(197%2c 26%25%2c 23%25%2c 0.8)' /%3e%3c/svg%3e";
1625
+
1626
+ var img$c = "data:image/svg+xml,%3c%3fxml version='1.0' encoding='UTF-8' standalone='no'%3f%3e%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' version='1.1'%3e %3cpath d='m 243%2c25.5 c -3%2c3.6 -6%2c8.5 -6%2c14 V 129 l -8%2c-7 c -7%2c-8 -20%2c-8 -28%2c0 -7%2c7 -7%2c19 0%2c26 l 42%2c42 v 0 c 2%2c2 4%2c3 6%2c4 3%2c1 5%2c1 8%2c2 v 0 c 5%2c-1 10%2c-2 14%2c-6 l 41%2c-42 c 7%2c-7 7%2c-19 0%2c-26 -8%2c-8 -20%2c-8 -28%2c0 l -8%2c7 V 38.9 C 276%2c28.5 268%2c20 257%2c20 c -6%2c0 -11%2c2.4 -14%2c5.5 z' style='stroke-width:0.608' /%3e %3cpath d='m 486%2c243 c -4%2c-3 -8%2c-6 -14%2c-6 h -89 l 7%2c-8 c 8%2c-7 8%2c-21 0%2c-29 -7%2c-7 -19%2c-7 -26%2c0 l -42%2c43 v 0 c -2%2c2 -3%2c4 -4%2c6 -1%2c3 -1%2c5 -2%2c8 v 0 c 1%2c5 2%2c10 6%2c14 l 42%2c41 c 7%2c7 19%2c7 26%2c0 8%2c-8 8%2c-20 0%2c-28 l -7%2c-8 h 90 c 10%2c0 19%2c-8 19%2c-19 0%2c-6 -3%2c-11 -6%2c-14 z' style='stroke-width:0.608' /%3e %3cpath d='m 269%2c486 c 3%2c-4 6%2c-8 6%2c-14 v -89 l 8%2c7 c 7%2c8 21%2c8 29%2c0 7%2c-7 7%2c-19 0%2c-26 l -43%2c-42 v 0 c -2%2c-2 -4%2c-3 -6%2c-4 -3%2c-1 -5%2c-1 -8%2c-2 v 0 c -5%2c1 -10%2c2 -14%2c6 l -41%2c42 c -7%2c7 -7%2c19 0%2c26 8%2c8 20%2c8 28%2c0 l 8%2c-7 v 90 c 0%2c10 8%2c19 19%2c19 6%2c0 11%2c-3 14%2c-6 z' style='stroke-width:0.608' /%3e %3cpath d='m 26%2c269 c 4%2c3 8%2c6 14%2c6 h 89 l -7%2c8 c -8%2c7 -8%2c21 0%2c29 7%2c7 19%2c7 26%2c0 l 42%2c-43 v 0 c 2%2c-2 3%2c-4 4%2c-6 1%2c-3 1%2c-5 2%2c-8 v 0 c -1%2c-5 -2%2c-10 -6%2c-14 l -42%2c-41 c -7%2c-7 -19%2c-7 -26%2c0 -8%2c8 -8%2c20 0%2c28 l 7%2c8 H 39 c -10%2c0 -19%2c8 -19%2c19 0%2c6 3%2c11 6%2c14 z' style='stroke-width:0.608' /%3e%3c/svg%3e";
1627
+
1628
+ var _jsxFileName = "/home/tfischbach/code/pageflow/entry_types/scrolled/package/src/contentElements/hotspots/editor/EditAreaDialogView/DraggableEditorView.js";
1629
+ const i18nPrefix = 'pageflow_scrolled.editor.content_elements.hotspots.edit_area_dialog';
1630
+ const DraggableEditorView = Marionette.View.extend({
1631
+ render() {
1632
+ var _this$options$file;
1633
+ ReactDOM.render( /*#__PURE__*/React.createElement(DraggableEditor, {
1634
+ imageSrc: (_this$options$file = this.options.file) === null || _this$options$file === void 0 ? void 0 : _this$options$file.getBackgroundPositioningImageUrl(),
1635
+ portrait: this.options.file && this.options.file.get('width') < this.options.file.get('height'),
1636
+ indicatorColor: paletteColor(this.model.get(this.getPropertyName('color')) || this.model.get('color')),
1637
+ initialMode: this.model.get(this.getPropertyName('mode')),
1638
+ initialPoints: this.model.get(this.getPropertyName('outline')),
1639
+ initialIndicatorPosition: this.model.get(this.getPropertyName('indicatorPosition')),
1640
+ onModeChange: mode => this.mode = mode,
1641
+ onPointsChange: points => this.points = points,
1642
+ onIndicatorPositionChange: indicatorPosition => this.indicatorPosition = indicatorPosition,
1643
+ __self: this,
1644
+ __source: {
1645
+ fileName: _jsxFileName,
1646
+ lineNumber: 42,
1647
+ columnNumber: 7
1648
+ }
1649
+ }), this.el);
1650
+ return this;
1651
+ },
1652
+ save() {
1653
+ if (this.mode) {
1654
+ this.model.set(this.getPropertyName('mode'), this.mode);
1655
+ }
1656
+ if (this.points) {
1657
+ this.model.set(this.getPropertyName('outline'), this.points);
1658
+ }
1659
+ if (this.indicatorPosition) {
1660
+ this.model.set(this.getPropertyName('indicatorPosition'), this.indicatorPosition);
1661
+ }
1662
+ },
1663
+ getPropertyName(suffix) {
1664
+ return this.options.portrait ? `portrait${utils.capitalize(suffix)}` : suffix;
1665
+ }
1666
+ });
1667
+ function DraggableEditor({
1668
+ imageSrc,
1669
+ portrait,
1670
+ indicatorColor,
1671
+ initialMode,
1672
+ initialPoints,
1673
+ initialIndicatorPosition,
1674
+ onModeChange,
1675
+ onPointsChange,
1676
+ onIndicatorPositionChange
1677
+ }) {
1678
+ var _state$selection2, _state$selection3;
1679
+ const [state, dispatch] = useReducer(reducer, {
1680
+ mode: initialMode || 'rect',
1681
+ points: initialPoints || [[40, 40], [60, 40], [60, 60], [40, 60]],
1682
+ indicatorPosition: initialIndicatorPosition || [50, 50]
1683
+ });
1684
+ const {
1685
+ mode,
1686
+ points,
1687
+ potentialPoint,
1688
+ indicatorPosition,
1689
+ selection
1690
+ } = state;
1691
+ useEffect(() => {
1692
+ onModeChange(mode);
1693
+ }, [onModeChange, mode]);
1694
+ useEffect(() => {
1695
+ onPointsChange(points);
1696
+ }, [onPointsChange, points]);
1697
+ useEffect(() => {
1698
+ onIndicatorPositionChange(indicatorPosition);
1699
+ }, [onIndicatorPositionChange, indicatorPosition]);
1700
+ const ref = useRef();
1701
+ function clientToPercent(event) {
1702
+ const rect = ref.current.getBoundingClientRect();
1703
+ return [Math.max(0, Math.min(100, (event.clientX - rect.left) / rect.width * 100)), Math.max(0, Math.min(100, (event.clientY - rect.top) / rect.height * 100))];
1704
+ }
1705
+ return /*#__PURE__*/React.createElement("div", {
1706
+ __self: this,
1707
+ __source: {
1708
+ fileName: _jsxFileName,
1709
+ lineNumber: 121,
1710
+ columnNumber: 5
1711
+ }
1712
+ }, /*#__PURE__*/React.createElement("div", {
1713
+ className: styles$1.buttons,
1714
+ __self: this,
1715
+ __source: {
1716
+ fileName: _jsxFileName,
1717
+ lineNumber: 122,
1718
+ columnNumber: 7
1719
+ }
1720
+ }, /*#__PURE__*/React.createElement(ModeButtons, {
1721
+ mode: mode,
1722
+ dispatch: dispatch,
1723
+ __self: this,
1724
+ __source: {
1725
+ fileName: _jsxFileName,
1726
+ lineNumber: 123,
1727
+ columnNumber: 9
1728
+ }
1729
+ }), /*#__PURE__*/React.createElement(Coordinates, {
1730
+ selection: selection,
1731
+ onChange: position => dispatch({
1732
+ type: UPDATE_SELECTION_POSITION,
1733
+ position
1734
+ }),
1735
+ onBlur: () => dispatch({
1736
+ type: BLUR_SELECTION_POSITION
1737
+ }),
1738
+ __self: this,
1739
+ __source: {
1740
+ fileName: _jsxFileName,
1741
+ lineNumber: 124,
1742
+ columnNumber: 9
1743
+ }
1744
+ }), /*#__PURE__*/React.createElement(CenterIndicatorButton, {
1745
+ onClick: () => dispatch({
1746
+ type: CENTER_INDICATOR
1747
+ }),
1748
+ __self: this,
1749
+ __source: {
1750
+ fileName: _jsxFileName,
1751
+ lineNumber: 132,
1752
+ columnNumber: 9
1753
+ }
1754
+ })), /*#__PURE__*/React.createElement("div", {
1755
+ className: styles$1.wrapper,
1756
+ __self: this,
1757
+ __source: {
1758
+ fileName: _jsxFileName,
1759
+ lineNumber: 137,
1760
+ columnNumber: 7
1761
+ }
1762
+ }, imageSrc ? /*#__PURE__*/React.createElement("img", {
1763
+ className: classNames(styles$1.image, {
1764
+ [styles$1.portraitImage]: portrait
1765
+ }),
1766
+ src: imageSrc,
1767
+ alt: I18n.t(`${i18nPrefix}.hotspots_image`),
1768
+ __self: this,
1769
+ __source: {
1770
+ fileName: _jsxFileName,
1771
+ lineNumber: 139,
1772
+ columnNumber: 10
1773
+ }
1774
+ }) : /*#__PURE__*/React.createElement("div", {
1775
+ className: classNames(styles$1.image, styles$1.placeholderImage),
1776
+ __self: this,
1777
+ __source: {
1778
+ fileName: _jsxFileName,
1779
+ lineNumber: 142,
1780
+ columnNumber: 10
1781
+ }
1782
+ }), /*#__PURE__*/React.createElement("div", {
1783
+ ref: ref,
1784
+ className: styles$1.overlay,
1785
+ onMouseMove: event => dispatch({
1786
+ type: MOUSE_MOVE,
1787
+ cursor: clientToPercent(event)
1788
+ }),
1789
+ __self: this,
1790
+ __source: {
1791
+ fileName: _jsxFileName,
1792
+ lineNumber: 143,
1793
+ columnNumber: 9
1794
+ }
1795
+ }, /*#__PURE__*/React.createElement("svg", {
1796
+ xmlns: "http://www.w3.org/2000/svg",
1797
+ viewBox: "0 0 100 100",
1798
+ preserveAspectRatio: "none",
1799
+ __self: this,
1800
+ __source: {
1801
+ fileName: _jsxFileName,
1802
+ lineNumber: 146,
1803
+ columnNumber: 11
1804
+ }
1805
+ }, /*#__PURE__*/React.createElement(DraggableCore, {
1806
+ onDrag: (event, dragEvent) => {
1807
+ const rect = ref.current.getBoundingClientRect();
1808
+ dispatch({
1809
+ type: DRAG,
1810
+ delta: [dragEvent.deltaX / rect.width * 100, dragEvent.deltaY / rect.height * 100]
1811
+ });
1812
+ },
1813
+ __self: this,
1814
+ __source: {
1815
+ fileName: _jsxFileName,
1816
+ lineNumber: 147,
1817
+ columnNumber: 13
1818
+ }
1819
+ }, /*#__PURE__*/React.createElement("polygon", {
1820
+ points: drawnOutlinePoints(state).map(coords => coords.map(coord => coord).join(',')).join(' '),
1821
+ __self: this,
1822
+ __source: {
1823
+ fileName: _jsxFileName,
1824
+ lineNumber: 158,
1825
+ columnNumber: 15
1826
+ }
1827
+ }))), handles(state).map((handle, index) => {
1828
+ var _state$selection;
1829
+ return /*#__PURE__*/React.createElement(Handle, {
1830
+ key: index,
1831
+ point: handle.point,
1832
+ selected: ((_state$selection = state.selection) === null || _state$selection === void 0 ? void 0 : _state$selection.index) === index,
1833
+ axis: handle.axis,
1834
+ cursor: handle.cursor,
1835
+ circle: handle.circle,
1836
+ title: handle.deletable ? I18n.t(`${i18nPrefix}.double_click_to_delete`) : null,
1837
+ onClick: event => dispatch({
1838
+ type: CLICK_HANDLE,
1839
+ index
1840
+ }),
1841
+ onDoubleClick: event => dispatch({
1842
+ type: DOUBLE_CLICK_HANDLE,
1843
+ index
1844
+ }),
1845
+ onDrag: event => dispatch({
1846
+ type: DRAG_HANDLE,
1847
+ index,
1848
+ cursor: clientToPercent(event)
1849
+ }),
1850
+ onDragStop: event => dispatch({
1851
+ type: DRAG_HANDLE_STOP
1852
+ }),
1853
+ __self: this,
1854
+ __source: {
1855
+ fileName: _jsxFileName,
1856
+ lineNumber: 165,
1857
+ columnNumber: 13
1858
+ }
1859
+ });
1860
+ }), potentialPoint && /*#__PURE__*/React.createElement(Handle, {
1861
+ point: potentialPoint,
1862
+ circle: true,
1863
+ potential: true,
1864
+ selected: ((_state$selection2 = state.selection) === null || _state$selection2 === void 0 ? void 0 : _state$selection2.type) === 'potentialPoint',
1865
+ onDrag: event => dispatch({
1866
+ type: DRAG_POTENTIAL_POINT,
1867
+ cursor: clientToPercent(event)
1868
+ }),
1869
+ onDragStop: event => dispatch({
1870
+ type: DRAG_POTENTIAL_POINT_STOP
1871
+ }),
1872
+ __self: this,
1873
+ __source: {
1874
+ fileName: _jsxFileName,
1875
+ lineNumber: 191,
1876
+ columnNumber: 30
1877
+ }
1878
+ }), /*#__PURE__*/React.createElement(Indicator, {
1879
+ position: indicatorPosition,
1880
+ selected: ((_state$selection3 = state.selection) === null || _state$selection3 === void 0 ? void 0 : _state$selection3.type) === 'indicator',
1881
+ color: indicatorColor,
1882
+ onClick: event => dispatch({
1883
+ type: CLICK_INDICATOR
1884
+ }),
1885
+ onDrag: event => dispatch({
1886
+ type: DRAG_INDICATOR,
1887
+ cursor: clientToPercent(event)
1888
+ }),
1889
+ __self: this,
1890
+ __source: {
1891
+ fileName: _jsxFileName,
1892
+ lineNumber: 203,
1893
+ columnNumber: 11
1894
+ }
1895
+ }))));
1896
+ }
1897
+ const modeIcons = {
1898
+ rect: img$a,
1899
+ polygon: img$b
1900
+ };
1901
+ function ModeButtons({
1902
+ mode,
1903
+ dispatch
1904
+ }) {
1905
+ return /*#__PURE__*/React.createElement("div", {
1906
+ className: styles$1.modeButtons,
1907
+ __self: this,
1908
+ __source: {
1909
+ fileName: _jsxFileName,
1910
+ lineNumber: 226,
1911
+ columnNumber: 5
1912
+ }
1913
+ }, ['rect', 'polygon'].map(availableMode => /*#__PURE__*/React.createElement("button", {
1914
+ key: availableMode,
1915
+ type: "button",
1916
+ className: buttonStyles.secondaryIconButton,
1917
+ "aria-pressed": mode === availableMode,
1918
+ onClick: () => dispatch({
1919
+ type: SET_MODE,
1920
+ value: availableMode
1921
+ }),
1922
+ __self: this,
1923
+ __source: {
1924
+ fileName: _jsxFileName,
1925
+ lineNumber: 228,
1926
+ columnNumber: 9
1927
+ }
1928
+ }, /*#__PURE__*/React.createElement("img", {
1929
+ src: modeIcons[availableMode],
1930
+ alt: "",
1931
+ width: "20",
1932
+ height: "20",
1933
+ __self: this,
1934
+ __source: {
1935
+ fileName: _jsxFileName,
1936
+ lineNumber: 233,
1937
+ columnNumber: 11
1938
+ }
1939
+ }), I18n.t(availableMode, {
1940
+ scope: `${i18nPrefix}.modes`
1941
+ }))));
1942
+ }
1943
+ function Handle({
1944
+ point,
1945
+ selected,
1946
+ circle,
1947
+ potential,
1948
+ title,
1949
+ cursor,
1950
+ onDrag,
1951
+ onDragStop,
1952
+ onClick,
1953
+ onDoubleClick
1954
+ }) {
1955
+ return /*#__PURE__*/React.createElement(DraggableCore, {
1956
+ onDrag: onDrag,
1957
+ onStop: onDragStop,
1958
+ __self: this,
1959
+ __source: {
1960
+ fileName: _jsxFileName,
1961
+ lineNumber: 244,
1962
+ columnNumber: 5
1963
+ }
1964
+ }, /*#__PURE__*/React.createElement("div", {
1965
+ className: classNames(styles$1.handle, {
1966
+ [styles$1.circle]: circle,
1967
+ [styles$1.selected]: selected,
1968
+ [styles$1.potential]: potential
1969
+ }),
1970
+ tabIndex: "0",
1971
+ onClick: onClick,
1972
+ onDoubleClick: onDoubleClick,
1973
+ title: title,
1974
+ style: {
1975
+ left: `${point[0]}%`,
1976
+ top: `${point[1]}%`,
1977
+ cursor
1978
+ },
1979
+ __self: this,
1980
+ __source: {
1981
+ fileName: _jsxFileName,
1982
+ lineNumber: 246,
1983
+ columnNumber: 7
1984
+ }
1985
+ }));
1986
+ }
1987
+ function Indicator({
1988
+ position,
1989
+ selected,
1990
+ color,
1991
+ onClick,
1992
+ onDrag
1993
+ }) {
1994
+ return /*#__PURE__*/React.createElement(DraggableCore, {
1995
+ onDrag: onDrag,
1996
+ __self: this,
1997
+ __source: {
1998
+ fileName: _jsxFileName,
1999
+ lineNumber: 261,
2000
+ columnNumber: 5
2001
+ }
2002
+ }, /*#__PURE__*/React.createElement("div", {
2003
+ className: classNames(styles$1.indicator, {
2004
+ [styles$1.selected]: selected
2005
+ }),
2006
+ onClick: onClick,
2007
+ style: {
2008
+ left: `${position[0]}%`,
2009
+ top: `${position[1]}%`,
2010
+ '--color': color
2011
+ },
2012
+ title: I18n.t(`${i18nPrefix}.indicator_title`),
2013
+ __self: this,
2014
+ __source: {
2015
+ fileName: _jsxFileName,
2016
+ lineNumber: 262,
2017
+ columnNumber: 7
2018
+ }
2019
+ }));
2020
+ }
2021
+ function CenterIndicatorButton({
2022
+ onClick
2023
+ }) {
2024
+ return /*#__PURE__*/React.createElement("button", {
2025
+ type: "button",
2026
+ className: buttonStyles.secondaryIconButton,
2027
+ onClick: onClick,
2028
+ __self: this,
2029
+ __source: {
2030
+ fileName: _jsxFileName,
2031
+ lineNumber: 276,
2032
+ columnNumber: 5
2033
+ }
2034
+ }, /*#__PURE__*/React.createElement("img", {
2035
+ src: img$c,
2036
+ alt: "",
2037
+ width: "20",
2038
+ height: "20",
2039
+ __self: this,
2040
+ __source: {
2041
+ fileName: _jsxFileName,
2042
+ lineNumber: 279,
2043
+ columnNumber: 7
2044
+ }
2045
+ }), I18n.t(`${i18nPrefix}.centerIndicator`));
2046
+ }
2047
+ function Coordinates({
2048
+ selection,
2049
+ onChange,
2050
+ onBlur
2051
+ }) {
2052
+ if (!selection) {
2053
+ return null;
2054
+ }
2055
+ const position = selection.position;
2056
+ return /*#__PURE__*/React.createElement("div", {
2057
+ className: styles$1.coordinates,
2058
+ __self: this,
2059
+ __source: {
2060
+ fileName: _jsxFileName,
2061
+ lineNumber: 293,
2062
+ columnNumber: 5
2063
+ }
2064
+ }, /*#__PURE__*/React.createElement(CoordinateInput, {
2065
+ label: "X",
2066
+ disabled: selection.axis === 'y',
2067
+ value: position[0],
2068
+ onChange: event => onChange([parseFloat(event.target.value || 0), position[1]]),
2069
+ onBlur: onBlur,
2070
+ __self: this,
2071
+ __source: {
2072
+ fileName: _jsxFileName,
2073
+ lineNumber: 294,
2074
+ columnNumber: 7
2075
+ }
2076
+ }), /*#__PURE__*/React.createElement(CoordinateInput, {
2077
+ label: "Y",
2078
+ disabled: selection.axis === 'x',
2079
+ value: position[1],
2080
+ onChange: event => onChange([position[0], parseFloat(event.target.value || 0)]),
2081
+ onBlur: onBlur,
2082
+ __self: this,
2083
+ __source: {
2084
+ fileName: _jsxFileName,
2085
+ lineNumber: 299,
2086
+ columnNumber: 7
2087
+ }
2088
+ }));
2089
+ }
2090
+ function CoordinateInput({
2091
+ disabled,
2092
+ label,
2093
+ value,
2094
+ onChange,
2095
+ onBlur
2096
+ }) {
2097
+ return /*#__PURE__*/React.createElement("div", {
2098
+ className: classNames({
2099
+ 'input-disabled': disabled
2100
+ }),
2101
+ __self: this,
2102
+ __source: {
2103
+ fileName: _jsxFileName,
2104
+ lineNumber: 310,
2105
+ columnNumber: 5
2106
+ }
2107
+ }, /*#__PURE__*/React.createElement("label", {
2108
+ __self: this,
2109
+ __source: {
2110
+ fileName: _jsxFileName,
2111
+ lineNumber: 311,
2112
+ columnNumber: 7
2113
+ }
2114
+ }, label, ":", /*#__PURE__*/React.createElement("input", {
2115
+ type: "number",
2116
+ min: "0",
2117
+ max: "100",
2118
+ disabled: disabled,
2119
+ value: value,
2120
+ onClick: event => event.target.focus(),
2121
+ onChange: onChange,
2122
+ onBlur: onBlur,
2123
+ __self: this,
2124
+ __source: {
2125
+ fileName: _jsxFileName,
2126
+ lineNumber: 313,
2127
+ columnNumber: 9
2128
+ }
2129
+ }), "%"));
2130
+ }
2131
+
2132
+ var css$2 = ".EditAreaDialogView-module_box__1IOYj {\n width: min-content;\n min-height: 310px;\n min-width: 400px;\n}\n\n.EditAreaDialogView-module_wrapper__F28hP {}\n\n.EditAreaDialogView-module_save__1o3Qg {}\n";
2133
+ var styles$2 = {"box":"EditAreaDialogView-module_box__1IOYj","wrapper":"EditAreaDialogView-module_wrapper__F28hP","save":"EditAreaDialogView-module_save__1o3Qg"};
2134
+ styleInject(css$2);
2135
+
2136
+ const i18nPrefix$1 = 'pageflow_scrolled.editor.content_elements.hotspots.edit_area_dialog';
2137
+ const EditAreaDialogView = Marionette.ItemView.extend({
2138
+ template: () => `
2139
+ <div class="${dialogViewStyles.backdrop}">
2140
+ <div class="editor ${dialogViewStyles.box} ${styles$2.box}">
2141
+ <h1 class="${dialogViewStyles.header}">
2142
+ ${I18n.t(`${i18nPrefix$1}.header`)}
2143
+ </h1>
2144
+
2145
+ <div class="${styles$2.wrapper}">
2146
+ </div>
2147
+
2148
+ <div class="${dialogViewStyles.footer}">
2149
+ <button class="${styles$2.save} ${buttonStyles.saveButton}">
2150
+ ${I18n.t(`${i18nPrefix$1}.save`)}
2151
+ </button>
2152
+ <button class="${dialogViewStyles.close}">
2153
+ ${I18n.t(`${i18nPrefix$1}.cancel`)}
2154
+ </button>
2155
+ </div>
2156
+ </div>
2157
+ </div>
2158
+ `,
2159
+ mixins: [dialogView],
2160
+ ui: cssModulesUtils$1.ui(styles$2, 'wrapper'),
2161
+ events: cssModulesUtils$1.events(styles$2, {
2162
+ 'click save': function () {
2163
+ this.save();
2164
+ this.close();
2165
+ if (this.options.onSave) {
2166
+ this.options.onSave();
2167
+ }
2168
+ }
2169
+ }),
2170
+ onRender() {
2171
+ if (this.options.portraitFile) {
2172
+ const tabsView = new TabsView({
2173
+ translationKeyPrefixes: [`${i18nPrefix$1}.tabs`],
2174
+ defaultTab: this.options.defaultTab
2175
+ });
2176
+ this.editorViews = [new DraggableEditorView({
2177
+ model: this.model,
2178
+ file: this.options.file
2179
+ }), new DraggableEditorView({
2180
+ model: this.model,
2181
+ file: this.options.portraitFile,
2182
+ portrait: true
2183
+ })];
2184
+ tabsView.tab('default', () => this.editorViews[0]);
2185
+ tabsView.tab('portrait', () => this.editorViews[1]);
2186
+ this.appendSubview(tabsView, {
2187
+ to: this.ui.wrapper
2188
+ });
2189
+ } else {
2190
+ this.editorViews = [new DraggableEditorView({
2191
+ model: this.model,
2192
+ file: this.options.file
2193
+ })];
2194
+ this.appendSubview(this.editorViews[0], {
2195
+ to: this.ui.wrapper
2196
+ });
2197
+ }
2198
+ },
2199
+ save() {
2200
+ this.editorViews.forEach(view => view.save());
2201
+ }
2202
+ });
2203
+ EditAreaDialogView.show = function (options) {
2204
+ app.dialogRegion.show(new EditAreaDialogView(options));
2205
+ };
2206
+
2207
+ const Area = Backbone.Model.extend({
2208
+ mixins: [transientReferences],
2209
+ thumbnailFile() {
2210
+ var _this$imageFile;
2211
+ return (_this$imageFile = this.imageFile()) === null || _this$imageFile === void 0 ? void 0 : _this$imageFile.thumbnailFile();
2212
+ },
2213
+ title() {
2214
+ var _tooltipTexts$this$id, _tooltipTexts$this$id2, _tooltipTexts$this$id3, _tooltipTexts$this$id4, _tooltipTexts$this$id5;
2215
+ const tooltipTexts = this.collection.contentElement.configuration.get('tooltipTexts');
2216
+ return tooltipTexts === null || tooltipTexts === void 0 ? void 0 : (_tooltipTexts$this$id = tooltipTexts[this.id]) === null || _tooltipTexts$this$id === void 0 ? void 0 : (_tooltipTexts$this$id2 = _tooltipTexts$this$id.title) === null || _tooltipTexts$this$id2 === void 0 ? void 0 : (_tooltipTexts$this$id3 = _tooltipTexts$this$id2[0]) === null || _tooltipTexts$this$id3 === void 0 ? void 0 : (_tooltipTexts$this$id4 = _tooltipTexts$this$id3.children) === null || _tooltipTexts$this$id4 === void 0 ? void 0 : (_tooltipTexts$this$id5 = _tooltipTexts$this$id4[0]) === null || _tooltipTexts$this$id5 === void 0 ? void 0 : _tooltipTexts$this$id5.text;
2217
+ },
2218
+ imageFile() {
2219
+ return this.collection.entry.imageFiles.getByPermaId(this.get('activeImage'));
2220
+ },
2221
+ highlight() {
2222
+ this.collection.contentElement.postCommand({
2223
+ type: 'HIGHLIGHT_AREA',
2224
+ index: this.collection.indexOf(this)
2225
+ });
2226
+ },
2227
+ resetHighlight() {
2228
+ this.collection.contentElement.postCommand({
2229
+ type: 'RESET_AREA_HIGHLIGHT'
2230
+ });
2231
+ }
2232
+ });
2233
+
2234
+ var css$3 = ".AreasListView-module_listContainer__1vyoU {}\n";
2235
+ var styles$3 = {"listContainer":"AreasListView-module_listContainer__1vyoU"};
2236
+ styleInject(css$3);
2237
+
2238
+ const AreasListView = Marionette.Layout.extend({
2239
+ template: data => `
2240
+ <div class='${styles$3.listContainer}'></div>
2241
+ <button class="${buttonStyles.addButton}">
2242
+ ${I18n.t('pageflow_scrolled.editor.content_elements.hotspots.areas.add')}
2243
+ </button>
2244
+ `,
2245
+ regions: cssModulesUtils.ui(styles$3, 'listContainer'),
2246
+ events: cssModulesUtils.events(buttonStyles, {
2247
+ 'click addButton': function () {
2248
+ const model = new Area();
2249
+ EditAreaDialogView.show({
2250
+ model,
2251
+ file: this.model.getImageFile('image'),
2252
+ portraitFile: this.model.getImageFile('portraitImage'),
2253
+ onSave: () => this.collection.addWithId(model)
2254
+ });
2255
+ }
2256
+ }),
2257
+ onRender() {
2258
+ this.listContainer.show(new ListView({
2259
+ label: I18n.t('pageflow_scrolled.editor.content_elements.hotspots.areas.label'),
2260
+ collection: this.collection,
2261
+ sortable: true,
2262
+ highlight: true,
2263
+ onEdit: model => {
2264
+ this.options.contentElement.postCommand({
2265
+ type: 'SET_ACTIVE_AREA',
2266
+ index: this.collection.indexOf(model)
2267
+ });
2268
+ editor.navigate(`/scrolled/hotspots/${this.options.contentElement.id}/${model.id}`, {
2269
+ trigger: true
2270
+ });
2271
+ },
2272
+ onRemove: model => {
2273
+ if (window.confirm(I18n.t('pageflow_scrolled.editor.content_elements.hotspots.areas.confirm_delete'))) {
2274
+ this.collection.remove(model);
2275
+ }
2276
+ }
2277
+ }));
2278
+ }
2279
+ });
2280
+
2281
+ const AreasCollection = Backbone.Collection.extend({
2282
+ model: Area,
2283
+ comparator: 'position',
2284
+ initialize(models, options) {
2285
+ this.entry = options.entry;
2286
+ this.contentElement = options.contentElement;
2287
+ this.listenTo(this, 'add change sort', this.updateConfiguration);
2288
+ this.listenTo(this, 'remove', () => this.updateConfiguration({
2289
+ pruneTooltips: true
2290
+ }));
2291
+ },
2292
+ updateConfiguration({
2293
+ pruneTooltips
2294
+ }) {
2295
+ let updatedAttributes = {
2296
+ areas: this.toJSON()
2297
+ };
2298
+ if (pruneTooltips) {
2299
+ updatedAttributes = {
2300
+ ...updatedAttributes,
2301
+ ...this.getPrunedProperty('tooltipTexts'),
2302
+ ...this.getPrunedProperty('tooltipLinks')
2303
+ };
2304
+ }
2305
+ this.contentElement.configuration.set(updatedAttributes);
2306
+ },
2307
+ getPrunedProperty(propertyName) {
2308
+ return {
2309
+ [propertyName]: _.pick(this.contentElement.configuration.get(propertyName) || {}, ...this.pluck('id'))
2310
+ };
2311
+ },
2312
+ addWithId(model) {
2313
+ model.set('id', this.length ? Math.max(...this.pluck('id')) + 1 : 1);
2314
+ this.add(model);
2315
+ },
2316
+ saveOrder() {}
2317
+ });
2318
+ AreasCollection.forContentElement = function (contentElement, entry) {
2319
+ return new AreasCollection(contentElement.configuration.get('areas') || [], {
2320
+ entry: entry,
2321
+ contentElement: contentElement
2322
+ });
2323
+ };
2324
+
2325
+ const SidebarRouter$1 = Marionette.AppRouter.extend({
2326
+ appRoutes: {
2327
+ 'scrolled/hotspots/:id/:area_id': 'area',
2328
+ 'scrolled/hotspots/:id/:area_id/:tab': 'area'
2329
+ }
2330
+ });
2331
+
2332
+ var css$4 = ".AreaInputView-module_button__3LSo- {\n width: 100%;\n}\n";
2333
+ var styles$4 = {"button":"AreaInputView-module_button__3LSo-"};
2334
+ styleInject(css$4);
2335
+
2336
+ const AreaInputView = Marionette.Layout.extend({
2337
+ template: data => `
2338
+ <label>
2339
+ <span class="name"></span>
2340
+ <span class="inline_help"></span>
2341
+ </label>
2342
+ <button class="${buttonStyles.targetButton} ${styles$4.button}">
2343
+ ${I18n.t('pageflow_scrolled.editor.content_elements.hotspots.area_input.edit')}
2344
+ </button>
2345
+ `,
2346
+ mixins: [inputView],
2347
+ events: cssModulesUtils.events(buttonStyles, {
2348
+ 'click targetButton': function () {
2349
+ EditAreaDialogView.show({
2350
+ model: this.model,
2351
+ file: this.options.file,
2352
+ portraitFile: this.options.portraitFile,
2353
+ defaultTab: this.options.defaultTab
2354
+ });
2355
+ }
2356
+ })
2357
+ });
2358
+
2359
+ var css$5 = ".SidebarEditAreaView-module_view__2AVKF .tabs_view-tabs > :nth-child(2) {\n margin-left: 5px;\n}\n\n.SidebarEditAreaView-module_view__2AVKF .tabs_view-tabs > :nth-child(2)::before {\n content: \"\\203A\";\n margin-left: -15px;\n margin-right: 10px;\n font-weight: normal;\n}\n";
2360
+ var styles$5 = {"view":"SidebarEditAreaView-module_view__2AVKF"};
2361
+ styleInject(css$5);
2362
+
2363
+ const SidebarEditAreaView = EditConfigurationView.extend({
2364
+ translationKeyPrefix: 'pageflow_scrolled.editor.content_elements.hotspots.edit_area',
2365
+ className: 'edit_configuration_view ' + styles$5.view,
2366
+ containingCollection() {
2367
+ return this.options.collection;
2368
+ },
2369
+ getConfigurationModel() {
2370
+ return this.model;
2371
+ },
2372
+ defaultTab() {
2373
+ return this.options.tab || (this.options.entry.get('emulation_mode') === 'phone' ? 'portrait' : 'area');
2374
+ },
2375
+ goBackPath() {
2376
+ return `/scrolled/content_elements/${this.options.contentElement.get('id')}`;
2377
+ },
2378
+ goBack() {
2379
+ this.options.contentElement.postCommand({
2380
+ type: 'SET_ACTIVE_AREA',
2381
+ index: -1
2382
+ });
2383
+ EditConfigurationView.prototype.goBack.call(this);
2384
+ },
2385
+ getActionsMenuItems() {
2386
+ return [new DestroyAreaMenuItem({}, {
2387
+ collection: this.options.collection,
2388
+ model: this.model
2389
+ })];
2390
+ },
2391
+ configure(configurationEditor) {
2392
+ const options = this.options;
2393
+ const file = options.contentElement.configuration.getImageFile('image');
2394
+ const portraitFile = options.contentElement.configuration.getImageFile('portraitImage');
2395
+ const panZoomEnabled = options.contentElement.configuration.get('enablePanZoom') !== 'never';
2396
+ const preserveActiveArea = () => setTimeout(() => options.contentElement.postCommand({
2397
+ type: 'SET_ACTIVE_AREA',
2398
+ index: options.collection.indexOf(this.model)
2399
+ }), 200);
2400
+ if (file && portraitFile) {
2401
+ this.previousEmulationMode = options.entry.get('emulation_mode') || 'desktop';
2402
+ }
2403
+ configurationEditor.tab('area', function () {
2404
+ if (file && portraitFile && options.entry.has('emulation_mode')) {
2405
+ options.entry.unset('emulation_mode');
2406
+ preserveActiveArea();
2407
+ }
2408
+ this.input('area', AreaInputView, {
2409
+ file,
2410
+ portraitFile
2411
+ });
2412
+ this.input('activeImage', FileInputView, {
2413
+ collection: 'image_files',
2414
+ fileSelectionHandler: 'hotspotsArea',
2415
+ fileSelectionHandlerOptions: {
2416
+ contentElementId: options.contentElement.get('id'),
2417
+ tab: 'area'
2418
+ },
2419
+ positioning: false
2420
+ });
2421
+ if (panZoomEnabled) {
2422
+ this.input('zoom', SliderInputView);
2423
+ }
2424
+ this.group('PaletteColor', {
2425
+ propertyName: 'color',
2426
+ entry: options.entry
2427
+ });
2428
+ this.input('tooltipReference', SelectInputView, {
2429
+ values: ['indicator', 'area']
2430
+ });
2431
+ this.input('tooltipPosition', SelectInputView, {
2432
+ values: ['below', 'above']
2433
+ });
2434
+ this.input('tooltipMaxWidth', SelectInputView, {
2435
+ defaultValue: 'medium',
2436
+ values: ['wide', 'medium', 'narrow', 'veryNarrow']
2437
+ });
2438
+ this.view(SeparatorView);
2439
+ this.input('tooltipImage', FileInputView, {
2440
+ collection: 'image_files',
2441
+ fileSelectionHandler: 'hotspotsArea',
2442
+ fileSelectionHandlerOptions: {
2443
+ contentElementId: options.contentElement.get('id'),
2444
+ tab: 'area'
2445
+ },
2446
+ positioning: false
2447
+ });
2448
+ this.input('tooltipTextAlign', SelectInputView, {
2449
+ values: ['left', 'right', 'center']
2450
+ });
2451
+ });
2452
+ if (portraitFile) {
2453
+ configurationEditor.tab('portrait', function () {
2454
+ if (file && portraitFile && !options.entry.has('emulation_mode')) {
2455
+ options.entry.set('emulation_mode', 'phone');
2456
+ preserveActiveArea();
2457
+ }
2458
+ this.input('portraitArea', AreaInputView, {
2459
+ file,
2460
+ portraitFile,
2461
+ defaultTab: 'portrait'
2462
+ });
2463
+ this.input('portraitActiveImage', FileInputView, {
2464
+ collection: 'image_files',
2465
+ fileSelectionHandler: 'hotspotsArea',
2466
+ fileSelectionHandlerOptions: {
2467
+ contentElementId: options.contentElement.get('id'),
2468
+ tab: 'portrait'
2469
+ },
2470
+ positioning: false
2471
+ });
2472
+ if (panZoomEnabled) {
2473
+ this.input('portraitZoom', SliderInputView);
2474
+ }
2475
+ this.group('PaletteColor', {
2476
+ propertyName: 'portraitColor',
2477
+ entry: options.entry
2478
+ });
2479
+ this.input('portraitTooltipReference', SelectInputView, {
2480
+ values: ['indicator', 'area']
2481
+ });
2482
+ this.input('portraitTooltipPosition', SelectInputView, {
2483
+ values: ['below', 'above']
2484
+ });
2485
+ this.input('portraitTooltipMaxWidth', SelectInputView, {
2486
+ defaultValue: 'medium',
2487
+ values: ['wide', 'medium', 'narrow', 'veryNarrow']
2488
+ });
2489
+ });
2490
+ }
2491
+ }
2492
+ });
2493
+ const DestroyAreaMenuItem = DestroyMenuItem.extend({
2494
+ translationKeyPrefix: 'pageflow_scrolled.editor.content_elements.hotspots.edit_area',
2495
+ destroyModel() {
2496
+ this.options.collection.remove(this.options.model);
2497
+ }
2498
+ });
2499
+
2500
+ const SidebarController$1 = Marionette.Controller.extend({
2501
+ initialize: function (options) {
2502
+ this.entry = options.entry;
2503
+ this.region = options.region;
2504
+ },
2505
+ area: function (id, areaId, tab) {
2506
+ const contentElement = this.entry.contentElements.get(id);
2507
+ const areasCollection = AreasCollection.forContentElement(contentElement, this.entry);
2508
+ this.region.show(new SidebarEditAreaView({
2509
+ model: areasCollection.get(areaId),
2510
+ collection: areasCollection,
2511
+ entry: this.entry,
2512
+ contentElement,
2513
+ tab
2514
+ }));
2515
+ }
2516
+ });
2517
+
2518
+ var img$d = "data:image/svg+xml,%3c%3fxml version='1.0' encoding='UTF-8'%3f%3e%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' version='1.1'%3e %3cpath d='M 63.099609 32 C 28.639609 32 -0.009765625 60.65 -0.009765625 96 L -0.009765625 416 C -0.009765625 451.35 28.641797 480 63.091797 480 L 447.0918 480 C 482.4418 480 511.0918 451.35 511.0918 416 L 511.0918 96 C 511.1009 60.65 483.29961 32 447.09961 32 L 63.099609 32 z M 147.62305 91.271484 C 194.82656 91.271484 233.12305 127.19517 233.12305 171.47461 C 233.12305 207.98427 181.0205 272.98443 158.17578 299.80273 C 152.69839 306.19401 142.54575 306.19401 137.06836 299.80273 C 114.22363 272.98443 62.121094 207.98427 62.121094 171.47461 C 62.121094 127.19517 100.41953 91.271484 147.62305 91.271484 z M 147.62305 133.9043 A 38.686943 36.290436 0 0 0 108.93555 170.19336 A 38.686943 36.290436 0 0 0 147.62305 206.48438 A 38.686943 36.290436 0 0 0 186.30859 170.19336 A 38.686943 36.290436 0 0 0 147.62305 133.9043 z M 364.37695 207.4043 C 411.58047 207.4043 449.87891 243.32993 449.87891 287.60938 C 449.87891 324.11903 397.77637 389.11725 374.93164 415.93555 C 369.45425 422.32683 359.30162 422.32683 353.82422 415.93555 C 330.9795 389.11725 278.87695 324.11903 278.87695 287.60938 C 278.87695 243.32992 317.17343 207.4043 364.37695 207.4043 z M 364.37695 250.03711 A 38.686943 36.290436 0 0 0 325.69141 286.32617 A 38.686943 36.290436 0 0 0 364.37695 322.61719 A 38.686943 36.290436 0 0 0 403.06445 286.32617 A 38.686943 36.290436 0 0 0 364.37695 250.03711 z ' style='fill:white' /%3e%3c/svg%3e";
2519
+
2520
+ editor.registerSideBarRouting({
2521
+ router: SidebarRouter$1,
2522
+ controller: SidebarController$1
2523
+ });
2524
+ editor.contentElementTypes.register('hotspots', {
2525
+ pictogram: img$d,
2526
+ category: 'interactive',
2527
+ supportedPositions: ['inline', 'side', 'sticky', 'standAlone', 'left', 'right', 'backdrop'],
2528
+ supportedWidthRange: ['xxs', 'full'],
2529
+ supportedCaptions: true,
2530
+ supportedStyles: ['boxShadow', 'outline'],
2531
+ editorPath(contentElement) {
2532
+ const activeAreaId = contentElement.transientState.get('activeAreaId');
2533
+ if (activeAreaId) {
2534
+ return `/scrolled/hotspots/${contentElement.id}/${activeAreaId}`;
2535
+ }
2536
+ },
2537
+ configurationPlace(contentElement, path) {
2538
+ const [propertyName] = path;
2539
+ if (propertyName !== 'areas') {
2540
+ return elementConfigurationPlace(contentElement);
2541
+ }
2542
+ return areaConfigurationPlace(contentElement, path);
2543
+ },
2544
+ configurationEditor({
2545
+ entry,
2546
+ contentElement
2547
+ }) {
2548
+ this.tab('general', function () {
2549
+ this.input('image', FileInputView, {
2550
+ collection: 'image_files',
2551
+ fileSelectionHandler: 'contentElementConfiguration',
2552
+ positioning: false,
2553
+ dropDownMenuItems: [InlineFileRightsMenuItem]
2554
+ });
2555
+ this.input('portraitImage', FileInputView, {
2556
+ collection: 'image_files',
2557
+ fileSelectionHandler: 'contentElementConfiguration',
2558
+ positioning: false
2559
+ });
2560
+ this.view(AreasListView, {
2561
+ configuration: this.model,
2562
+ contentElement,
2563
+ collection: AreasCollection.forContentElement(contentElement, entry)
2564
+ });
2565
+ this.input('invertTooltips', CheckBoxInputView$1);
2566
+ this.input('enablePanZoom', SelectInputView$1, {
2567
+ values: ['never', 'phonePlatform', 'always']
2568
+ });
2569
+ this.view(SeparatorView$1);
2570
+ this.input('enableFullscreen', CheckBoxInputView$1, {
2571
+ disabledBinding: ['position', 'width'],
2572
+ disabled: () => contentElement.getWidth() === contentElementWidths.full || contentElement.getPosition() === 'backdrop',
2573
+ displayUncheckedIfDisabled: true
2574
+ });
2575
+ this.group('ContentElementPosition', {
2576
+ entry
2577
+ });
2578
+ this.view(SeparatorView$1);
2579
+ this.group('LinkButtonVariant', {
2580
+ entry
2581
+ });
2582
+ this.group('ContentElementCaption', {
2583
+ entry
2584
+ });
2585
+ this.group('ContentElementInlineFileRightsSettings');
2586
+ });
2587
+ }
2588
+ });
2589
+ editor.registerFileSelectionHandler('hotspotsArea', function (options) {
2590
+ const contentElement = options.entry.contentElements.get(options.contentElementId);
2591
+ const areas = AreasCollection.forContentElement(contentElement, options.entry);
2592
+ this.call = function (file) {
2593
+ areas.get(options.id).setReference(options.attributeName, file);
2594
+ };
2595
+ this.getReferer = function () {
2596
+ return '/scrolled/hotspots/' + contentElement.id + '/' + options.id + '/' + options.tab;
2597
+ };
2598
+ });
2599
+
2600
+ // The editor path of the element points at the active area, which
2601
+ // would send the sidebar back to an area the property is not in.
2602
+ function elementConfigurationPlace(contentElement) {
2603
+ return {
2604
+ select() {
2605
+ contentElement.postCommand({
2606
+ type: 'SET_ACTIVE_AREA',
2607
+ index: -1
2608
+ });
2609
+ contentElement.select();
2610
+ }
2611
+ };
2612
+ }
2613
+ function areaConfigurationPlace(contentElement, [, index, propertyName]) {
2614
+ const area = contentElement.configuration.get('areas')[index];
2615
+ const tab = propertyName.startsWith('portrait') ? 'portrait' : 'area';
2616
+ return {
2617
+ label: areaAttributeLabel(propertyName),
2618
+ select() {
2619
+ contentElement.postCommand({
2620
+ type: 'SET_ACTIVE_AREA',
2621
+ index: Number(index)
2622
+ });
2623
+ contentElement.select({
2624
+ navigate: false
2625
+ });
2626
+ editor.navigate(`/scrolled/hotspots/${contentElement.id}/${area.id}/${tab}`, {
2627
+ trigger: true
2628
+ });
2629
+ }
2630
+ };
2631
+ }
2632
+ function areaAttributeLabel(propertyName) {
2633
+ return I18n.t(`${propertyName}.label`, {
2634
+ scope: 'pageflow_scrolled.editor.content_elements.hotspots.edit_area.attributes'
2635
+ });
2636
+ }
2637
+
2638
+ var img$e = "data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 640 512'%3e%3c!--! Font Awesome Pro 6.1.1 by %40fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons%2c Inc. --%3e%3cpath fill='white' d='M578.2 66.06C409.8 116.6 230.2 116.6 61.8 66.06C31 56.82 0 79.88 0 112v319.9c0 32.15 30.1 55.21 61.79 45.97c168.4-50.53 347.1-50.53 516.4-.002C608.1 487.2 640 464.1 640 431.1V112C640 79.88 609 56.82 578.2 66.06zM128 224C110.3 224 96 209.7 96 192s14.33-32 32-32c17.68 0 32 14.33 32 32S145.7 224 128 224zM474.3 388.6C423.4 380.3 371.8 376 320 376c-50.45 0-100.7 4.043-150.3 11.93c-14.14 2.246-24.11-13.19-15.78-24.84l49.18-68.56C206.1 290.4 210.9 288 216 288s9.916 2.441 12.93 6.574l32.46 44.51l93.3-139.1C357.7 194.7 362.7 192 368 192s10.35 2.672 13.31 7.125l109.1 165.1C498.1 375.9 488.1 390.8 474.3 388.6z'/%3e%3c/svg%3e";
2639
+
2640
+ const aspectRatios = ['wide', 'narrow', 'square', 'portrait'];
2641
+ editor.contentElementTypes.register('vrImage', {
2642
+ pictogram: img$e,
2643
+ category: 'interactive',
2644
+ supportedPositions: ['inline', 'side', 'sticky', 'standAlone', 'left', 'right', 'backdrop'],
2645
+ supportedWidthRange: ['xxs', 'full'],
2646
+ supportedCaptions: true,
2647
+ supportedStyles: ['boxShadow', 'outline'],
2648
+ configurationEditor({
2649
+ entry
2650
+ }) {
2651
+ this.tab('general', function () {
2652
+ this.input('image', FileInputView, {
2653
+ collection: 'image_files',
2654
+ fileSelectionHandler: 'contentElementConfiguration',
816
2655
  filter: 'with_projection',
817
2656
  positioning: false,
818
2657
  dropDownMenuItems: [InlineFileRightsMenuItem]
@@ -827,84 +2666,700 @@ editor.contentElementTypes.register('vrImage', {
827
2666
  minValue: -60,
828
2667
  maxValue: 60
829
2668
  });
830
- this.group('ContentElementPosition');
2669
+ this.input('aspectRatio', SelectInputView$1, {
2670
+ includeBlank: true,
2671
+ blankTranslationKey: 'pageflow_scrolled.editor.' + 'content_elements.vrImage.' + 'attributes.aspectRatio.blank',
2672
+ values: aspectRatios
2673
+ });
2674
+ this.input('portraitAspectRatio', SelectInputView$1, {
2675
+ includeBlank: true,
2676
+ blankTranslationKey: 'pageflow_scrolled.editor.' + 'content_elements.vrImage.' + 'attributes.portraitAspectRatio.blank',
2677
+ values: aspectRatios
2678
+ });
2679
+ this.view(SeparatorView$1);
2680
+ this.group('ContentElementPosition', {
2681
+ entry
2682
+ });
2683
+ this.view(SeparatorView$1);
2684
+ this.group('ContentElementCaption', {
2685
+ entry
2686
+ });
2687
+ this.group('ContentElementInlineFileRightsSettings');
2688
+ });
2689
+ }
2690
+ });
2691
+ editor.fileTypes.modify('image_files', {
2692
+ configurationEditorInputs(model) {
2693
+ var values = ['equirectangular_mono', 'equirectangular_stereo'];
2694
+ return [{
2695
+ name: 'projection',
2696
+ inputView: SelectInputView$1,
2697
+ inputViewOptions: {
2698
+ includeBlank: true,
2699
+ values: values
2700
+ }
2701
+ }];
2702
+ },
2703
+ confirmUploadTableColumns: [{
2704
+ name: 'projection',
2705
+ cellView: EnumTableCellView
2706
+ }],
2707
+ filters: [{
2708
+ name: 'with_projection',
2709
+ matches: function (file) {
2710
+ return !!file.configuration.get('projection');
2711
+ }
2712
+ }]
2713
+ });
2714
+
2715
+ var img$f = "data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 640 512'%3e%3c!--! Font Awesome Pro 6.1.1 by %40fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons%2c Inc. --%3e%3cpath fill='white' d='M414.8 40.79L286.8 488.8C281.9 505.8 264.2 515.6 247.2 510.8C230.2 505.9 220.4 488.2 225.2 471.2L353.2 23.21C358.1 6.216 375.8-3.624 392.8 1.232C409.8 6.087 419.6 23.8 414.8 40.79H414.8zM518.6 121.4L630.6 233.4C643.1 245.9 643.1 266.1 630.6 278.6L518.6 390.6C506.1 403.1 485.9 403.1 473.4 390.6C460.9 378.1 460.9 357.9 473.4 345.4L562.7 256L473.4 166.6C460.9 154.1 460.9 133.9 473.4 121.4C485.9 108.9 506.1 108.9 518.6 121.4V121.4zM166.6 166.6L77.25 256L166.6 345.4C179.1 357.9 179.1 378.1 166.6 390.6C154.1 403.1 133.9 403.1 121.4 390.6L9.372 278.6C-3.124 266.1-3.124 245.9 9.372 233.4L121.4 121.4C133.9 108.9 154.1 108.9 166.6 121.4C179.1 133.9 179.1 154.1 166.6 166.6V166.6z'/%3e%3c/svg%3e";
2716
+
2717
+ const aspectRatios$1 = ['wide', 'narrow', 'square', 'portrait'];
2718
+ editor.contentElementTypes.register('iframeEmbed', {
2719
+ pictogram: img$f,
2720
+ category: 'interactive',
2721
+ featureName: 'iframe_embed_content_element',
2722
+ supportedPositions: ['inline', 'side', 'sticky', 'standAlone', 'left', 'right'],
2723
+ supportedWidthRange: ['xxs', 'full'],
2724
+ supportedCaptions: true,
2725
+ supportedStyles: ['boxShadow', 'outline'],
2726
+ configurationEditor({
2727
+ entry
2728
+ }) {
2729
+ this.tab('general', function () {
2730
+ this.input('source', TextInputView, {
2731
+ maxLength: 2000
2732
+ });
2733
+ this.input('requireConsent', CheckBoxInputView);
2734
+ this.view(InfoBoxView, {
2735
+ level: 'error',
2736
+ text: I18n.t('pageflow_scrolled.editor.content_elements.iframeEmbed.help_texts.missingConsentVendor'),
2737
+ visibleBinding: ['source', 'requireConsent'],
2738
+ visible: ([source, requireConsent]) => source && requireConsent && !entry.consentVendors.fromUrl(source)
2739
+ });
2740
+ this.input('title', TextInputView);
2741
+ this.input('aspectRatio', SelectInputView, {
2742
+ values: aspectRatios$1,
2743
+ disabledBinding: 'autoResize'
2744
+ });
2745
+ this.input('portraitAspectRatio', SelectInputView, {
2746
+ includeBlank: true,
2747
+ blankTranslationKey: 'pageflow_scrolled.editor.' + 'content_elements.iframeEmbed.' + 'attributes.portraitAspectRatio.blank',
2748
+ values: aspectRatios$1,
2749
+ disabledBinding: 'autoResize'
2750
+ });
2751
+ this.input('autoResize', CheckBoxInputView);
2752
+ this.view(InfoBoxView, {
2753
+ level: 'info',
2754
+ text: I18n.t('pageflow_scrolled.editor.content_elements.iframeEmbed.help_texts.autoResize'),
2755
+ visibleBinding: 'autoResize'
2756
+ });
2757
+ this.input('scale', SelectInputView, {
2758
+ values: ['p100', 'p75', 'p50', 'p33']
2759
+ });
2760
+ this.group('ContentElementPosition', {
2761
+ entry
2762
+ });
2763
+ this.view(SeparatorView);
2764
+ this.group('ContentElementCaption', {
2765
+ entry
2766
+ });
2767
+ });
2768
+ }
2769
+ });
2770
+
2771
+ var css$6 = ".ItemsListView-module_listContainer__2XDCy {\n}\n";
2772
+ var styles$6 = {"listContainer":"ItemsListView-module_listContainer__2XDCy"};
2773
+ styleInject(css$6);
2774
+
2775
+ const ItemsListView = Marionette.Layout.extend({
2776
+ template: data => `
2777
+ <div class='${styles$6.listContainer}'></div>
2778
+ <button class="${buttonStyles.addButton}">
2779
+ ${I18n.t('pageflow_scrolled.editor.content_elements.imageGallery.items.add')}
2780
+ </button>
2781
+ `,
2782
+ regions: cssModulesUtils.ui(styles$6, 'listContainer'),
2783
+ events: cssModulesUtils.events(buttonStyles, {
2784
+ 'click addButton': function () {
2785
+ this.collection.selectImage();
2786
+ }
2787
+ }),
2788
+ onRender() {
2789
+ this.listContainer.show(new ListView({
2790
+ label: I18n.t('pageflow_scrolled.editor.content_elements.imageGallery.items.label'),
2791
+ collection: this.collection,
2792
+ sortable: true,
2793
+ onEdit: model => {
2794
+ this.options.contentElement.postCommand({
2795
+ type: 'SET_CURRENT_ITEM',
2796
+ index: this.collection.indexOf(model)
2797
+ });
2798
+ editor.navigate(`/scrolled/imageGalleries/${this.options.contentElement.id}/${model.id}`, {
2799
+ trigger: true
2800
+ });
2801
+ },
2802
+ onRemove: model => this.collection.remove(model)
2803
+ }));
2804
+ }
2805
+ });
2806
+
2807
+ const Item = Backbone.Model.extend({
2808
+ mixins: [transientReferences],
2809
+ thumbnailFile() {
2810
+ var _this$imageFile;
2811
+ return (_this$imageFile = this.imageFile()) === null || _this$imageFile === void 0 ? void 0 : _this$imageFile.thumbnailFile();
2812
+ },
2813
+ title() {
2814
+ var _this$imageFile2;
2815
+ return (_this$imageFile2 = this.imageFile()) === null || _this$imageFile2 === void 0 ? void 0 : _this$imageFile2.title();
2816
+ },
2817
+ imageFile() {
2818
+ return this.collection.entry.imageFiles.getByPermaId(this.get('image'));
2819
+ }
2820
+ });
2821
+
2822
+ const ItemsCollection = Backbone.Collection.extend({
2823
+ model: Item,
2824
+ comparator: 'position',
2825
+ initialize(models, options) {
2826
+ this.entry = options.entry;
2827
+ this.contentElement = options.contentElement;
2828
+ this.listenTo(this, 'add change remove sort', this.updateConfiguration);
2829
+ this.listenTo(this, 'remove', this.pruneCaptions);
2830
+ },
2831
+ updateConfiguration() {
2832
+ this.contentElement.configuration.set('items', this.toJSON());
2833
+ },
2834
+ pruneCaptions() {
2835
+ this.contentElement.configuration.set('captions', _.pick(this.contentElement.configuration.get('captions') || {}, ...this.pluck('id')));
2836
+ },
2837
+ selectImage() {
2838
+ editor$1.selectFile('image_files', 'newImageGalleryItem', {
2839
+ id: this.contentElement.id
2840
+ });
2841
+ },
2842
+ addWithId(imageFile) {
2843
+ this.add({
2844
+ id: this.length ? Math.max(...this.pluck('id')) + 1 : 1,
2845
+ image: imageFile.get('perma_id')
2846
+ });
2847
+ },
2848
+ saveOrder() {}
2849
+ });
2850
+ ItemsCollection.forContentElement = function (contentElement, entry) {
2851
+ return new ItemsCollection(contentElement.configuration.get('items') || [], {
2852
+ entry: entry,
2853
+ contentElement: contentElement
2854
+ });
2855
+ };
2856
+ const FileSelectionHandler = function (options) {
2857
+ const contentElement = options.entry.contentElements.get(options.id);
2858
+ this.call = function (file) {
2859
+ ItemsCollection.forContentElement(contentElement).addWithId(file);
2860
+ };
2861
+ this.getReferer = function () {
2862
+ return '/scrolled/content_elements/' + contentElement.id;
2863
+ };
2864
+ };
2865
+ editor$1.registerFileSelectionHandler('newImageGalleryItem', FileSelectionHandler);
2866
+
2867
+ const SidebarRouter$2 = Marionette.AppRouter.extend({
2868
+ appRoutes: {
2869
+ 'scrolled/imageGalleries/:id/:item_id': 'item'
2870
+ }
2871
+ });
2872
+
2873
+ const SidebarEditItemView = EditConfigurationView.extend({
2874
+ translationKeyPrefix: 'pageflow_scrolled.editor.content_elements.imageGallery.edit_item',
2875
+ containingCollection() {
2876
+ return this.options.collection;
2877
+ },
2878
+ getConfigurationModel() {
2879
+ return this.model;
2880
+ },
2881
+ goBackPath() {
2882
+ return `/scrolled/content_elements/${this.options.contentElement.get('id')}`;
2883
+ },
2884
+ getActionsMenuItems() {
2885
+ return [new DestroyItemMenuItem({}, {
2886
+ collection: this.options.collection,
2887
+ model: this.model
2888
+ })];
2889
+ },
2890
+ configure(configurationEditor) {
2891
+ const contentElement = this.options.contentElement;
2892
+ configurationEditor.tab('item', function () {
2893
+ this.input('image', FileInputView, {
2894
+ collection: 'image_files',
2895
+ fileSelectionHandler: 'imageGalleryItem',
2896
+ fileSelectionHandlerOptions: {
2897
+ contentElementId: contentElement.get('id')
2898
+ },
2899
+ positioning: false
2900
+ });
2901
+ this.input('portraitImage', FileInputView, {
2902
+ collection: 'image_files',
2903
+ fileSelectionHandler: 'imageGalleryItem',
2904
+ fileSelectionHandlerOptions: {
2905
+ contentElementId: contentElement.get('id')
2906
+ },
2907
+ positioning: false
2908
+ });
2909
+ });
2910
+ }
2911
+ });
2912
+ const DestroyItemMenuItem = DestroyMenuItem.extend({
2913
+ translationKeyPrefix: 'pageflow_scrolled.editor.content_elements.imageGallery.edit_item',
2914
+ destroyModel() {
2915
+ this.options.collection.remove(this.options.model);
2916
+ }
2917
+ });
2918
+
2919
+ const SidebarController$2 = Marionette.Controller.extend({
2920
+ initialize: function (options) {
2921
+ this.entry = options.entry;
2922
+ this.region = options.region;
2923
+ },
2924
+ item: function (id, itemId) {
2925
+ const contentElement = this.entry.contentElements.get(id);
2926
+ const itemsCollection = ItemsCollection.forContentElement(contentElement, this.entry);
2927
+ this.region.show(new SidebarEditItemView({
2928
+ model: itemsCollection.get(itemId),
2929
+ collection: itemsCollection,
2930
+ entry: this.entry,
2931
+ contentElement
2932
+ }));
2933
+ }
2934
+ });
2935
+
2936
+ var img$g = "data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 576 512'%3e%3c!--! Font Awesome Pro 6.4.0 by %40fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons%2c Inc. --%3e%3cpath fill='white' d='M160 32c-35.3 0-64 28.7-64 64V320c0 35.3 28.7 64 64 64H512c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64H160zM396 138.7l96 144c4.9 7.4 5.4 16.8 1.2 24.6S480.9 320 472 320H328 280 200c-9.2 0-17.6-5.3-21.6-13.6s-2.9-18.2 2.9-25.4l64-80c4.6-5.7 11.4-9 18.7-9s14.2 3.3 18.7 9l17.3 21.6 56-84C360.5 132 368 128 376 128s15.5 4 20 10.7zM192 128a32 32 0 1 1 64 0 32 32 0 1 1 -64 0zM48 120c0-13.3-10.7-24-24-24S0 106.7 0 120V344c0 75.1 60.9 136 136 136H456c13.3 0 24-10.7 24-24s-10.7-24-24-24H136c-48.6 0-88-39.4-88-88V120z'/%3e%3c/svg%3e";
2937
+
2938
+ editor.registerSideBarRouting({
2939
+ router: SidebarRouter$2,
2940
+ controller: SidebarController$2
2941
+ });
2942
+ editor.contentElementTypes.register('imageGallery', {
2943
+ pictogram: img$g,
2944
+ category: 'media',
2945
+ supportedPositions: ['inline', 'side', 'sticky', 'standAlone', 'left', 'right'],
2946
+ supportedWidthRange: ['xxs', 'full'],
2947
+ supportedCaptions: {
2948
+ disableWhenNoCaption: false
2949
+ },
2950
+ supportedStyles: ['boxShadow', 'outline'],
2951
+ configurationPlace(contentElement, path) {
2952
+ const [propertyName, index, itemProperty] = path;
2953
+ if (propertyName !== 'items') {
2954
+ return;
2955
+ }
2956
+ const item = contentElement.configuration.get('items')[index];
2957
+ return {
2958
+ label: attributeLabel$1(itemProperty),
2959
+ select() {
2960
+ contentElement.postCommand({
2961
+ type: 'SET_CURRENT_ITEM',
2962
+ index: Number(index)
2963
+ });
2964
+ contentElement.select({
2965
+ navigate: false
2966
+ });
2967
+ editor.navigate(`/scrolled/imageGalleries/${contentElement.id}/${item.id}`, {
2968
+ trigger: true
2969
+ });
2970
+ }
2971
+ };
2972
+ },
2973
+ configurationEditor({
2974
+ entry,
2975
+ contentElement
2976
+ }) {
2977
+ this.tab('general', function () {
2978
+ this.view(ItemsListView, {
2979
+ contentElement,
2980
+ collection: ItemsCollection.forContentElement(this.model.parent, entry)
2981
+ });
2982
+ this.input('displayPeeks', CheckBoxInputView$1, {
2983
+ storeInverted: 'hidePeeks'
2984
+ });
2985
+ this.input('displayPaginationIndicator', CheckBoxInputView$1);
2986
+ this.input('enableFullscreenOnDesktop', CheckBoxInputView$1, {
2987
+ disabledBinding: ['position', 'width'],
2988
+ disabled: () => contentElement.getWidth() === contentElementWidths.full,
2989
+ displayUncheckedIfDisabled: true
2990
+ });
2991
+ this.group('ContentElementPosition', {
2992
+ entry
2993
+ });
2994
+ this.view(SeparatorView$1);
2995
+ this.group('ContentElementCaption', {
2996
+ entry,
2997
+ disableWhenNoCaption: false
2998
+ });
2999
+ this.group('ContentElementInlineFileRightsSettings', {
3000
+ entry,
3001
+ disableWhenNoFileRights: false
3002
+ });
3003
+ });
3004
+ },
3005
+ defaultConfig: {
3006
+ displayPaginationIndicator: true
3007
+ }
3008
+ });
3009
+ editor.registerFileSelectionHandler('imageGalleryItem', function (options) {
3010
+ const contentElement = options.entry.contentElements.get(options.contentElementId);
3011
+ const items = ItemsCollection.forContentElement(contentElement, options.entry);
3012
+ this.call = function (file) {
3013
+ items.get(options.id).setReference(options.attributeName, file);
3014
+ };
3015
+ this.getReferer = function () {
3016
+ return '/scrolled/imageGalleries/' + contentElement.id + '/' + options.id;
3017
+ };
3018
+ });
3019
+ function attributeLabel$1(propertyName) {
3020
+ return I18n.t(`${propertyName}.label`, {
3021
+ scope: 'pageflow_scrolled.editor.content_elements.imageGallery.edit_item.attributes'
3022
+ });
3023
+ }
3024
+
3025
+ const LottieFile = UploadableFile.extend({
3026
+ isPositionable: function () {
3027
+ return this.isReady();
3028
+ }
3029
+ });
3030
+
3031
+ // Prevent the player from fetching its WebAssembly module from a CDN.
3032
+ // Frontend and editor run in separate bundles and thus each need to
3033
+ // point the player at the module emitted by their own build.
3034
+ DotLottie.setWasmUrl(wasmUrl);
3035
+
3036
+ // Base class for views which play a lottie file. Sub classes render a
3037
+ // canvas, return the options the player shall be created with from
3038
+ // `playerOptions` and use `onAnimationLoad` for everything that
3039
+ // requires the player to have read the file.
3040
+ const LottieFilePlayerView = Marionette.ItemView.extend({
3041
+ ui: {
3042
+ canvas: 'canvas'
3043
+ },
3044
+ onRender: function () {
3045
+ // Sub classes size themselves based on dimensions which only the
3046
+ // animation provides. The canvas stays invisible until the player
3047
+ // has read them. Taking it out of the layout instead would let the
3048
+ // surrounding box collapse and jump back open.
3049
+ this.$el.css('visibility', 'hidden');
3050
+ this.player = new DotLottie({
3051
+ canvas: this.ui.canvas[0],
3052
+ src: this.model.get('original_url'),
3053
+ renderConfig: {
3054
+ autoResize: true
3055
+ },
3056
+ ...this.playerOptions()
831
3057
  });
3058
+ this.player.addEventListener('load', () => {
3059
+ this.onAnimationLoad();
3060
+
3061
+ // The player has already drawn a frame into a canvas of the size
3062
+ // the view had before. It only notices the new size via a resize
3063
+ // observer, which fires too late to keep the frame from being
3064
+ // stretched into the new box.
3065
+ this.player.resize();
3066
+ this.$el.css('visibility', '');
3067
+ });
3068
+ },
3069
+ playerOptions: function () {
3070
+ return {};
3071
+ },
3072
+ onAnimationLoad: function () {},
3073
+ onClose: function () {
3074
+ this.player.destroy();
832
3075
  }
833
3076
  });
834
- editor.fileTypes.modify('image_files', {
835
- configurationEditorInputs: function configurationEditorInputs(model) {
836
- var values = ['equirectangular_mono', 'equirectangular_stereo'];
837
- return [{
838
- name: 'projection',
839
- inputView: SelectInputView$1,
840
- inputViewOptions: {
841
- includeBlank: true,
842
- values: values
843
- }
844
- }];
3077
+
3078
+ var css$7 = ".LottieFilePositioningView-module_cover__3ZKEB {\n display: block;\n width: 100%;\n height: 100%;\n}\n\n/* A max height would squash the canvas instead of scaling it down,\n since the aspect ratio only determines the height before it is\n clamped. Limiting the width covers both directions. */\n.LottieFilePositioningView-module_contain__2UeDA {\n display: block;\n width: var(--positioning-width, 100%);\n max-width: min(var(--positioning-max-width, 100%),\n var(--positioning-max-height, 100vh) *\n var(--positioning-aspect-ratio, 1));\n aspect-ratio: var(--positioning-aspect-ratio, 1);\n}\n\n.LottieFilePositioningView-module_canvas__3OxWg {\n display: block;\n width: 100%;\n height: 100%;\n}\n";
3079
+ var styles$7 = {"cover":"LottieFilePositioningView-module_cover__3ZKEB","contain":"LottieFilePositioningView-module_contain__2UeDA","canvas":"LottieFilePositioningView-module_canvas__3OxWg"};
3080
+ styleInject(css$7);
3081
+
3082
+ const LottieFilePositioningView = LottieFilePlayerView.extend({
3083
+ template: () => `<canvas class="${styles$7.canvas}"></canvas>`,
3084
+ className: function () {
3085
+ return styles$7[this.options.fit];
845
3086
  },
846
- confirmUploadTableColumns: [{
847
- name: 'projection',
848
- cellView: EnumTableCellView
849
- }],
850
- filters: [{
851
- name: 'with_projection',
852
- matches: function matches(file) {
853
- return !!file.configuration.get('projection');
3087
+ playerOptions: function () {
3088
+ return {
3089
+ autoplay: true,
3090
+ loop: true,
3091
+ layout: this.layout()
3092
+ };
3093
+ },
3094
+ setPosition: function (x, y) {
3095
+ this.align = [x / 100, y / 100];
3096
+ this.player.setLayout(this.layout());
3097
+ },
3098
+ // The player ignores layout changes as long as it is still reading
3099
+ // the file.
3100
+ onAnimationLoad: function () {
3101
+ this.player.setLayout(this.layout());
3102
+ this.applyDimensions();
3103
+ },
3104
+ layout: function () {
3105
+ return {
3106
+ fit: this.options.fit,
3107
+ align: this.align
3108
+ };
3109
+ },
3110
+ // Unlike images and videos, lottie files have no dimensions stored on
3111
+ // the server. The box can thus only be sized once the player has read
3112
+ // them from the file.
3113
+ applyDimensions: function () {
3114
+ var size = this.player.animationSize();
3115
+ if (size.width && size.height) {
3116
+ this.el.style.setProperty('--positioning-aspect-ratio', `${size.width / size.height}`);
3117
+ this.el.style.setProperty('--positioning-width', `${size.width}px`);
854
3118
  }
855
- }]
3119
+ }
3120
+ });
3121
+
3122
+ var css$8 = "/* Scaled down to whatever height the overlay has left, just like the\n image and video previews. The player keeps the animation centered\n inside the canvas, so a clamped height only adds transparent space\n left and right. */\n.LottieFilePreviewView-module_canvas__h1U-D {\n display: block;\n width: 100%;\n max-width: var(--preview-width, 100%);\n max-height: var(--preview-max-height, none);\n margin: 0 auto;\n aspect-ratio: var(--preview-aspect-ratio, 1);\n}\n";
3123
+ var styles$8 = {"canvas":"LottieFilePreviewView-module_canvas__h1U-D"};
3124
+ styleInject(css$8);
3125
+
3126
+ const LottieFilePreviewView = LottieFilePlayerView.extend({
3127
+ template: () => `<canvas class="${styles$8.canvas}"></canvas>`,
3128
+ className: 'file_preview',
3129
+ playerOptions: function () {
3130
+ return {
3131
+ autoplay: true,
3132
+ loop: true
3133
+ };
3134
+ },
3135
+ // Unlike images and videos, lottie files have no dimensions stored on
3136
+ // the server. The box can thus only be sized once the player has read
3137
+ // them from the file.
3138
+ onAnimationLoad: function () {
3139
+ var size = this.player.animationSize();
3140
+ if (size.width && size.height) {
3141
+ this.ui.canvas[0].style.setProperty('--preview-aspect-ratio', `${size.width} / ${size.height}`);
3142
+ this.ui.canvas[0].style.setProperty('--preview-width', `${size.width}px`);
3143
+ }
3144
+ }
856
3145
  });
857
3146
 
858
- var img$b = "data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 640 512'%3e%3c!--! Font Awesome Pro 6.1.1 by %40fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons%2c Inc. --%3e%3cpath fill='white' d='M414.8 40.79L286.8 488.8C281.9 505.8 264.2 515.6 247.2 510.8C230.2 505.9 220.4 488.2 225.2 471.2L353.2 23.21C358.1 6.216 375.8-3.624 392.8 1.232C409.8 6.087 419.6 23.8 414.8 40.79H414.8zM518.6 121.4L630.6 233.4C643.1 245.9 643.1 266.1 630.6 278.6L518.6 390.6C506.1 403.1 485.9 403.1 473.4 390.6C460.9 378.1 460.9 357.9 473.4 345.4L562.7 256L473.4 166.6C460.9 154.1 460.9 133.9 473.4 121.4C485.9 108.9 506.1 108.9 518.6 121.4V121.4zM166.6 166.6L77.25 256L166.6 345.4C179.1 357.9 179.1 378.1 166.6 390.6C154.1 403.1 133.9 403.1 121.4 390.6L9.372 278.6C-3.124 266.1-3.124 245.9 9.372 233.4L121.4 121.4C133.9 108.9 154.1 108.9 166.6 121.4C179.1 133.9 179.1 154.1 166.6 166.6V166.6z'/%3e%3c/svg%3e";
3147
+ var css$9 = ".LottieFileThumbnailView-module_thumbnail__2joie,\n.LottieFileThumbnailView-module_canvas__1Aby1 {\n display: block;\n width: 100%;\n height: 100%;\n}\n";
3148
+ var styles$9 = {"thumbnail":"LottieFileThumbnailView-module_thumbnail__2joie","canvas":"LottieFileThumbnailView-module_canvas__1Aby1"};
3149
+ styleInject(css$9);
3150
+
3151
+ const LottieFileThumbnailView = LottieFilePlayerView.extend({
3152
+ template: () => `<canvas class="${styles$9.canvas}"></canvas>`,
3153
+ className: styles$9.thumbnail,
3154
+ playerOptions: function () {
3155
+ return {
3156
+ autoplay: false,
3157
+ layout: {
3158
+ fit: 'cover'
3159
+ }
3160
+ };
3161
+ },
3162
+ // Animations commonly build up their scene over time, which would
3163
+ // leave the thumbnail close to blank on the first frame the player
3164
+ // draws once it has loaded the file.
3165
+ onAnimationLoad: function () {
3166
+ this.player.setFrame(this.player.totalFrames - 1);
3167
+ }
3168
+ });
859
3169
 
860
- var aspectRatios = ['wide', 'narrow', 'square', 'portrait'];
861
- editor.contentElementTypes.register('iframeEmbed', {
862
- pictogram: img$b,
863
- category: 'interactive',
864
- featureName: 'iframe_embed_content_element',
865
- supportedPositions: ['inline', 'sticky', 'standAlone', 'left', 'right'],
3170
+ var img$h = "data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='white' d='M400 176a72 72 0 1 1-144 0 72 72 0 0 1 144 0zM240 288a44 44 0 1 1-88 0 44 44 0 0 1 88 0zM136 384a28 28 0 1 1-56 0 28 28 0 0 1 56 0zM72 448a16 16 0 1 1-32 0 16 16 0 0 1 32 0z'/%3e%3c/svg%3e";
3171
+
3172
+ editor.fileTypes.register('lottie_files', {
3173
+ model: LottieFile,
3174
+ positioningView: LottieFilePositioningView,
3175
+ previewView: LottieFilePreviewView,
3176
+ thumbnailView: LottieFileThumbnailView,
3177
+ metaDataAttributes: [altMetaDataAttribute],
3178
+ configurationEditorInputs: [altConfigurationEditorInput],
3179
+ // Browsers derive the content type of uploads from the file
3180
+ // extension. Since dotLottie is missing from their mappings, uploads
3181
+ // have an empty content type and matching by name is the only option.
3182
+ matchUpload: upload => /\.lottie$/i.test(upload.name)
3183
+ });
3184
+ const playbackModes = ['loop', 'playOnce', 'scroll'];
3185
+ const startAnimationTriggers = ['onActivate', 'onVisible'];
3186
+ const scrollRanges = ['cover', 'contain', 'inFocus', 'entry'];
3187
+ const pinnedPositions = ['sticky', 'standAlone'];
3188
+ const scrollRangeValuesKey = 'pageflow_scrolled.editor.content_elements.lottieAnimation.attributes.scrollRange.values';
3189
+ const pinnedScrollRangeKeys = ['cover', 'contain', 'inFocusWhenPinned', 'entry'].map(name => `${scrollRangeValuesKey}.${name}`);
3190
+ editor.contentElementTypes.register('lottieAnimation', {
3191
+ pictogram: img$h,
3192
+ category: 'media',
3193
+ featureName: 'lottie_animation_content_element',
3194
+ supportedPositions: ['inline', 'side', 'sticky', 'standAlone', 'left', 'right'],
866
3195
  supportedWidthRange: ['xxs', 'full'],
867
- configurationEditor: function configurationEditor(_ref) {
868
- var entry = _ref.entry;
3196
+ supportedCaptions: true,
3197
+ supportedStyles: ['boxShadow', 'outline'],
3198
+ defaultConfig: {
3199
+ playbackMode: 'loop'
3200
+ },
3201
+ defaultsInputs() {
3202
+ this.input('playbackMode', SelectInputView, {
3203
+ values: playbackModes
3204
+ });
3205
+ },
3206
+ configurationEditor({
3207
+ entry,
3208
+ contentElement
3209
+ }) {
869
3210
  this.tab('general', function () {
870
- this.input('source', TextInputView);
871
- this.input('requireConsent', CheckBoxInputView$1);
872
- this.view(InfoBoxView, {
873
- level: 'error',
874
- text: I18n.t('pageflow_scrolled.editor.content_elements.iframeEmbed.help_texts.missingConsentVendor'),
875
- visibleBinding: ['source', 'requireConsent'],
876
- visible: function visible(_ref2) {
877
- var _ref3 = _slicedToArray(_ref2, 2),
878
- source = _ref3[0],
879
- requireConsent = _ref3[1];
3211
+ this.input('id', FileInputView, {
3212
+ collection: 'lottie_files',
3213
+ fileSelectionHandler: 'contentElementConfiguration',
3214
+ positioning: imageModifiers => !!processImageModifiers(imageModifiers).aspectRatio,
3215
+ positioningBinding: 'imageModifiers',
3216
+ positioningOptions: () => {
3217
+ const {
3218
+ aspectRatio
3219
+ } = processImageModifiers(this.model.get('imageModifiers'));
3220
+ return {
3221
+ preview: aspectRatio && 1 / entry.getAspectRatio(aspectRatio)
3222
+ };
3223
+ },
3224
+ dropDownMenuItems: [InlineFileRightsMenuItem]
3225
+ });
3226
+ this.input('imageModifiers', ImageModifierListInputView, {
3227
+ entry,
3228
+ visibleBinding: 'id',
3229
+ visible: () => this.model.getReference('id', 'lottie_files')
3230
+ });
3231
+ this.input('playbackMode', SelectInputView, {
3232
+ values: playbackModes
3233
+ });
3234
+ this.input('startAnimationTrigger', PlaybackStartSelectInputView, {
3235
+ values: startAnimationTriggers,
3236
+ ...illustrationOptions(contentElement),
3237
+ visibleBinding: 'playbackMode',
3238
+ visible: playbackMode => playbackMode === 'playOnce'
3239
+ });
3240
+ // Elements that stay in place while scrolling name the inFocus
3241
+ // range after that phase instead of after the center of the
3242
+ // viewport. Since the texts of a select cannot depend on other
3243
+ // attributes, there is one input per wording.
3244
+ this.input('scrollRange', ScrollRangeSelectInputView, {
3245
+ values: scrollRanges,
3246
+ ...illustrationOptions(contentElement),
3247
+ visibleBinding: ['playbackMode', 'position'],
3248
+ visible: ([playbackMode]) => playbackMode === 'scroll' && !staysInPlace(contentElement)
3249
+ });
3250
+ this.input('scrollRange', ScrollRangeSelectInputView, {
3251
+ values: scrollRanges,
3252
+ translationKeys: pinnedScrollRangeKeys,
3253
+ ...illustrationOptions(contentElement),
3254
+ visibleBinding: ['playbackMode', 'position'],
3255
+ visible: ([playbackMode]) => playbackMode === 'scroll' && staysInPlace(contentElement)
3256
+ });
3257
+ this.view(SeparatorView);
3258
+ this.group('ContentElementPosition', {
3259
+ entry
3260
+ });
3261
+ this.view(SeparatorView);
3262
+ this.group('ContentElementCaption', {
3263
+ entry
3264
+ });
3265
+ this.group('ContentElementInlineFileRightsSettings');
3266
+ });
3267
+ }
3268
+ });
3269
+
3270
+ // Layouts that do not support sticky position render such elements
3271
+ // inline, which does not keep them in place while scrolling.
3272
+ function staysInPlace(contentElement) {
3273
+ return pinnedPositions.includes(contentElement.getResolvedPosition());
3274
+ }
3275
+
3276
+ // Illustrate options with the element as it looks in its section.
3277
+ function illustrationOptions(contentElement) {
3278
+ return {
3279
+ position: () => contentElement.getResolvedPosition(),
3280
+ sectionLayout: () => contentElement.section.configuration.get('layout')
3281
+ };
3282
+ }
880
3283
 
881
- return source && requireConsent && !entry.consentVendors.fromUrl(source);
3284
+ var img$i = "data:image/svg+xml,%3csvg version='1.1' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e %3cpath fill='white' d='m 63.5%2c52 c -35%2c0 -63%2c29 -63%2c64 v 280 c 0%2c35 28%2c64 63%2c64 H 447 c 35%2c0 65%2c-29 65%2c-64 V 116 C 512%2c81 483%2c52 447%2c52 Z m 78.5%2c80 c 51%2c0 93%2c42 93%2c93 0%2c51 -42%2c93 -93%2c93 -51.4%2c0 -93%2c-42 -93%2c-93 0%2c-51 41.6%2c-93 93%2c-93 z m 172%2c15 h 113 c 19%2c0 34%2c15 34%2c34 0%2c19 -15%2c34 -34%2c34 H 314 c -19%2c0 -34%2c-15 -34%2c-34 0%2c-19 15%2c-34 34%2c-34 z m -13%2c111 h 116 c 11%2c0 21%2c10 21%2c21 0%2c12 -10%2c22 -21%2c22 H 301 c -11%2c0 -21%2c-10 -21%2c-22 0%2c-11 10%2c-21 21%2c-21 z'/%3e%3c/svg%3e";
3285
+
3286
+ function processBlueskyOembed(oembedResponse) {
3287
+ var parser = new DOMParser();
3288
+ var doc = parser.parseFromString(oembedResponse.html, 'text/html');
3289
+ var blockquote = doc.querySelector('blockquote.bluesky-embed');
3290
+ if (blockquote) {
3291
+ var dataUri = blockquote.getAttribute('data-bluesky-uri');
3292
+ if (dataUri) {
3293
+ return dataUri;
3294
+ }
3295
+ }
3296
+
3297
+ // Fallback to original URL if extraction fails
3298
+ return oembedResponse.url;
3299
+ }
3300
+
3301
+ editor.contentElementTypes.register('socialEmbed', {
3302
+ pictogram: img$i,
3303
+ category: 'media',
3304
+ supportedPositions: ['inline', 'side', 'sticky', 'standAlone', 'left', 'right'],
3305
+ featureName: 'social_embed_content_element',
3306
+ defaultConfig: {
3307
+ provider: 'bluesky'
3308
+ },
3309
+ configurationEditor({
3310
+ entry
3311
+ }) {
3312
+ this.tab('general', function () {
3313
+ this.input('provider', SelectInputView, {
3314
+ values: ['bluesky', 'instagram', 'tiktok', 'x']
3315
+ });
3316
+ this.input('url', OembedUrlInputView, {
3317
+ displayPropertyName: 'displayPostId',
3318
+ providerNameProperty: 'provider',
3319
+ providers: {
3320
+ bluesky: {
3321
+ supportedHosts: ['bsky.app', 'bsky.social'],
3322
+ transform: processBlueskyOembed
3323
+ },
3324
+ instagram: {
3325
+ supportedHosts: ['instagram.com', 'www.instagram.com'],
3326
+ skipOembedValidation: true
3327
+ },
3328
+ x: {
3329
+ supportedHosts: ['twitter.com', 'www.twitter.com', 'x.com', 'www.x.com'],
3330
+ skipOembedValidation: true
3331
+ },
3332
+ tiktok: {
3333
+ supportedHosts: ['https://www.tiktok.com'],
3334
+ skipOembedValidation: true
3335
+ }
882
3336
  }
883
3337
  });
884
- this.input('title', TextInputView);
885
- this.input('aspectRatio', SelectInputView, {
886
- values: aspectRatios
3338
+ this.group('ContentElementPosition', {
3339
+ entry
887
3340
  });
888
- this.input('portraitAspectRatio', SelectInputView, {
889
- includeBlank: true,
890
- blankTranslationKey: 'pageflow_scrolled.editor.' + 'content_elements.iframeEmbed.' + 'attributes.portraitAspectRatio.blank',
891
- values: aspectRatios
3341
+ this.input('hideConversation', CheckBoxInputView, {
3342
+ visibleBinding: 'provider',
3343
+ visibleBindingValue: 'x'
892
3344
  });
893
- this.input('scale', SelectInputView, {
894
- values: ['p100', 'p75', 'p50', 'p33']
3345
+ this.input('hideMedia', CheckBoxInputView, {
3346
+ visibleBinding: 'provider',
3347
+ visibleBindingValue: 'x'
895
3348
  });
896
- this.group('ContentElementPosition');
897
3349
  });
898
3350
  }
899
3351
  });
900
3352
 
901
- var img$c = "data:image/svg+xml,%3csvg version='1.1' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e %3cpath fill='white' d='M389.2 48h70.6L305.6 224.2 487 464H345L233.7 318.6 106.5 464H35.8L200.7 275.5 26.8 48H172.4L272.9 180.9 389.2 48zM364.4 421.8h39.1L151.1 88h-42L364.4 421.8z'/%3e%3c/svg%3e";
3353
+ var img$j = "data:image/svg+xml,%3csvg version='1.1' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e %3cpath fill='white' d='M389.2 48h70.6L305.6 224.2 487 464H345L233.7 318.6 106.5 464H35.8L200.7 275.5 26.8 48H172.4L272.9 180.9 389.2 48zM364.4 421.8h39.1L151.1 88h-42L364.4 421.8z'/%3e%3c/svg%3e";
902
3354
 
903
3355
  editor.contentElementTypes.register('twitterEmbed', {
904
- pictogram: img$c,
3356
+ pictogram: img$j,
905
3357
  category: 'media',
906
- supportedPositions: ['inline', 'sticky', 'standAlone', 'left', 'right'],
907
- configurationEditor: function configurationEditor() {
3358
+ featureName: 'legacy_social_embed_content_elements',
3359
+ supportedPositions: ['inline', 'side', 'sticky', 'standAlone', 'left', 'right'],
3360
+ configurationEditor({
3361
+ entry
3362
+ }) {
908
3363
  this.tab('general', function () {
909
3364
  this.input('url', UrlInputView, {
910
3365
  supportedHosts: ['http://twitter.com', 'https://twitter.com', 'http://x.com', 'https://x.com'],
@@ -912,9 +3367,11 @@ editor.contentElementTypes.register('twitterEmbed', {
912
3367
  required: true,
913
3368
  permitHttps: true
914
3369
  });
915
- this.group('ContentElementPosition');
916
- this.input('hideConversation', CheckBoxInputView$1);
917
- this.input('hideMedia', CheckBoxInputView$1);
3370
+ this.group('ContentElementPosition', {
3371
+ entry
3372
+ });
3373
+ this.input('hideConversation', CheckBoxInputView);
3374
+ this.input('hideMedia', CheckBoxInputView);
918
3375
  });
919
3376
  },
920
3377
  defaultConfig: {
@@ -922,112 +3379,260 @@ editor.contentElementTypes.register('twitterEmbed', {
922
3379
  }
923
3380
  });
924
3381
 
925
- var img$d = "data:image/svg+xml,%3c%3fxml version='1.0' encoding='UTF-8' standalone='no'%3f%3e%3csvg xmlns:svg='http://www.w3.org/2000/svg' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512' version='1.1'%3e %3cpath style='fill:white%3bstroke-width:1.0715934' d='M 154.45629%2c72.962988 C 141.76916%2c73.980674 134.17753%2c85.77696 126.39089%2c94.31369 115.08265%2c105.89861 104.03984%2c117.73757 92.93941%2c129.52047 75.031239%2c111.21828 59.122369%2c90.77981 39.104383%2c74.658023 24.482281%2c67.834512 6.4140221%2c83.81238 10.775786%2c99.1746 c 2.708951%2c12.98866 15.286417%2c19.97415 22.964661%2c29.74046 17.657732%2c17.41285 32.403074%2c38.12856 52.621136%2c52.73529 10.829773%2c3.83939 22.062597%2c-3.51996 28.134937%2c-12.18527 19.44195%2c-22.50249 42.21653%2c-42.18327 59.90279%2c-66.14032 5.6424%2c-13.25737 -5.31055%2c-30.615753 -19.94302%2c-30.361772 z' /%3e %3cpath style='fill:white' d='M 256%2c428 H 31.999999 C 14.329999%2c428 -9.5000001e-7%2c442.33 -9.5000001e-7%2c460 -9.5000001e-7%2c477.67 14.329999%2c492 31.999999%2c492 H 256 c 17.7%2c0 32%2c-14.33 32%2c-32 0%2c-17.67 -14.3%2c-32 -32%2c-32 z M -9.5000001e-7%2c332 C -9.5000001e-7%2c349.7 14.329999%2c364 31.999999%2c364 H 416 c 17.7%2c0 32%2c-14.3 32%2c-32 0%2c-17.7 -14.3%2c-32 -32%2c-32 H 31.999999 C 14.329999%2c300 -9.5000001e-7%2c314.3 -9.5000001e-7%2c332 Z' /%3e %3cpath style='fill:white%3bstroke:white%3bstroke-width:0' d='m 356.05605%2c1.671899 c -22.75276%2c2.300391 -47.49513%2c-4.661754 -68.50543%2c6.450454 -16.00534%2c8.484395 -29.74636%2c27.036262 -24.98608%2c45.803882 5.50667%2c15.699356 29.05588%2c21.427535 39.82967%2c7.900392 4.46727%2c-4.523763 5.45002%2c-13.464333 13.29935%2c-12.285569 15.47565%2c-0.207336 30.89377%2c0.32159 46.37678%2c-0.223975 7.3323%2c-0.346315 15.23462%2c5.874856 12.62272%2c13.740223 -2.68086%2c9.147994 -13.45058%2c10.823444 -20.24491%2c15.836144 -11.40111%2c6.6584 -24.83231%2c11.40873 -32.94777%2c22.30075 -5.41404%2c11.18313 -4.76974%2c25.17905 -0.0141%2c36.40876 8.15241%2c13.79679 31.57231%2c15.50575 40.17388%2c0.85347 4.19853%2c-4.46787 1.87713%2c-12.57946 8.75385%2c-14.22118 18.79687%2c-10.20424 40.72904%2c-20.78924 48.43263%2c-42.36648 C 431.32621%2c52.120851 413.71956%2c13.332394 382.01823%2c4.732093 373.62266%2c2.216616 364.78493%2c1.519639 356.05609%2c1.671899 Z M 341.22896%2c172.48634 c -21.90876%2c-0.63629 -38.00737%2c26.58485 -26.67177%2c45.4856 9.43025%2c18.07827 37.60246%2c22.17393 50.69123%2c5.8469 12.093%2c-13.5735 9.43272%2c-37.5803 -6.86539%2c-46.64791 -5.10378%2c-3.1728 -11.1363%2c-4.88155 -17.15407%2c-4.68459 z' /%3e%3c/svg%3e";
3382
+ var img$k = "data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512'%3e%3c!--!Font Awesome Free 6.5.2 by %40fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons%2c Inc.--%3e%3cpath fill='white' d='M448 209.9a210.1 210.1 0 0 1 -122.8-39.3V349.4A162.6 162.6 0 1 1 185 188.3V278.2a74.6 74.6 0 1 0 52.2 71.2V0l88 0a121.2 121.2 0 0 0 1.9 22.2h0A122.2 122.2 0 0 0 381 102.4a121.4 121.4 0 0 0 67 20.1z'/%3e%3c/svg%3e";
3383
+
3384
+ editor.contentElementTypes.register('tikTokEmbed', {
3385
+ pictogram: img$k,
3386
+ category: 'media',
3387
+ featureName: 'legacy_social_embed_content_elements',
3388
+ supportedPositions: ['inline', 'side', 'sticky', 'standAlone', 'left', 'right'],
3389
+ supportedWidthRange: ['md', 'full'],
3390
+ configurationEditor({
3391
+ entry
3392
+ }) {
3393
+ this.tab('general', function () {
3394
+ this.input('url', UrlInputView, {
3395
+ supportedHosts: ['https://www.tiktok.com'],
3396
+ displayPropertyName: 'displayUrl',
3397
+ required: true,
3398
+ permitHttps: true
3399
+ });
3400
+ this.group('ContentElementPosition', {
3401
+ entry
3402
+ });
3403
+ });
3404
+ },
3405
+ defaultConfig: {}
3406
+ });
3407
+
3408
+ var img$l = "data:image/svg+xml,%3c%3fxml version='1.0' encoding='UTF-8' standalone='no'%3f%3e%3csvg xmlns:svg='http://www.w3.org/2000/svg' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512' version='1.1'%3e %3cpath style='fill:white%3bstroke-width:1.0715934' d='M 154.45629%2c72.962988 C 141.76916%2c73.980674 134.17753%2c85.77696 126.39089%2c94.31369 115.08265%2c105.89861 104.03984%2c117.73757 92.93941%2c129.52047 75.031239%2c111.21828 59.122369%2c90.77981 39.104383%2c74.658023 24.482281%2c67.834512 6.4140221%2c83.81238 10.775786%2c99.1746 c 2.708951%2c12.98866 15.286417%2c19.97415 22.964661%2c29.74046 17.657732%2c17.41285 32.403074%2c38.12856 52.621136%2c52.73529 10.829773%2c3.83939 22.062597%2c-3.51996 28.134937%2c-12.18527 19.44195%2c-22.50249 42.21653%2c-42.18327 59.90279%2c-66.14032 5.6424%2c-13.25737 -5.31055%2c-30.615753 -19.94302%2c-30.361772 z' /%3e %3cpath style='fill:white' d='M 256%2c428 H 31.999999 C 14.329999%2c428 -9.5000001e-7%2c442.33 -9.5000001e-7%2c460 -9.5000001e-7%2c477.67 14.329999%2c492 31.999999%2c492 H 256 c 17.7%2c0 32%2c-14.33 32%2c-32 0%2c-17.67 -14.3%2c-32 -32%2c-32 z M -9.5000001e-7%2c332 C -9.5000001e-7%2c349.7 14.329999%2c364 31.999999%2c364 H 416 c 17.7%2c0 32%2c-14.3 32%2c-32 0%2c-17.7 -14.3%2c-32 -32%2c-32 H 31.999999 C 14.329999%2c300 -9.5000001e-7%2c314.3 -9.5000001e-7%2c332 Z' /%3e %3cpath style='fill:white%3bstroke:white%3bstroke-width:0' d='m 356.05605%2c1.671899 c -22.75276%2c2.300391 -47.49513%2c-4.661754 -68.50543%2c6.450454 -16.00534%2c8.484395 -29.74636%2c27.036262 -24.98608%2c45.803882 5.50667%2c15.699356 29.05588%2c21.427535 39.82967%2c7.900392 4.46727%2c-4.523763 5.45002%2c-13.464333 13.29935%2c-12.285569 15.47565%2c-0.207336 30.89377%2c0.32159 46.37678%2c-0.223975 7.3323%2c-0.346315 15.23462%2c5.874856 12.62272%2c13.740223 -2.68086%2c9.147994 -13.45058%2c10.823444 -20.24491%2c15.836144 -11.40111%2c6.6584 -24.83231%2c11.40873 -32.94777%2c22.30075 -5.41404%2c11.18313 -4.76974%2c25.17905 -0.0141%2c36.40876 8.15241%2c13.79679 31.57231%2c15.50575 40.17388%2c0.85347 4.19853%2c-4.46787 1.87713%2c-12.57946 8.75385%2c-14.22118 18.79687%2c-10.20424 40.72904%2c-20.78924 48.43263%2c-42.36648 C 431.32621%2c52.120851 413.71956%2c13.332394 382.01823%2c4.732093 373.62266%2c2.216616 364.78493%2c1.519639 356.05609%2c1.671899 Z M 341.22896%2c172.48634 c -21.90876%2c-0.63629 -38.00737%2c26.58485 -26.67177%2c45.4856 9.43025%2c18.07827 37.60246%2c22.17393 50.69123%2c5.8469 12.093%2c-13.5735 9.43272%2c-37.5803 -6.86539%2c-46.64791 -5.10378%2c-3.1728 -11.1363%2c-4.88155 -17.15407%2c-4.68459 z' /%3e%3c/svg%3e";
926
3409
 
927
3410
  editor.contentElementTypes.register('question', {
928
- pictogram: img$d,
3411
+ pictogram: img$l,
929
3412
  supportedPositions: ['inline'],
930
- configurationEditor: function configurationEditor(_ref) {
931
- var entry = _ref.entry,
932
- contentElement = _ref.contentElement;
3413
+ configurationEditor({
3414
+ entry,
3415
+ contentElement
3416
+ }) {
933
3417
  this.tab('general', function () {
934
- this.input('expandByDefault', CheckBoxInputView$1);
3418
+ const modelDelegator = entry.createLegacyTypographyVariantDelegator({
3419
+ model: this.model,
3420
+ paletteColorPropertyName: 'color'
3421
+ });
3422
+ this.group('ContentElementTypographyVariant', {
3423
+ entry,
3424
+ model: modelDelegator,
3425
+ getPreviewConfiguration: (configuration, typographyVariant) => ({
3426
+ ...configuration,
3427
+ expandByDefault: true,
3428
+ typographyVariant
3429
+ })
3430
+ });
3431
+ this.group('ContentElementTypographySize', {
3432
+ entry,
3433
+ model: modelDelegator,
3434
+ getPreviewConfiguration: (configuration, typographySize) => ({
3435
+ ...configuration,
3436
+ expandByDefault: true,
3437
+ // Ensure size in preview is not overridden by legacy variant
3438
+ typographyVariant: modelDelegator.get('typographyVariant'),
3439
+ typographySize
3440
+ })
3441
+ });
3442
+ this.group('PaletteColor', {
3443
+ entry,
3444
+ propertyName: 'color'
3445
+ });
3446
+ this.group('PaletteColor', {
3447
+ entry,
3448
+ propertyName: 'answerColor'
3449
+ });
3450
+ this.input('expandByDefault', CheckBoxInputView);
935
3451
  });
936
3452
  }
937
3453
  });
938
3454
 
939
- var img$e = "data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512'%3e%3cpath fill='white' d='M181.3 32.4c17.4 2.9 29.2 19.4 26.3 36.8L197.8 128h95.1l11.5-69.3c2.9-17.4 19.4-29.2 36.8-26.3s29.2 19.4 26.3 36.8L357.8 128H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H347.1L325.8 320H384c17.7 0 32 14.3 32 32s-14.3 32-32 32H315.1l-11.5 69.3c-2.9 17.4-19.4 29.2-36.8 26.3s-29.2-19.4-26.3-36.8l9.8-58.7H155.1l-11.5 69.3c-2.9 17.4-19.4 29.2-36.8 26.3s-29.2-19.4-26.3-36.8L90.2 384H32c-17.7 0-32-14.3-32-32s14.3-32 32-32h68.9l21.3-128H64c-17.7 0-32-14.3-32-32s14.3-32 32-32h68.9l11.5-69.3c2.9-17.4 19.4-29.2 36.8-26.3zM187.1 192L165.8 320h95.1l21.3-128H187.1z'/%3e%3c/svg%3e";
3455
+ const legacyTextSizes = {
3456
+ verySmall: 'xs',
3457
+ small: 'md',
3458
+ medium: 'xl',
3459
+ large: 'xxxl'
3460
+ };
3461
+ function createLegacyConfigurationDelegator(model) {
3462
+ const delegator = Object.create(model);
3463
+ delegator.get = function (name) {
3464
+ const result = model.get(name);
3465
+ if (name === 'numberSize') {
3466
+ return result || legacyTextSizes[model.get('textSize')];
3467
+ }
3468
+ if (name === 'countingAnimation') {
3469
+ const countingSpeed = model.get('countingSpeed');
3470
+ return result || (countingSpeed && countingSpeed !== 'none' ? 'plain' : undefined);
3471
+ }
3472
+ return result;
3473
+ };
3474
+ return delegator;
3475
+ }
3476
+
3477
+ var img$m = "data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512'%3e%3cpath fill='white' d='M181.3 32.4c17.4 2.9 29.2 19.4 26.3 36.8L197.8 128h95.1l11.5-69.3c2.9-17.4 19.4-29.2 36.8-26.3s29.2 19.4 26.3 36.8L357.8 128H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H347.1L325.8 320H384c17.7 0 32 14.3 32 32s-14.3 32-32 32H315.1l-11.5 69.3c-2.9 17.4-19.4 29.2-36.8 26.3s-29.2-19.4-26.3-36.8l9.8-58.7H155.1l-11.5 69.3c-2.9 17.4-19.4 29.2-36.8 26.3s-29.2-19.4-26.3-36.8L90.2 384H32c-17.7 0-32-14.3-32-32s14.3-32 32-32h68.9l21.3-128H64c-17.7 0-32-14.3-32-32s14.3-32 32-32h68.9l11.5-69.3c2.9-17.4 19.4-29.2 36.8-26.3zM187.1 192L165.8 320h95.1l21.3-128H187.1z'/%3e%3c/svg%3e";
940
3478
 
941
3479
  editor.contentElementTypes.register('counter', {
942
3480
  category: 'data',
943
- pictogram: img$e,
944
- supportedPositions: ['inline', 'sticky', 'standAlone', 'left', 'right'],
3481
+ pictogram: img$m,
3482
+ supportedPositions: ['inline', 'side', 'sticky', 'standAlone', 'left', 'right'],
945
3483
  supportedWidthRange: ['xxs', 'full'],
946
3484
  defaultConfig: {
947
3485
  targetValue: 100,
948
- countingSpeed: 'medium',
949
- textSize: 'medium'
3486
+ countingSpeed: 'medium'
950
3487
  },
951
- configurationEditor: function configurationEditor(_ref) {
952
- var entry = _ref.entry;
953
- var locale = entry.metadata.get('locale');
3488
+ configurationEditor({
3489
+ entry
3490
+ }) {
3491
+ const locale = entry.metadata.get('locale');
954
3492
  this.tab('general', function () {
3493
+ const modelDelegator = createLegacyConfigurationDelegator(this.model);
955
3494
  this.input('targetValue', NumberInputView, {
956
- locale: locale
3495
+ locale
957
3496
  });
958
3497
  this.input('decimalPlaces', SelectInputView, {
959
3498
  values: [0, 1, 2, 3],
960
- texts: [0, 1, 2, 3].map(function (i) {
961
- return 0 .toLocaleString(locale, {
962
- minimumFractionDigits: i
963
- });
964
- })
3499
+ texts: [0, 1, 2, 3].map(i => 0 .toLocaleString(locale, {
3500
+ minimumFractionDigits: i
3501
+ }))
3502
+ });
3503
+ this.input('thousandsSeparators', CheckBoxInputView, {
3504
+ storeInverted: 'hideThousandsSeparators'
965
3505
  });
966
3506
  this.input('unit', TextInputView);
967
3507
  this.input('unitPlacement', SelectInputView, {
968
3508
  values: ['trailing', 'leading']
969
3509
  });
970
3510
  this.view(SeparatorView);
3511
+ const [numberSizes, numberTexts] = entry.getTypographySizes({
3512
+ scaleCategory: 'counterNumber',
3513
+ texts: 'short',
3514
+ order: 'asc'
3515
+ });
3516
+ this.input('numberSize', SliderInputView, {
3517
+ model: modelDelegator,
3518
+ values: numberSizes,
3519
+ texts: numberTexts,
3520
+ defaultValue: 'xl',
3521
+ saveOnSlide: true
3522
+ });
3523
+ const [unitSizes, unitTexts] = entry.getTypographySizes({
3524
+ scaleCategory: 'counterUnit',
3525
+ texts: 'short',
3526
+ order: 'asc'
3527
+ });
3528
+ this.input('unitSize', SliderInputView, {
3529
+ values: unitSizes,
3530
+ texts: unitTexts,
3531
+ defaultValue: 'md',
3532
+ saveOnSlide: true,
3533
+ visibleBinding: 'unit',
3534
+ visible: unit => !!unit
3535
+ });
3536
+ const [descriptionSizes, descriptionTexts] = entry.getTypographySizes({
3537
+ scaleCategory: 'counterDescription',
3538
+ texts: 'short',
3539
+ order: 'asc'
3540
+ });
3541
+ this.input('descriptionSize', SliderInputView, {
3542
+ values: descriptionSizes,
3543
+ texts: descriptionTexts,
3544
+ defaultValue: 'md',
3545
+ saveOnSlide: true
3546
+ });
3547
+ this.view(SeparatorView);
3548
+ this.group('PaletteColor', {
3549
+ propertyName: 'numberColor',
3550
+ entry
3551
+ });
3552
+ this.group('PaletteColor', {
3553
+ propertyName: 'unitColor',
3554
+ entry,
3555
+ visibleBinding: 'unit',
3556
+ visible: unit => !!unit
3557
+ });
3558
+ this.group('PaletteColor', {
3559
+ propertyName: 'descriptionColor',
3560
+ entry
3561
+ });
3562
+ this.view(SeparatorView);
971
3563
  this.input('entranceAnimation', SelectInputView, {
972
3564
  values: ['none', 'fadeIn', 'fadeInFromBelow', 'fadeInFromAbove', 'fadeInScaleUp', 'fadeInScaleDown']
973
3565
  });
3566
+ this.input('countingAnimation', SelectInputView, {
3567
+ model: modelDelegator,
3568
+ values: ['none', 'plain', 'wheel']
3569
+ });
974
3570
  this.input('countingSpeed', SelectInputView, {
975
- values: ['none', 'slow', 'medium', 'fast']
3571
+ model: modelDelegator,
3572
+ values: ['slow', 'medium', 'fast'],
3573
+ visibleBinding: 'countingAnimation',
3574
+ visible: countingAnimation => countingAnimation && countingAnimation !== 'none'
976
3575
  });
977
3576
  this.input('startValue', NumberInputView, {
978
- locale: locale,
979
- visibleBinding: 'countingSpeed',
980
- visible: function visible(countingSpeed) {
981
- return countingSpeed !== 'none';
982
- }
3577
+ model: modelDelegator,
3578
+ locale,
3579
+ visibleBinding: 'countingAnimation',
3580
+ visible: countingAnimation => countingAnimation && countingAnimation !== 'none'
983
3581
  });
984
- this.view(SeparatorView);
985
- this.input('textSize', SelectInputView, {
986
- values: ['large', 'medium', 'small', 'verySmall']
3582
+ this.input('startAnimationTrigger', SelectInputView, {
3583
+ model: modelDelegator,
3584
+ values: ['onActivate', 'onVisible'],
3585
+ visibleBinding: ['entranceAnimation', 'countingAnimation'],
3586
+ visible: ([entranceAnimation, countingAnimation]) => (entranceAnimation || 'none') !== 'none' || countingAnimation && countingAnimation !== 'none'
987
3587
  });
3588
+ this.view(SeparatorView);
988
3589
  this.group('ContentElementTypographyVariant', {
989
- entry: entry,
990
- getPreviewConfiguration: function getPreviewConfiguration(configuration, typographyVariant) {
991
- return _objectSpread2(_objectSpread2({}, configuration), {}, {
992
- typographyVariant: typographyVariant,
993
- entranceAnimation: 'none',
994
- countingSpeed: 'none',
995
- textSize: 'small',
996
- position: 'inline'
997
- });
998
- }
3590
+ entry,
3591
+ getPreviewConfiguration: (configuration, typographyVariant) => ({
3592
+ ...configuration,
3593
+ typographyVariant,
3594
+ entranceAnimation: 'none',
3595
+ countingSpeed: 'none',
3596
+ numberSize: 'sm',
3597
+ position: 'inline'
3598
+ })
999
3599
  });
1000
- this.group('PaletteColor', {
1001
- propertyName: 'numberColor',
1002
- entry: entry
3600
+ this.input('textAlign', SelectInputView, {
3601
+ values: ['left', 'right', 'center', 'centerRagged'],
3602
+ includeBlank: true
3603
+ });
3604
+ this.group('ContentElementPosition', {
3605
+ entry
1003
3606
  });
1004
- this.group('ContentElementPosition');
1005
3607
  });
1006
3608
  }
1007
3609
  });
1008
3610
 
1009
- var img$f = "data:image/svg+xml,%3csvg aria-hidden='true' focusable='false' data-prefix='fas' data-icon='quote-right' class='svg-inline--fa fa-quote-right fa-w-16' role='img' xmlns='http://www.w3.org/2000/svg' viewBox='-50 -50 612 612'%3e%3cpath fill='white' d='M464 32H336c-26.5 0-48 21.5-48 48v128c0 26.5 21.5 48 48 48h80v64c0 35.3-28.7 64-64 64h-8c-13.3 0-24 10.7-24 24v48c0 13.3 10.7 24 24 24h8c88.4 0 160-71.6 160-160V80c0-26.5-21.5-48-48-48zm-288 0H48C21.5 32 0 53.5 0 80v128c0 26.5 21.5 48 48 48h80v64c0 35.3-28.7 64-64 64h-8c-13.3 0-24 10.7-24 24v48c0 13.3 10.7 24 24 24h8c88.4 0 160-71.6 160-160V80c0-26.5-21.5-48-48-48z'%3e%3c/path%3e%3c/svg%3e";
3611
+ var img$n = "data:image/svg+xml,%3csvg aria-hidden='true' focusable='false' data-prefix='fas' data-icon='quote-right' class='svg-inline--fa fa-quote-right fa-w-16' role='img' xmlns='http://www.w3.org/2000/svg' viewBox='-50 -50 612 612'%3e%3cpath fill='white' d='M464 32H336c-26.5 0-48 21.5-48 48v128c0 26.5 21.5 48 48 48h80v64c0 35.3-28.7 64-64 64h-8c-13.3 0-24 10.7-24 24v48c0 13.3 10.7 24 24 24h8c88.4 0 160-71.6 160-160V80c0-26.5-21.5-48-48-48zm-288 0H48C21.5 32 0 53.5 0 80v128c0 26.5 21.5 48 48 48h80v64c0 35.3-28.7 64-64 64h-8c-13.3 0-24 10.7-24 24v48c0 13.3 10.7 24 24 24h8c88.4 0 160-71.6 160-160V80c0-26.5-21.5-48-48-48z'%3e%3c/path%3e%3c/svg%3e";
1010
3612
 
1011
3613
  editor.contentElementTypes.register('quote', {
1012
- pictogram: img$f,
1013
- supportedPositions: ['inline', 'sticky', 'standAlone', 'left', 'right'],
3614
+ pictogram: img$n,
3615
+ supportedPositions: ['inline', 'side', 'sticky', 'standAlone', 'left', 'right'],
1014
3616
  supportedWidthRange: ['xs', 'xl'],
1015
3617
  defaultConfig: {
1016
3618
  textSize: 'medium'
1017
3619
  },
1018
- configurationEditor: function configurationEditor(_ref) {
1019
- var entry = _ref.entry;
3620
+ configurationEditor({
3621
+ entry
3622
+ }) {
1020
3623
  this.tab('general', function () {
1021
3624
  this.group('ContentElementVariant', {
1022
- entry: entry
3625
+ entry
1023
3626
  });
1024
3627
  this.input('textSize', SelectInputView, {
1025
3628
  values: ['large', 'medium', 'small', 'verySmall']
1026
3629
  });
1027
- this.group('ContentElementPosition');
3630
+ this.group('ContentElementPosition', {
3631
+ entry
3632
+ });
1028
3633
  this.group('PaletteColor', {
1029
3634
  propertyName: 'color',
1030
- entry: entry
3635
+ entry
1031
3636
  });
1032
3637
  this.view(SeparatorView);
1033
3638
  this.view(InfoBoxView, {
@@ -1037,123 +3642,90 @@ editor.contentElementTypes.register('quote', {
1037
3642
  }
1038
3643
  });
1039
3644
 
1040
- var css$1 = ".ItemsListView-module_listContainer__2XDCy {\n}\n";
1041
- var styles$1 = {"listContainer":"ItemsListView-module_listContainer__2XDCy"};
1042
- styleInject(css$1);
1043
-
1044
- var ItemsListView = Marionette.Layout.extend({
1045
- template: function template(data) {
1046
- return "\n <div class='".concat(styles$1.listContainer, "'></div>\n <button class=\"").concat(buttonStyles.addButton, "\">\n ").concat(I18n.t('pageflow_scrolled.editor.content_elements.imageGallery.items.add'), "\n </button>\n ");
1047
- },
1048
- regions: cssModulesUtils.ui(styles$1, 'listContainer'),
1049
- events: cssModulesUtils.events(buttonStyles, {
1050
- 'click addButton': function clickAddButton() {
1051
- this.collection.selectImage();
1052
- }
1053
- }),
1054
- onRender: function onRender() {
1055
- var _this = this;
3645
+ var img$o = "data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3c!--!Font Awesome Free 6.7.1 by %40fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons%2c Inc.--%3e%3cpath fill='white' d='M 446%2c37.9 C 341%2c38.2 236%2c37.8 132%2c38 106%2c38.4 80.7%2c37.3 55.3%2c38.5 26.6%2c42.6 3.13%2c70.8 6.21%2c100 5.84%2c203 5.94%2c305 6.15%2c408 c -0.18%2c12 0.3%2c26 7.25%2c36 11.2%2c20 34.2%2c33 57%2c30 128.6%2c0 256.6%2c0 384.6%2c0 30%2c-4 55%2c-34 51%2c-64 0%2c-107 0%2c-215 0%2c-322.2 C 501%2c59.7 475%2c36.7 446%2c37.9 Z M 60%2c90 c 24.7%2c0 49%2c0 74%2c0 0%2c25 0%2c51 0%2c76 -25%2c0 -50.7%2c0 -76%2c0 0%2c-25 0%2c-51 0%2c-76 h 1 z m 128%2c0 c 89%2c0 177%2c0 266%2c0 0%2c25 0%2c51 0%2c76 -89%2c0 -179%2c0 -268%2c0 0%2c-25 0%2c-51 0%2c-76 h 1 z M 60%2c218 c 24.7%2c0 49%2c0 74%2c0 0%2c25 0%2c51 0%2c76 -25%2c0 -50.7%2c0 -76%2c0 0%2c-25 0%2c-51 0%2c-76 h 1 z m 128%2c0 c 89%2c0 177%2c0 266%2c0 0%2c25 0%2c51 0%2c76 -89%2c0 -179%2c0 -268%2c0 0%2c-25 0%2c-51 0%2c-76 h 1 z M 60%2c346 c 24.7%2c0 49%2c0 74%2c0 0%2c25 0%2c51 0%2c76 -25%2c0 -50.7%2c0 -76%2c0 0%2c-25 0%2c-51 0%2c-76 h 1 z m 128%2c0 c 89%2c0 177%2c0 266%2c0 0%2c25 0%2c51 0%2c76 -89%2c0 -179%2c0 -268%2c0 0%2c-25 0%2c-51 0%2c-76 h 1 z' /%3e%3c/svg%3e";
1056
3646
 
1057
- this.listContainer.show(new ListView({
1058
- label: I18n.t('pageflow_scrolled.editor.content_elements.imageGallery.items.label'),
1059
- collection: this.collection,
1060
- sortable: true,
1061
- onRemove: function onRemove(model) {
1062
- return _this.collection.remove(model);
1063
- }
1064
- }));
3647
+ editor.contentElementTypes.register('infoTable', {
3648
+ pictogram: img$o,
3649
+ supportedPositions: ['inline', 'side', 'sticky', 'standAlone', 'left', 'right'],
3650
+ supportedWidthRange: ['s', 'xl'],
3651
+ configurationEditor({
3652
+ entry,
3653
+ contentElement
3654
+ }) {
3655
+ this.tab('general', function () {
3656
+ this.input('labelColumnAlign', SelectInputView, {
3657
+ values: ['auto', 'left', 'center', 'right']
3658
+ });
3659
+ this.input('valueColumnAlign', SelectInputView, {
3660
+ values: ['auto', 'left', 'center', 'right']
3661
+ });
3662
+ this.input('singleColumnInPhoneLayout', CheckBoxInputView);
3663
+ this.input('singleColumnAlign', SelectInputView, {
3664
+ values: ['auto', 'left', 'center', 'right'],
3665
+ visibleBinding: 'singleColumnInPhoneLayout'
3666
+ });
3667
+ this.view(SeparatorView);
3668
+ this.group('PaletteColor', {
3669
+ propertyName: 'labelColor',
3670
+ entry
3671
+ });
3672
+ this.group('PaletteColor', {
3673
+ propertyName: 'valueColor',
3674
+ entry
3675
+ });
3676
+ this.view(SeparatorView);
3677
+ this.group('ContentElementPosition', {
3678
+ entry
3679
+ });
3680
+ this.view(SeparatorView);
3681
+ this.view(InfoBoxView, {
3682
+ text: I18n.t('pageflow_scrolled.editor.content_elements.infoTable.help_texts.shortcuts')
3683
+ });
3684
+ });
1065
3685
  }
1066
3686
  });
1067
3687
 
1068
- var Item = Backbone.Model.extend({
1069
- mixins: [transientReferences],
1070
- thumbnailFile: function thumbnailFile() {
1071
- var _this$imageFile;
1072
-
1073
- return (_this$imageFile = this.imageFile()) === null || _this$imageFile === void 0 ? void 0 : _this$imageFile.thumbnailFile();
1074
- },
1075
- title: function title() {
1076
- var _this$imageFile2;
1077
-
1078
- return (_this$imageFile2 = this.imageFile()) === null || _this$imageFile2 === void 0 ? void 0 : _this$imageFile2.title();
1079
- },
1080
- imageFile: function imageFile() {
1081
- return this.collection.entry.imageFiles.getByPermaId(this.get('image'));
3688
+ // Headings carry no ranged comments since EditableInlineText has no
3689
+ // commenting alternative, so every comment refers to the header as a whole
3690
+ // and the quote covers all three of its texts.
3691
+ review.contentElementTypes.register('heading', {
3692
+ extractQuote(configuration) {
3693
+ const parts = [inlineText(configuration.tagline), mainText(configuration), inlineText(configuration.subtitle)];
3694
+ return parts.map(part => part.trim()).filter(Boolean).join('\n') || null;
1082
3695
  }
1083
3696
  });
1084
3697
 
1085
- var ItemsCollection = Backbone.Collection.extend({
1086
- model: Item,
1087
- comparator: 'position',
1088
- initialize: function initialize(models, options) {
1089
- this.entry = options.entry;
1090
- this.contentElement = options.contentElement;
1091
- this.listenTo(this, 'add remove sort', this.updateConfiguration);
1092
- this.listenTo(this, 'remove', this.pruneCaptions);
1093
- },
1094
- updateConfiguration: function updateConfiguration() {
1095
- this.contentElement.configuration.set('items', this.toJSON());
1096
- },
1097
- pruneCaptions: function pruneCaptions() {
1098
- this.contentElement.configuration.set('captions', _.pick.apply(_, [this.contentElement.configuration.get('captions') || {}].concat(_toConsumableArray(this.pluck('id')))));
1099
- },
1100
- selectImage: function selectImage() {
1101
- editor$1.selectFile('image_files', 'newImageGalleryItem', {
1102
- id: this.contentElement.id
1103
- });
1104
- },
1105
- addWithId: function addWithId(imageFile) {
1106
- this.add({
1107
- id: this.length ? Math.max.apply(Math, _toConsumableArray(this.pluck('id'))) + 1 : 1,
1108
- image: imageFile.get('perma_id')
1109
- });
1110
- },
1111
- saveOrder: function saveOrder() {}
1112
- });
1113
-
1114
- ItemsCollection.forContentElement = function (contentElement, entry) {
1115
- return new ItemsCollection(contentElement.configuration.get('items') || [], {
1116
- entry: entry,
1117
- contentElement: contentElement
1118
- });
1119
- };
1120
-
1121
- var FileSelectionHandler = function FileSelectionHandler(options) {
1122
- var contentElement = options.entry.contentElements.get(options.id);
1123
-
1124
- this.call = function (file) {
1125
- ItemsCollection.forContentElement(contentElement).addWithId(file);
1126
- };
1127
-
1128
- this.getReferer = function () {
1129
- return '/scrolled/content_elements/' + contentElement.id;
1130
- };
1131
- };
1132
-
1133
- editor$1.registerFileSelectionHandler('newImageGalleryItem', FileSelectionHandler);
1134
-
1135
- var img$g = "data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 576 512'%3e%3c!--! Font Awesome Pro 6.4.0 by %40fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons%2c Inc. --%3e%3cpath fill='white' d='M160 32c-35.3 0-64 28.7-64 64V320c0 35.3 28.7 64 64 64H512c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64H160zM396 138.7l96 144c4.9 7.4 5.4 16.8 1.2 24.6S480.9 320 472 320H328 280 200c-9.2 0-17.6-5.3-21.6-13.6s-2.9-18.2 2.9-25.4l64-80c4.6-5.7 11.4-9 18.7-9s14.2 3.3 18.7 9l17.3 21.6 56-84C360.5 132 368 128 376 128s15.5 4 20 10.7zM192 128a32 32 0 1 1 64 0 32 32 0 1 1 -64 0zM48 120c0-13.3-10.7-24-24-24S0 106.7 0 120V344c0 75.1 60.9 136 136 136H456c13.3 0 24-10.7 24-24s-10.7-24-24-24H136c-48.6 0-88-39.4-88-88V120z'/%3e%3c/svg%3e";
3698
+ // Mirrors how EditableInlineText picks the legacy string value, so the quote
3699
+ // never contains text the heading does not display.
3700
+ function mainText(configuration) {
3701
+ return configuration.value ? inlineText(configuration.value) : configuration.children || '';
3702
+ }
3703
+ function inlineText(value) {
3704
+ return value ? value.map(node => Node.string(node)).join(' ') : '';
3705
+ }
1136
3706
 
1137
- editor.contentElementTypes.register('imageGallery', {
1138
- pictogram: img$g,
1139
- category: 'media',
1140
- supportedPositions: ['inline', 'sticky', 'standAlone', 'left', 'right'],
1141
- supportedWidthRange: ['xxs', 'full'],
1142
- configurationEditor: function configurationEditor(_ref) {
1143
- var entry = _ref.entry,
1144
- contentElement = _ref.contentElement;
1145
- this.tab('general', function () {
1146
- this.view(ItemsListView, {
1147
- collection: ItemsCollection.forContentElement(this.model.parent, entry)
1148
- });
1149
- this.input('enableFullscreenOnDesktop', CheckBoxInputView, {
1150
- disabledBinding: ['position', 'width'],
1151
- disabled: function disabled() {
1152
- return contentElement.getWidth() === contentElementWidths.full;
1153
- },
1154
- displayUncheckedIfDisabled: true
1155
- });
1156
- this.group('ContentElementPosition');
1157
- });
3707
+ review.contentElementTypes.register('textBlock', {
3708
+ compareRanges(a, b) {
3709
+ if (!a && !b) return 0;
3710
+ if (!a) return 1;
3711
+ if (!b) return -1;
3712
+ return Point.compare(rangeStart(a), rangeStart(b));
3713
+ },
3714
+ // Element wide comments stay unquoted: the whole text is too long to serve
3715
+ // as a point of reference, and any edit anywhere in it would mark the quote
3716
+ // outdated.
3717
+ extractQuote(configuration, range) {
3718
+ if (!range) return null;
3719
+ const root = {
3720
+ children: configuration.value || []
3721
+ };
3722
+ if (!Node.has(root, range.anchor.path) || !Node.has(root, range.focus.path)) {
3723
+ return null;
3724
+ }
3725
+ const text = Node.fragment(root, range).map(node => Node.string(node)).join('\n').trim();
3726
+ return text || null;
1158
3727
  }
1159
3728
  });
3729
+ function rangeStart(range) {
3730
+ return Point.isBefore(range.anchor, range.focus) ? range.anchor : range.focus;
3731
+ }