pageflow 17.1.0 → 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 (302) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +319 -345
  3. data/README.md +3 -4
  4. data/admins/pageflow/accounts.rb +6 -6
  5. data/admins/pageflow/entry.rb +10 -8
  6. data/admins/pageflow/membership.rb +11 -11
  7. data/admins/pageflow/translations.rb +5 -5
  8. data/app/assets/images/pageflow/admin/icons/comment.svg +1 -0
  9. data/app/assets/javascripts/pageflow/dist/ui.js +1350 -630
  10. data/app/assets/javascripts/pageflow/editor/vendor.js +0 -1
  11. data/app/assets/javascripts/pageflow/ui.js +0 -1
  12. data/app/assets/stylesheets/pageflow/admin/entry_comments_indicator.scss +45 -0
  13. data/app/assets/stylesheets/pageflow/admin/permalink_input.scss +8 -1
  14. data/app/assets/stylesheets/pageflow/admin.scss +1 -0
  15. data/app/assets/stylesheets/pageflow/animations/spin.scss +9 -0
  16. data/app/assets/stylesheets/pageflow/animations.scss +1 -0
  17. data/app/assets/stylesheets/pageflow/editor/background_positioning.scss +21 -5
  18. data/app/assets/stylesheets/pageflow/editor/base.scss +9 -1
  19. data/app/assets/stylesheets/pageflow/editor/drop_down_button.scss +13 -1
  20. data/app/assets/stylesheets/pageflow/editor/edit_configuration_view.scss +5 -0
  21. data/app/assets/stylesheets/pageflow/editor/file_folders.scss +127 -0
  22. data/app/assets/stylesheets/pageflow/editor/file_meta_data.scss +0 -1
  23. data/app/assets/stylesheets/pageflow/editor/file_meta_data_overlay.scss +45 -0
  24. data/app/assets/stylesheets/pageflow/editor/file_preview.scss +138 -0
  25. data/app/assets/stylesheets/pageflow/editor/file_references.scss +68 -0
  26. data/app/assets/stylesheets/pageflow/editor/file_settings_dialog.scss +1 -1
  27. data/app/assets/stylesheets/pageflow/editor/file_stage_icons.scss +17 -0
  28. data/app/assets/stylesheets/pageflow/editor/file_stages.scss +25 -32
  29. data/app/assets/stylesheets/pageflow/editor/file_thumbnails.scss +31 -48
  30. data/app/assets/stylesheets/pageflow/editor/file_type_pills.scss +73 -0
  31. data/app/assets/stylesheets/pageflow/editor/files.scss +230 -50
  32. data/app/assets/stylesheets/pageflow/editor/filtered_files.scss +142 -14
  33. data/app/assets/stylesheets/pageflow/editor/folder_breadcrumb.scss +40 -0
  34. data/app/assets/stylesheets/pageflow/editor/info_box.scss +12 -0
  35. data/app/assets/stylesheets/pageflow/editor/inputs/edit_defaults_button.scss +15 -0
  36. data/app/assets/stylesheets/pageflow/editor/inputs.scss +1 -0
  37. data/app/assets/stylesheets/pageflow/editor/list.scss +88 -38
  38. data/app/assets/stylesheets/pageflow/editor/manage_files.scss +9 -0
  39. data/app/assets/stylesheets/pageflow/editor/menu.scss +14 -0
  40. data/app/assets/stylesheets/pageflow/editor/move_to_folder_dialog.scss +83 -0
  41. data/app/assets/stylesheets/pageflow/mixins/pageflow.scss +9 -5
  42. data/app/assets/stylesheets/pageflow/ui/color_picker.scss +230 -0
  43. data/app/assets/stylesheets/pageflow/ui/forms.scss +34 -4
  44. data/app/assets/stylesheets/pageflow/ui/functions.scss +12 -2
  45. data/app/assets/stylesheets/pageflow/ui/input/color_input.scss +9 -16
  46. data/app/assets/stylesheets/pageflow/ui/input/text_area_input.scss +15 -0
  47. data/app/assets/stylesheets/pageflow/ui/overrides.scss +8 -0
  48. data/app/assets/stylesheets/pageflow/ui/properties.scss +29 -0
  49. data/app/assets/stylesheets/pageflow/ui/tabs_view.scss +8 -3
  50. data/app/assets/stylesheets/pageflow/ui.scss +4 -2
  51. data/app/controllers/pageflow/editor/entries_controller.rb +1 -0
  52. data/app/controllers/pageflow/editor/file_folders_controller.rb +80 -0
  53. data/app/controllers/pageflow/editor/file_import_controller.rb +1 -0
  54. data/app/controllers/pageflow/editor/files_controller.rb +15 -6
  55. data/app/controllers/pageflow/editor/oembeds_controller.rb +21 -0
  56. data/app/controllers/pageflow/entries_controller.rb +17 -13
  57. data/app/controllers/pageflow/review/comment_thread_reads_controller.rb +30 -0
  58. data/app/controllers/pageflow/review/comment_threads_controller.rb +60 -0
  59. data/app/controllers/pageflow/review/comments_controller.rb +53 -0
  60. data/app/controllers/pageflow/revisions_controller.rb +4 -1
  61. data/app/helpers/pageflow/admin/entries_helper.rb +40 -0
  62. data/app/helpers/pageflow/admin/widgets_helper.rb +2 -2
  63. data/app/helpers/pageflow/common_entry_seed_helper.rb +5 -3
  64. data/app/helpers/pageflow/editor/config_helper.rb +3 -1
  65. data/app/helpers/pageflow/entries_helper.rb +24 -42
  66. data/app/helpers/pageflow/entry_json_seed_helper.rb +4 -4
  67. data/app/helpers/pageflow/public_i18n_helper.rb +9 -8
  68. data/app/helpers/pageflow/structured_data_helper.rb +4 -1
  69. data/app/helpers/pageflow/themes_helper.rb +1 -3
  70. data/app/helpers/pageflow/widgets_helper.rb +2 -1
  71. data/app/inputs/pageflow_permalink_input.rb +6 -2
  72. data/app/models/concerns/pageflow/auto_generated_perma_id.rb +11 -4
  73. data/app/models/concerns/pageflow/reusable_file.rb +1 -1
  74. data/app/models/concerns/pageflow/serialization_blacklist.rb +2 -4
  75. data/app/models/concerns/pageflow/translated_attributes.rb +101 -0
  76. data/app/models/concerns/pageflow/uploadable_file.rb +1 -1
  77. data/app/models/pageflow/comment.rb +30 -0
  78. data/app/models/pageflow/comment_thread.rb +65 -0
  79. data/app/models/pageflow/comment_thread_read.rb +22 -0
  80. data/app/models/pageflow/customized_theme.rb +3 -2
  81. data/app/models/pageflow/draft_entry.rb +20 -8
  82. data/app/models/pageflow/entry.rb +2 -0
  83. data/app/models/pageflow/entry_at_revision.rb +9 -1
  84. data/app/models/pageflow/entry_comment_summary.rb +114 -0
  85. data/app/models/pageflow/file_folder.rb +74 -0
  86. data/app/models/pageflow/file_reuse.rb +3 -2
  87. data/app/models/pageflow/file_usage.rb +8 -0
  88. data/app/models/pageflow/image_file.rb +24 -20
  89. data/app/models/pageflow/image_file_url_templates.rb +3 -3
  90. data/app/models/pageflow/legal_info.rb +38 -0
  91. data/app/models/pageflow/nested_revision_component_copy.rb +1 -1
  92. data/app/models/pageflow/permalink.rb +1 -0
  93. data/app/models/pageflow/revision.rb +6 -2
  94. data/app/models/pageflow/site.rb +10 -0
  95. data/app/models/pageflow/used_file.rb +8 -2
  96. data/app/models/pageflow/widget.rb +2 -2
  97. data/app/views/pageflow/audio_files/_audio_file.json.jbuilder +0 -1
  98. data/app/views/pageflow/editor/config/_seeds.json.jbuilder +4 -2
  99. data/app/views/pageflow/editor/entries/_entry.json.jbuilder +2 -1
  100. data/app/views/pageflow/editor/entries/seed.json.erb +1 -0
  101. data/app/views/pageflow/editor/file_folders/_file_folder.json.jbuilder +5 -0
  102. data/app/views/pageflow/editor/file_folders/create.json.jbuilder +1 -0
  103. data/app/views/pageflow/editor/file_folders/index.json.jbuilder +3 -0
  104. data/app/views/pageflow/editor/files/_file.json.jbuilder +2 -1
  105. data/app/views/pageflow/editor/image_files/_image_file.json.jbuilder +3 -0
  106. data/app/views/pageflow/editor/video_files/_video_file.json.jbuilder +3 -0
  107. data/app/views/pageflow/files/_file.json.jbuilder +2 -0
  108. data/app/views/pageflow/image_files/_image_file.json.jbuilder +0 -1
  109. data/app/views/pageflow/review/comment_threads/_comment_thread.json.jbuilder +20 -0
  110. data/app/views/pageflow/review/comment_threads/create.json.jbuilder +2 -0
  111. data/app/views/pageflow/review/comment_threads/index.json.jbuilder +13 -0
  112. data/app/views/pageflow/review/comments/_comment.json.jbuilder +13 -0
  113. data/app/views/pageflow/review/comments/create.json.jbuilder +1 -0
  114. data/app/views/pageflow/structured_data/_entry.json.jbuilder +2 -3
  115. data/app/views/pageflow/video_files/_video_file.json.jbuilder +0 -1
  116. data/config/locales/de.yml +152 -14
  117. data/config/locales/en.yml +150 -14
  118. data/config/routes.rb +14 -0
  119. data/db/migrate/20140418225525_setup_schema.rb +2 -2
  120. data/db/migrate/20251015000000_add_structured_data_type_name_to_revisions.rb +5 -0
  121. data/db/migrate/20251029142849_convert_legacy_social_embeds_to_unified_social_embed.rb +38 -0
  122. data/db/migrate/20251119083347_fix_main_storyline_positions.rb +16 -0
  123. data/db/migrate/20251119083348_ensure_scrolled_entries_have_excursion_storyline.rb +15 -0
  124. data/db/migrate/20260303000000_add_layout_version_to_revisions.rb +6 -0
  125. data/db/migrate/20260323000000_create_comment_threads_and_comments.rb +30 -0
  126. data/db/migrate/20260414000000_add_subject_range_to_comment_threads.rb +5 -0
  127. data/db/migrate/20260415000000_add_section_perma_id_to_comment_threads.rb +5 -0
  128. data/db/migrate/20260727000000_add_quote_to_comments.rb +5 -0
  129. data/db/migrate/20260728000000_create_file_folders.rb +17 -0
  130. data/db/migrate/20260805000000_add_attribute_translations_to_sites.rb +5 -0
  131. data/db/migrate/20260806000000_add_edited_at_to_comments.rb +5 -0
  132. data/db/migrate/20260810000000_create_pageflow_scrolled_lottie_files.rb +24 -0
  133. data/db/migrate/20260817000000_create_comment_thread_reads.rb +16 -0
  134. data/db/migrate/20260819000000_add_unread_comments_since_at_to_users.rb +18 -0
  135. data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/editor.js +8665 -3890
  136. data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/frontend.js +979 -3571
  137. data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/react-client.js +20199 -28120
  138. data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/react-server.js +18652 -26584
  139. data/entry_types/scrolled/app/assets/stylesheets/pageflow_scrolled/ui.scss +2 -0
  140. data/entry_types/scrolled/app/controllers/pageflow_scrolled/editor/content_elements_controller.rb +33 -3
  141. data/entry_types/scrolled/app/controllers/pageflow_scrolled/editor/sections_controller.rb +2 -3
  142. data/entry_types/scrolled/app/controllers/pageflow_scrolled/entries_controller.rb +21 -1
  143. data/entry_types/scrolled/app/helpers/pageflow_scrolled/cache_helper.rb +3 -3
  144. data/entry_types/scrolled/app/helpers/pageflow_scrolled/editor/entry_json_seed_helper.rb +7 -5
  145. data/entry_types/scrolled/app/helpers/pageflow_scrolled/editor/seed_html_helper.rb +5 -2
  146. data/entry_types/scrolled/app/helpers/pageflow_scrolled/entry_json_seed_helper.rb +13 -5
  147. data/entry_types/scrolled/app/helpers/pageflow_scrolled/i18n_helper.rb +28 -13
  148. data/entry_types/scrolled/app/helpers/pageflow_scrolled/packs_helper.rb +26 -11
  149. data/entry_types/scrolled/app/helpers/pageflow_scrolled/react_server_side_rendering_helper.rb +2 -2
  150. data/entry_types/scrolled/app/helpers/pageflow_scrolled/sprockets_helper.rb +16 -0
  151. data/entry_types/scrolled/app/helpers/pageflow_scrolled/themes_helper.rb +174 -3
  152. data/entry_types/scrolled/app/models/pageflow_scrolled/content_element.rb +49 -7
  153. data/entry_types/scrolled/app/models/pageflow_scrolled/lottie_file.rb +6 -0
  154. data/entry_types/scrolled/app/models/pageflow_scrolled/lottie_file_url_templates.rb +16 -0
  155. data/entry_types/scrolled/app/models/pageflow_scrolled/storyline.rb +1 -0
  156. data/entry_types/scrolled/app/views/pageflow_scrolled/entries/show.html.erb +13 -12
  157. data/entry_types/scrolled/app/views/pageflow_scrolled/entry_json_seed/_entry.json.jbuilder +30 -10
  158. data/entry_types/scrolled/app/views/pageflow_scrolled/entry_json_seed/_theme.json.jbuilder +9 -0
  159. data/entry_types/scrolled/app/views/pageflow_scrolled/favicons/_entry.html.erb +1 -1
  160. data/entry_types/scrolled/config/configuration_schemas/pageflow-scrolled.json +414 -0
  161. data/entry_types/scrolled/config/locales/de.yml +512 -65
  162. data/entry_types/scrolled/config/locales/en.yml +518 -52
  163. data/entry_types/scrolled/lib/pageflow_scrolled/additional_seed_data.rb +2 -2
  164. data/entry_types/scrolled/lib/pageflow_scrolled/configuration.rb +51 -6
  165. data/entry_types/scrolled/lib/pageflow_scrolled/configuration_schemas.rb +91 -0
  166. data/entry_types/scrolled/lib/pageflow_scrolled/engine.rb +2 -1
  167. data/entry_types/scrolled/lib/pageflow_scrolled/entry_file_reference_locations.rb +71 -0
  168. data/entry_types/scrolled/lib/pageflow_scrolled/entry_structured_data_types/faq_page.rb +58 -0
  169. data/entry_types/scrolled/lib/pageflow_scrolled/file_reference_locations.rb +69 -0
  170. data/entry_types/scrolled/lib/pageflow_scrolled/plugin.rb +205 -22
  171. data/entry_types/scrolled/lib/pageflow_scrolled/react_widget_type.rb +2 -4
  172. data/entry_types/scrolled/lib/pageflow_scrolled/seeds.rb +56 -36
  173. data/entry_types/scrolled/lib/pageflow_scrolled/theme_options_default_scale.rb +35 -0
  174. data/entry_types/scrolled/lib/pageflow_scrolled.rb +13 -0
  175. data/entry_types/scrolled/lib/tasks/pageflow_scrolled/storybook.rake +19 -1
  176. data/entry_types/scrolled/package/config/configurationSchemas.js +70 -0
  177. data/entry_types/scrolled/package/config/rollup/configurationSchemas.js +19 -0
  178. data/entry_types/scrolled/package/config/webpack.js +72 -0
  179. data/entry_types/scrolled/package/contentElements/hotspots-frontend.css +1 -1
  180. data/entry_types/scrolled/package/contentElements/hotspots-frontend.js +1181 -915
  181. data/entry_types/scrolled/package/contentElements/inlineBeforeAfter-frontend.css +1 -0
  182. data/entry_types/scrolled/package/contentElements/inlineBeforeAfter-frontend.js +219 -0
  183. data/entry_types/scrolled/package/contentElements/lottieAnimation-frontend.css +1 -0
  184. data/entry_types/scrolled/package/contentElements/lottieAnimation-frontend.js +244 -0
  185. data/entry_types/scrolled/package/contentElements/socialEmbed-frontend.css +1 -0
  186. data/entry_types/scrolled/package/contentElements/socialEmbed-frontend.js +823 -0
  187. data/entry_types/scrolled/package/contentElements/tikTokEmbed-frontend.js +71 -21
  188. data/entry_types/scrolled/package/contentElements/twitterEmbed-frontend.css +1 -0
  189. data/entry_types/scrolled/package/contentElements/twitterEmbed-frontend.js +277 -0
  190. data/entry_types/scrolled/package/contentElements/videoEmbed-frontend.css +1 -0
  191. data/entry_types/scrolled/package/contentElements/videoEmbed-frontend.js +244 -0
  192. data/entry_types/scrolled/package/contentElements-editor.js +1915 -1097
  193. data/entry_types/scrolled/package/contentElements-frontend.css +1 -1
  194. data/entry_types/scrolled/package/contentElements-frontend.js +3093 -1679
  195. data/entry_types/scrolled/package/editor.css +1 -0
  196. data/entry_types/scrolled/package/editor.js +8667 -4077
  197. data/entry_types/scrolled/package/entryState.js +1600 -0
  198. data/entry_types/scrolled/package/frontend/FloatingPortalRootProvider-20c600de.js +1979 -0
  199. data/entry_types/scrolled/package/frontend/FloatingPortalRootProvider-58189220.js +2538 -0
  200. data/entry_types/scrolled/package/frontend/{PhonePlatformContext-9f76033e.js → PhonePlatformContext-035a99fa.js} +7 -12
  201. data/entry_types/scrolled/package/frontend/PhonePlatformContext-9da43797.js +33 -0
  202. data/entry_types/scrolled/package/frontend/Placeholder.module-bf0966b4.js +5267 -0
  203. data/entry_types/scrolled/package/frontend/Placeholder.module-d22a9335.js +4180 -0
  204. data/entry_types/scrolled/package/frontend/ThemeIcon-ab834849.js +754 -0
  205. data/entry_types/scrolled/package/frontend/ThemeIcon-f6cb3a8f.js +773 -0
  206. data/entry_types/scrolled/package/frontend/{ToggleFullscreenCornerButton-788e9cdb.js → ToggleFullscreenCornerButton-30fd1124.js} +6 -6
  207. data/entry_types/scrolled/package/frontend/ToggleFullscreenCornerButton-61c25224.js +72 -0
  208. data/entry_types/scrolled/package/frontend/Viewer-1074fd59.js +147 -0
  209. data/entry_types/scrolled/package/frontend/Viewer-1482ca34.js +480 -0
  210. data/entry_types/scrolled/package/frontend/Viewer-70504231.js +210 -0
  211. data/entry_types/scrolled/package/frontend/{Viewer-0345ce57.js → Viewer-cc8d4072.js} +84 -92
  212. data/entry_types/scrolled/package/frontend/Wavesurfer-656e3c36.js +302 -0
  213. data/entry_types/scrolled/package/frontend/Wavesurfer-b753b838.js +385 -0
  214. data/entry_types/scrolled/package/frontend/commenting.css +1 -0
  215. data/entry_types/scrolled/package/frontend/extensions-167ae143.js +1455 -0
  216. data/entry_types/scrolled/package/frontend/extensions-2318f92b.js +5918 -0
  217. data/entry_types/scrolled/package/frontend/extensions-a461fd13.js +4890 -0
  218. data/entry_types/scrolled/package/frontend/extensions-c98269fd.js +1982 -0
  219. data/entry_types/scrolled/package/frontend/i18n-493cd2a6.js +93 -0
  220. data/entry_types/scrolled/package/frontend/i18n-e06cac14.js +100 -0
  221. data/entry_types/scrolled/package/frontend/{index-eb670c2f.js → index-2e5546f7.js} +36 -44
  222. data/entry_types/scrolled/package/frontend/index-de2b418d.js +130 -0
  223. data/entry_types/scrolled/package/frontend/index.css +1 -1
  224. data/entry_types/scrolled/package/frontend/index.js +1870 -875
  225. data/entry_types/scrolled/package/frontend/inlineEditing.css +1 -0
  226. data/entry_types/scrolled/package/frontend/useContentElementEditorState-a084912e.js +25 -0
  227. data/entry_types/scrolled/package/frontend/useDelayedBoolean-a387d85b.js +24 -0
  228. data/entry_types/scrolled/package/frontend/{usePhonePlatform-c2ba875d.js → usePhonePlatform-4ecb96d4.js} +1 -1
  229. data/entry_types/scrolled/package/frontend/usePhonePlatform-ce9ff08d.js +8 -0
  230. data/entry_types/scrolled/package/frontend-server.js +20 -209
  231. data/entry_types/scrolled/package/package.json +5 -3
  232. data/entry_types/scrolled/package/review.css +1 -0
  233. data/entry_types/scrolled/package/review.js +3306 -0
  234. data/entry_types/scrolled/package/testHelpers.js +836 -359
  235. data/entry_types/scrolled/package/widgets/consentBar.css +1 -1
  236. data/entry_types/scrolled/package/widgets/consentBar.js +269 -290
  237. data/entry_types/scrolled/package/widgets/defaultNavigation.css +2 -2
  238. data/entry_types/scrolled/package/widgets/defaultNavigation.js +911 -352
  239. data/entry_types/scrolled/package/widgets/excursionSheet.css +1 -1
  240. data/entry_types/scrolled/package/widgets/excursionSheet.js +87 -124
  241. data/entry_types/scrolled/package/widgets/iconInlineFileRights.css +1 -1
  242. data/entry_types/scrolled/package/widgets/iconInlineFileRights.js +62 -29
  243. data/entry_types/scrolled/package/widgets/iconScrollIndicator.js +32 -13
  244. data/entry_types/scrolled/package/widgets/mainStorylineSheet.css +1 -1
  245. data/entry_types/scrolled/package/widgets/mainStorylineSheet.js +56 -100
  246. data/entry_types/scrolled/package/widgets/textInlineFileRights.css +1 -1
  247. data/entry_types/scrolled/package/widgets/textInlineFileRights.js +33 -28
  248. data/entry_types/scrolled/package/widgets-server.js +1 -0
  249. data/entry_types/scrolled/spec/factories/lottie_files.rb +29 -0
  250. data/entry_types/scrolled/spec/fixtures/animation.lottie +0 -0
  251. data/entry_types/scrolled/spec/fixtures/font.woff +0 -0
  252. data/entry_types/scrolled/spec/fixtures/font.woff2 +0 -0
  253. data/lib/generators/pageflow/resque/resque_generator.rb +0 -2
  254. data/lib/pageflow/configuration.rb +49 -7
  255. data/lib/pageflow/deprecation.rb +19 -0
  256. data/lib/pageflow/engine.rb +1 -1
  257. data/lib/pageflow/entries_controller_env_helper.rb +32 -2
  258. data/lib/pageflow/entry_export_import/entry_serialization.rb +4 -4
  259. data/lib/pageflow/entry_export_import/page_type_versions.rb +2 -2
  260. data/lib/pageflow/entry_export_import/revision_serialization/import.rb +10 -0
  261. data/lib/pageflow/entry_export_import/revision_serialization.rb +3 -0
  262. data/lib/pageflow/entry_structured_data_types.rb +43 -0
  263. data/lib/pageflow/entry_type_configuration.rb +1 -0
  264. data/lib/pageflow/file_type.rb +2 -2
  265. data/lib/pageflow/file_types.rb +1 -1
  266. data/lib/pageflow/oembed_providers.rb +42 -0
  267. data/lib/pageflow/primary_domain_entry_redirect.rb +6 -0
  268. data/lib/pageflow/rails_version.rb +13 -2
  269. data/lib/pageflow/themes.rb +41 -0
  270. data/lib/pageflow/user_mixin.rb +12 -0
  271. data/lib/pageflow/version.rb +1 -1
  272. data/lib/pageflow.rb +1 -0
  273. data/package/config/eslint-rules/documented-in-toc.js +125 -0
  274. data/package/config/jest/index.js +0 -1
  275. data/package/config/webpack.js +0 -1
  276. data/package/config/webpack5.js +0 -1
  277. data/package/editor.js +4378 -1897
  278. data/package/frontend.js +647 -886
  279. data/package/package.json +2 -1
  280. data/package/review.js +384 -0
  281. data/package/testHelpers.js +248 -188
  282. data/package/ui.js +1346 -630
  283. data/package/vendor/stubs/wysihtml5.js +2 -0
  284. data/spec/factories/comment_thread_reads.rb +10 -0
  285. data/spec/factories/comment_threads.rb +10 -0
  286. data/spec/factories/comments.rb +9 -0
  287. data/spec/factories/file_folders.rb +8 -0
  288. data/spec/factories/published_entries.rb +2 -0
  289. metadata +188 -67
  290. data/app/assets/stylesheets/pageflow/editor/select_button.scss +0 -51
  291. data/entry_types/scrolled/app/helpers/pageflow_scrolled/generated_media_queries_helper.rb +0 -55
  292. data/entry_types/scrolled/package/frontend/FloatingPortalRootProvider-51914be7.js +0 -5439
  293. data/entry_types/scrolled/package/frontend/ThemeIcon-81f2f066.js +0 -1932
  294. data/entry_types/scrolled/package/frontend/Viewer-cdc549cc.js +0 -147
  295. data/entry_types/scrolled/package/frontend/Wavesurfer-1cdc3925.js +0 -313
  296. data/entry_types/scrolled/package/frontend/components-96660ffd.js +0 -3803
  297. data/entry_types/scrolled/package/frontend/inherits-539844a6.js +0 -99
  298. data/entry_types/scrolled/package/frontend/useContentElementEditorState-77fe6c79.js +0 -51
  299. data/entry_types/scrolled/package/widgets/excursionDialog.css +0 -1
  300. data/entry_types/scrolled/package/widgets/excursionDialog.js +0 -109
  301. data/lib/generators/pageflow/resque/templates/resque_enqueue_after_commit_patch.rb +0 -25
  302. data/package/vendor/jquery.minicolors.js +0 -1108
@@ -1,12 +1,162 @@
1
1
  module PageflowScrolled
2
2
  # @api private
3
- class Plugin < Pageflow::Plugin
3
+ class Plugin < Pageflow::Plugin # rubocop:disable Metrics/ClassLength
4
4
  def configure(config)
5
5
  config.features.register('scrolled_entry_type') do |feature_config|
6
6
  feature_config.entry_types.register(PageflowScrolled.entry_type)
7
7
  end
8
8
 
9
9
  config.for_entry_type(PageflowScrolled.entry_type) do |c|
10
+ c.configuration_schema_load_path <<
11
+ Engine.root.join('config', 'configuration_schemas', '*.json').to_s
12
+
13
+ padding_scale = {
14
+ 'none' => '0px',
15
+ 'xxxs' => '1.375em',
16
+ 'xxs' => '3em',
17
+ 'xs' => '4.375em',
18
+ 'sm' => '6em',
19
+ 'md' => 'max(7em, 10svh)',
20
+ 'lg' => 'max(8em, 10svh)',
21
+ 'xl' => 'max(9em, 15svh)',
22
+ 'xxl' => 'max(10em, 20svh)',
23
+ 'xxxl' => 'max(11em, 30svh)'
24
+ }
25
+
26
+ margin_scale = {
27
+ 'xxs' => '2em',
28
+ 'xs' => '3em',
29
+ 'sm' => '4em',
30
+ 'md' => '6em',
31
+ 'lg' => '10em',
32
+ 'xl' => '12em',
33
+ 'xxl' => '16em'
34
+ }
35
+
36
+ box_shadow_scale = {
37
+ 'sm' => '0 1px 3px 0 rgb(0 0 0 / 0.2), 0 1px 2px -1px rgb(0 0 0 / 0.15)',
38
+ 'md' => '0 4px 6px -1px rgb(0 0 0 / 0.2), 0 2px 4px -2px rgb(0 0 0 / 0.15)',
39
+ 'lg' => '0 10px 15px -3px rgb(0 0 0 / 0.2), 0 4px 6px -4px rgb(0 0 0 / 0.12)',
40
+ 'xl' => '0 20px 25px -5px rgb(0 0 0 / 0.2), 0 8px 10px -6px rgb(0 0 0 / 0.12)'
41
+ }
42
+
43
+ c.themes.register_options_transform(
44
+ ThemeOptionsDefaultScale.new(
45
+ prefix: 'section_padding_top',
46
+ values: padding_scale
47
+ )
48
+ )
49
+
50
+ c.themes.register_options_transform(
51
+ ThemeOptionsDefaultScale.new(
52
+ prefix: 'section_padding_bottom',
53
+ values: padding_scale
54
+ )
55
+ )
56
+
57
+ c.themes.register_options_transform(
58
+ ThemeOptionsDefaultScale.new(
59
+ prefix: 'content_element_margin',
60
+ values: margin_scale
61
+ )
62
+ )
63
+
64
+ c.themes.register_options_transform(
65
+ ThemeOptionsDefaultScale.new(
66
+ prefix: 'content_element_box_shadow',
67
+ values: box_shadow_scale
68
+ )
69
+ )
70
+
71
+ c.themes.register_default_options(
72
+ properties: {
73
+ root: {
74
+ 'section_default_padding_top' => 'max(10em, 20svh)',
75
+ 'section_default_padding_bottom' => 'max(10em, 20svh)',
76
+ 'content_element_margin_style_default' => '2em',
77
+ 'content_element_box_shadow_style_default' =>
78
+ '0 4px 6px -1px rgb(0 0 0 / 0.2), 0 2px 4px -2px rgb(0 0 0 / 0.15)',
79
+ 'box_shadow_clip_margin_bottom' => '3rem',
80
+ 'outline_color' => '#a0a0a080'
81
+ },
82
+ cards_appearance_section: {
83
+ 'section_default_padding_top' => 'max(10em, 20svh)',
84
+ 'section_default_padding_bottom' => 'max(10em, 20svh)'
85
+ }
86
+ }
87
+ )
88
+
89
+ legacy_paddings = {
90
+ properties: {
91
+ root: {
92
+ 'section_default_padding_top' => '1.375em',
93
+ 'section_default_padding_bottom' => '4.375em'
94
+ },
95
+ cards_appearance_section: {
96
+ 'section_default_padding_top' => '3em',
97
+ 'section_default_padding_bottom' => '6em'
98
+ }
99
+ }
100
+ }
101
+
102
+ c.themes.register_options_transform(lambda { |options, entry:, **|
103
+ if entry.layout_version
104
+ options
105
+ else
106
+ options.deep_merge(legacy_paddings)
107
+ end
108
+ })
109
+
110
+ c.themes.register_default_options(
111
+ typography: {
112
+ 'counterNumber-xxxl' => {
113
+ font_size: '200px', line_height: '1',
114
+ sm: {font_size: '350px'}
115
+ },
116
+ 'counterNumber-xxl' => {
117
+ font_size: '150px', line_height: '1',
118
+ sm: {font_size: '265px'}
119
+ },
120
+ 'counterNumber-xl' => {
121
+ font_size: '110px', line_height: '1',
122
+ sm: {font_size: '200px'}
123
+ },
124
+ 'counterNumber-lg' => {
125
+ font_size: '86px', line_height: '1',
126
+ sm: {font_size: '150px'}
127
+ },
128
+ 'counterNumber-md' => {
129
+ font_size: '66px', line_height: '1',
130
+ sm: {font_size: '110px'}
131
+ },
132
+ 'counterNumber-sm' => {
133
+ font_size: '52px', line_height: '1',
134
+ sm: {font_size: '86px'}
135
+ },
136
+ 'counterNumber-xs' => {
137
+ font_size: '40px', line_height: '1.1',
138
+ sm: {font_size: '66px', line_height: '1'}
139
+ },
140
+ 'counterNumber-xxs' => {
141
+ font_size: '34px', line_height: '1.1',
142
+ sm: {font_size: '52px', line_height: '1'}
143
+ },
144
+ 'counterNumber-xxxs' => {
145
+ font_size: '28px', line_height: '1.1',
146
+ sm: {font_size: '40px', line_height: '1'}
147
+ },
148
+ 'counterUnit-md' => {font_size: '1em'},
149
+ 'counterUnit-sm' => {font_size: '0.7em'},
150
+ 'counterUnit-xs' => {font_size: '0.5em'},
151
+ 'counterDescription-lg' => {
152
+ font_size: '28px', line_height: '1.1',
153
+ sm: {font_size: '40px', line_height: '1'}
154
+ },
155
+ 'counterDescription-md' => {font_size: '22px'},
156
+ 'counterDescription-sm' => {font_size: '18px'}
157
+ }
158
+ )
159
+
10
160
  c.file_types.register(Pageflow::BuiltInFileType.image)
11
161
  c.file_types.register(Pageflow::BuiltInFileType.video)
12
162
  c.file_types.register(Pageflow::BuiltInFileType.audio)
@@ -14,7 +164,8 @@ module PageflowScrolled
14
164
 
15
165
  c.revision_components.register(Storyline, create_defaults: true)
16
166
 
17
- ['tikTokEmbed', 'hotspots'].each do |name|
167
+ ['tikTokEmbed', 'twitterEmbed', 'hotspots', 'socialEmbed',
168
+ 'videoEmbed', 'inlineBeforeAfter'].each do |name|
18
169
  c.additional_frontend_packs.register(
19
170
  "pageflow-scrolled/contentElements/#{name}-frontend",
20
171
  content_element_type_names: [name]
@@ -27,42 +178,75 @@ module PageflowScrolled
27
178
  c.widget_types.register(ReactWidgetType.new(name: 'consentBar',
28
179
  role: 'consent'),
29
180
  default: true)
30
-
31
181
  c.widget_types.register(ReactWidgetType.new(name: 'iconInlineFileRights',
32
182
  role: 'inlineFileRights'),
33
183
  default: true)
34
184
  c.widget_types.register(ReactWidgetType.new(name: 'textInlineFileRights',
35
185
  role: 'inlineFileRights'))
36
186
 
187
+ c.features.register('excursion_sheets') do |feature_config|
188
+ feature_config.widget_types.register(
189
+ ReactWidgetType.new(name: 'excursionSheet',
190
+ role: 'excursion'),
191
+ default: true
192
+ )
193
+
194
+ feature_config.widget_types.register(
195
+ ReactWidgetType.new(name: 'mainStorylineSheet',
196
+ role: 'mainStoryline'),
197
+ default: true
198
+ )
199
+ end
200
+
201
+ c.features.enable_by_default('excursion_sheets')
202
+
37
203
  c.features.register('icon_scroll_indicator') do |feature_config|
38
204
  feature_config.widget_types.register(
39
205
  ReactWidgetType.new(name: 'iconScrollIndicator',
40
- role: 'scrollIndicator'),
41
- default: true
206
+ role: 'scrollIndicator')
207
+ )
208
+ end
209
+
210
+ c.features.register('lottie_animation_content_element') do |feature_config|
211
+ feature_config.file_types.register(PageflowScrolled.lottie_file_type)
212
+
213
+ feature_config.additional_frontend_packs.register(
214
+ 'pageflow-scrolled/contentElements/lottieAnimation-frontend',
215
+ content_element_type_names: ['lottieAnimation']
42
216
  )
43
217
  end
44
218
 
45
219
  c.features.register('datawrapper_chart_embed_opt_in')
46
220
  c.features.enable_by_default('datawrapper_chart_embed_opt_in')
47
221
  c.features.register('iframe_embed_content_element')
48
- c.features.register('frontend_v2')
222
+ c.features.register('social_embed_content_element')
223
+ c.features.register('legacy_social_embed_content_elements')
49
224
  c.features.register('scrolled_entry_fragment_caching')
50
225
  c.features.register('backdrop_content_elements')
51
226
  c.features.register('custom_palette_colors')
52
- c.features.register('decoration_effects')
53
- c.features.register('content_element_margins')
54
227
  c.features.register('backdrop_size')
55
- c.features.register('section_paddings')
228
+ c.features.register('commenting')
229
+ c.features.register('image_srcset')
230
+ c.features.register('file_rights_from_references')
231
+ c.features.enable_by_default('image_srcset')
232
+ c.features.enable_by_default('file_rights_from_references')
56
233
 
57
- c.additional_frontend_seed_data.register(
58
- 'frontendVersion',
59
- FRONTEND_VERSION_SEED_DATA
60
- )
234
+ c.features.register('faq_page_structured_data') do |feature_config|
235
+ feature_config.entry_structured_data_types.register(
236
+ :faq_page,
237
+ PageflowScrolled::EntryStructuredDataTypes::FaqPage.new
238
+ )
239
+ end
61
240
 
62
241
  c.content_element_consent_vendors.register(
63
242
  IFRAME_EMBED_CONSENT_VENDOR,
64
243
  content_element_type_name: 'iframeEmbed'
65
244
  )
245
+
246
+ c.content_element_consent_vendors.register(
247
+ SOCIAL_EMBED_CONSENT_VENDOR,
248
+ content_element_type_name: 'socialEmbed'
249
+ )
66
250
  end
67
251
  end
68
252
 
@@ -70,21 +254,20 @@ module PageflowScrolled
70
254
  return unless configuration['requireConsent']
71
255
 
72
256
  uri = URI.parse(configuration['source'])
73
- host_matchers = Pageflow.config_for(entry).consent_vendor_host_matchers
257
+ url_matchers = Pageflow.config_for(entry).consent_vendor_url_matchers
74
258
 
75
- host_matchers.detect { |matcher, _|
76
- uri.host =~ matcher
259
+ url_matchers.detect { |matcher, _|
260
+ (uri.host + uri.path) =~ matcher
77
261
  }&.last
78
262
  rescue URI::InvalidURIError
79
263
  nil
80
264
  end
81
265
 
82
- FRONTEND_VERSION_SEED_DATA = lambda do |request:, entry:, **|
83
- if request.params[:frontend] == 'v2' || entry.feature_state('frontend_v2')
84
- 2
85
- else
86
- 1
87
- end
266
+ SOCIAL_EMBED_CONSENT_VENDOR = lambda do |configuration:, **|
267
+ provider = configuration['provider']
268
+ valid_providers = ['x', 'instagram', 'bluesky', 'tiktok']
269
+
270
+ valid_providers.include?(provider) ? provider : nil
88
271
  end
89
272
  end
90
273
  end
@@ -38,10 +38,8 @@ module PageflowScrolled
38
38
  end
39
39
 
40
40
  # @api private
41
- def self.all_for(entry)
42
- Pageflow.config_for(entry).widget_types.select do |widget_type|
43
- widget_type.insert_point == :react
44
- end
41
+ def packs(**)
42
+ [{path: pack, stylesheet: true}]
45
43
  end
46
44
  end
47
45
  end
@@ -24,6 +24,12 @@ module PageflowScrolled
24
24
  # @option attributes [Hash] :video_files A hash mapping video
25
25
  # names used in properties like `backdrop.video` to urls.
26
26
  # @option attributes [Hash] :text_track_files A hash mapping text track files to urls.
27
+ #
28
+ # Any further attribute ending in `_files` is interpreted as the
29
+ # collection name of a registered file type. Passing `lottie_files`,
30
+ # for example, creates files of the file type registered with
31
+ # collection name `lottie_files`.
32
+ #
27
33
  # @yield [entry] a block to be called before the entry is saved
28
34
  # @param [Hash] options options for entry and files creation
29
35
  # @option options [Boolean] :skip_encoding
@@ -36,12 +42,10 @@ module PageflowScrolled
36
42
  .first
37
43
 
38
44
  if entry.nil?
39
- entry = Pageflow::Entry.create!(type_name: 'scrolled',
40
- **attributes.except(:chapters,
41
- :image_files,
42
- :video_files,
43
- :audio_files,
44
- :text_track_files)) do |created_entry|
45
+ entry = Pageflow::Entry.create!(
46
+ type_name: 'scrolled',
47
+ **attributes.except(:chapters, *file_collection_names(attributes))
48
+ ) do |created_entry|
45
49
  created_entry.site = attributes.fetch(:account).default_site
46
50
 
47
51
  say_creating_scrolled_entry(created_entry)
@@ -50,29 +54,8 @@ module PageflowScrolled
50
54
 
51
55
  draft_entry = Pageflow::DraftEntry.new(entry)
52
56
 
53
- image_files_by_name = create_files(draft_entry,
54
- :image,
55
- attributes.fetch(:image_files, {}))
56
-
57
- video_files_by_name = create_files(draft_entry,
58
- :video,
59
- attributes.fetch(:video_files, {}),
60
- skip_encoding: options.fetch(:skip_encoding, false))
61
-
62
- audio_files_by_name = create_files(draft_entry,
63
- :audio,
64
- attributes.fetch(:audio_files, {}),
65
- skip_encoding: options.fetch(:skip_encoding, false))
66
-
67
- files_by_name = image_files_by_name.merge(video_files_by_name).merge(audio_files_by_name)
68
-
69
- # rewrite parent file references to actual ids
70
- text_tracks_by_name = attributes.fetch(:text_track_files, {})
71
- text_tracks_by_name.each_value do |text_track_config|
72
- parent_file = files_by_name.fetch(text_track_config['parent_file_id'])
73
- text_track_config['parent_file_id'] = parent_file.id
74
- end
75
- create_files(draft_entry, :text_track, text_tracks_by_name)
57
+ files_by_name = create_top_level_files(draft_entry, attributes, options)
58
+ create_text_track_files(draft_entry, attributes, files_by_name)
76
59
 
77
60
  attributes[:chapters].each_with_index do |chapter_config, i|
78
61
  create_chapter(entry, chapter_config, i, files_by_name)
@@ -92,24 +75,53 @@ module PageflowScrolled
92
75
  say(" sample scrolled entry '#{entry.title}'\n")
93
76
  end
94
77
 
95
- def create_files(draft_entry, file_type, file_data_by_name, skip_encoding: false)
78
+ def file_collection_names(attributes)
79
+ attributes.keys.select { |name| name.to_s.end_with?('_files') }
80
+ end
81
+
82
+ def create_top_level_files(draft_entry, attributes, options)
83
+ collection_names = file_collection_names(attributes) - [:text_track_files]
84
+
85
+ collection_names.reduce({}) do |files_by_name, collection_name|
86
+ files_by_name.merge(
87
+ create_files(draft_entry,
88
+ collection_name.to_s,
89
+ attributes.fetch(collection_name),
90
+ skip_encoding: options.fetch(:skip_encoding, false))
91
+ )
92
+ end
93
+ end
94
+
95
+ def create_text_track_files(draft_entry, attributes, files_by_name)
96
+ text_tracks_by_name = attributes.fetch(:text_track_files, {})
97
+
98
+ text_tracks_by_name.each_value do |text_track_config|
99
+ parent_file = files_by_name.fetch(text_track_config['parent_file_id'])
100
+ text_track_config['parent_file_id'] = parent_file.id
101
+ end
102
+
103
+ create_files(draft_entry, 'text_track_files', text_tracks_by_name)
104
+ end
105
+
106
+ def create_files(draft_entry, collection_name, file_data_by_name, skip_encoding: false)
107
+ file_type = Pageflow.config.file_types.find_by_collection_name!(collection_name)
108
+
96
109
  file_data_by_name.transform_values do |data|
97
- say(" creating #{file_type} file from #{data['url']}")
110
+ say(" creating #{collection_name.delete_suffix('_files')} file from #{data['url']}")
98
111
 
99
- file_state = %i[image text_track].include?(file_type) ? 'processed' : 'uploading'
100
112
  uri = URI.parse(data['url'])
101
- file = draft_entry.create_file!(Pageflow::BuiltInFileType.send(file_type),
102
- state: file_state,
113
+ file = draft_entry.create_file!(file_type,
114
+ state: initial_file_state(collection_name),
103
115
  attachment: uri,
104
116
  display_name: File.basename(uri.path, '*'),
105
117
  configuration: data['configuration'],
106
118
  parent_file_model_type: data['parent_file_model_type'],
107
119
  parent_file_id: data['parent_file_id'],
108
120
  **data.slice('width', 'height').symbolize_keys)
109
- if %i[audio video].include?(file_type)
121
+ if %w[audio_files video_files].include?(collection_name)
110
122
  if skip_encoding
111
123
  file.update!(state: 'encoded')
112
- if file_type.eql?(:video)
124
+ if collection_name == 'video_files'
113
125
  file.update!(output_presences: {
114
126
  'dash-playlist' => true,
115
127
  'hls-playlist' => true,
@@ -133,6 +145,14 @@ module PageflowScrolled
133
145
  end
134
146
  end
135
147
 
148
+ def initial_file_state(collection_name)
149
+ case collection_name
150
+ when 'image_files', 'text_track_files' then 'processed'
151
+ when 'audio_files', 'video_files' then 'uploading'
152
+ else 'uploaded'
153
+ end
154
+ end
155
+
136
156
  def create_chapter(entry, chapter_config, position, files_by_name)
137
157
  section_configs = chapter_config.delete('sections') || []
138
158
  chapter = Chapter.create!(
@@ -0,0 +1,35 @@
1
+ module PageflowScrolled
2
+ # Callable that ensures a scale with the given prefix is defined
3
+ # in theme options. If the theme already defines any properties
4
+ # with the prefix, the defaults are not added.
5
+ #
6
+ # @api private
7
+ class ThemeOptionsDefaultScale
8
+ def initialize(prefix:, values:)
9
+ @prefix = prefix
10
+ @values = values
11
+ end
12
+
13
+ def call(options, **)
14
+ return options if scale_defined?(options)
15
+
16
+ options.deep_merge(
17
+ properties: {
18
+ root: prefixed_values
19
+ }
20
+ )
21
+ end
22
+
23
+ private
24
+
25
+ def scale_defined?(options)
26
+ options.dig(:properties, :root)&.keys&.any? do |key|
27
+ key.to_s.start_with?("#{@prefix}-")
28
+ end
29
+ end
30
+
31
+ def prefixed_values
32
+ @values.transform_keys { |key| "#{@prefix}-#{key}" }
33
+ end
34
+ end
35
+ end
@@ -7,6 +7,13 @@ module PageflowScrolled
7
7
  PageflowScrolled::Plugin.new
8
8
  end
9
9
 
10
+ def lottie_file_type
11
+ Pageflow::FileType.new(model: 'PageflowScrolled::LottieFile',
12
+ collection_name: 'lottie_files',
13
+ url_templates: LottieFileUrlTemplates.new,
14
+ top_level_type: true)
15
+ end
16
+
10
17
  def entry_type
11
18
  Pageflow::EntryType.new(name: 'scrolled',
12
19
  frontend_app: PageflowScrolled::EntriesController.action(:show),
@@ -17,6 +24,7 @@ module PageflowScrolled
17
24
  theme_files: {
18
25
  logo_mobile: LOGO_OPTIONS,
19
26
  logo_desktop: LOGO_OPTIONS,
27
+ font: FONT_OPTIONS,
20
28
  **FAVICONS
21
29
  })
22
30
  end
@@ -40,6 +48,11 @@ module PageflowScrolled
40
48
  end
41
49
  }.freeze
42
50
 
51
+ FONT_OPTIONS = {
52
+ content_type: %r{\A(font/woff2?|application/(x-)?font-woff2?)\z},
53
+ styles: {original: {}}
54
+ }.freeze
55
+
43
56
  FAVICONS = {
44
57
  favicon: {
45
58
  content_type: %r{\Aimage/svg\+xml\z},
@@ -26,10 +26,15 @@ namespace :pageflow_scrolled do
26
26
  Pageflow.config.paperclip_s3_root = ENV['PAGEFLOW_PAPERCLIP_S3_ROOT']
27
27
  end
28
28
 
29
+ # Runs which skip uploads reference the files uploaded by the
30
+ # last upstream run. Since the storage path contains the file
31
+ # name, both need to use the original file name instead of the
32
+ # random one normally generated for uploads.
33
+ Pageflow::DraftEntry.class_eval { def generate_file_name(file_name) = file_name }
34
+
29
35
  if ENV['PAGEFLOW_SCROLLED_DB_SEED_SKIP_FILES'] == 'true'
30
36
  puts 'Skipping file uploads to S3.'
31
37
  Paperclip::Storage::S3.class_eval { def flush_writes; end }
32
- Pageflow::DraftEntry.class_eval { def generate_file_name(file_name) = file_name }
33
38
  end
34
39
 
35
40
  account = seeds.account(name: 'storybook-seed') do |account_in_progress|
@@ -41,6 +46,11 @@ namespace :pageflow_scrolled do
41
46
  attributes: {
42
47
  title: 'Storybook seed',
43
48
  account:,
49
+ # File types registered inside a feature are only included in
50
+ # the seed's model types and url templates if the feature is
51
+ # enabled. Enabled on the entry, which is recreated on each
52
+ # run, since the account is only seeded once.
53
+ features_configuration: {'lottie_animation_content_element' => true},
44
54
  chapters: [],
45
55
  image_files: {
46
56
  turtle: {
@@ -96,6 +106,14 @@ namespace :pageflow_scrolled do
96
106
  }
97
107
  }.stringify_keys
98
108
  }.stringify_keys,
109
+ lottie_files: {
110
+ animation: {
111
+ url: 'https://s3-eu-west-1.amazonaws.com/de.codevise.pageflow.development/pageflow-next/seed-assets/lottie_animations/animation.lottie',
112
+ configuration: {
113
+ testReferenceName: 'lottieAnimation'
114
+ }
115
+ }.stringify_keys
116
+ },
99
117
  text_track_files: {
100
118
  sample: {
101
119
  url: 'https://s3-eu-west-1.amazonaws.com/de.codevise.pageflow.development/pageflow-next/seed-assets/text_tracks/sample.vtt',
@@ -0,0 +1,70 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ const packageRoot = path.join(__dirname, '..');
5
+ const engineRoot = path.join(packageRoot, '..');
6
+
7
+ const pageflowScrolledSchemas = {
8
+ patterns: [
9
+ path.join(packageRoot, 'src/contentElements/*/schema.json'),
10
+ path.join(packageRoot, 'src/frontend/schemas/*.json')
11
+ ],
12
+ outputFile: path.join(engineRoot, 'config/configuration_schemas/pageflow-scrolled.json')
13
+ };
14
+
15
+ /**
16
+ * Merge configuration schemas into a single JSON file, from where the
17
+ * gem ships them. The authored files live next to the code they
18
+ * describe.
19
+ *
20
+ * @param {Object} options
21
+ * @param {Array<string>} options.patterns - Paths of schema files. A `*`
22
+ * inside a path segment matches entries of the directory.
23
+ * @param {string} options.outputFile - Path of the merged JSON file.
24
+ *
25
+ * @returns {Array<string>} Paths of the merged files.
26
+ */
27
+ function generateConfigurationSchemas({patterns, outputFile}) {
28
+ const files = patterns.flatMap(expand).sort();
29
+ const schemas = files.map(file => JSON.parse(fs.readFileSync(file, 'utf8')));
30
+
31
+ fs.mkdirSync(path.dirname(outputFile), {recursive: true});
32
+ fs.writeFileSync(outputFile, `${JSON.stringify(schemas, null, 2)}\n`);
33
+
34
+ return files;
35
+ }
36
+
37
+ function expand(pattern) {
38
+ const segments = pattern.split(path.sep);
39
+ const index = segments.findIndex(segment => segment.includes('*'));
40
+
41
+ if (index < 0) {
42
+ return fs.existsSync(pattern) ? [pattern] : [];
43
+ }
44
+
45
+ const dir = segments.slice(0, index).join(path.sep) || '.';
46
+
47
+ if (!fs.existsSync(dir)) {
48
+ return [];
49
+ }
50
+
51
+ return matchingEntries(dir, segments[index]).flatMap(
52
+ name => expand([...segments.slice(0, index), name, ...segments.slice(index + 1)].join(path.sep))
53
+ );
54
+ }
55
+
56
+ function matchingEntries(dir, segment) {
57
+ const pattern = new RegExp(`^${segment.split('*').map(escapeRegExp).join('.*')}$`);
58
+
59
+ return fs.readdirSync(dir).filter(name => pattern.test(name));
60
+ }
61
+
62
+ function escapeRegExp(string) {
63
+ return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
64
+ }
65
+
66
+ module.exports = {pageflowScrolledSchemas, generateConfigurationSchemas};
67
+
68
+ if (require.main === module) {
69
+ generateConfigurationSchemas(pageflowScrolledSchemas);
70
+ }
@@ -0,0 +1,19 @@
1
+ const {generateConfigurationSchemas} = require('../configurationSchemas');
2
+
3
+ /**
4
+ * Rollup plugin merging configuration schemas into a single JSON file.
5
+ * Watching the merged files keeps the output up to date in watch mode.
6
+ *
7
+ * @param {Object} options - See `generateConfigurationSchemas`.
8
+ */
9
+ function configurationSchemas(options) {
10
+ return {
11
+ name: 'configuration-schemas',
12
+
13
+ buildStart() {
14
+ generateConfigurationSchemas(options).forEach(file => this.addWatchFile(file));
15
+ }
16
+ };
17
+ }
18
+
19
+ module.exports = {configurationSchemas};