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
@@ -19,8 +19,8 @@ module PageflowScrolled
19
19
 
20
20
  # @api private
21
21
  def for(entry, request, options = {})
22
- items_for_entry(entry, options).each_with_object({}) do |item, result|
23
- result[item.name] = item.callable.call(entry:, request:, foo: 1)
22
+ items_for_entry(entry, options).to_h do |item|
23
+ [item.name, item.callable.call(entry:, request:, foo: 1)]
24
24
  end
25
25
  end
26
26
 
@@ -55,6 +55,26 @@ module PageflowScrolled
55
55
  # @since 17.1
56
56
  attr_reader :additional_theme_assets
57
57
 
58
+ # Paths or globs of JSON files to read configuration schemas
59
+ # from. Schemas describe the shape of configuration data of content
60
+ # elements, sections and other models. Used to find file references
61
+ # without going through the editor.
62
+ #
63
+ # @example
64
+ #
65
+ # config.configuration_schema_load_path += Dir[
66
+ # MyEngine.root.join('config', 'configuration_schemas', '*.json').to_s
67
+ # ]
68
+ #
69
+ # @return [Array<String>]
70
+ # @since 17.2
71
+ attr_accessor :configuration_schema_load_path
72
+
73
+ # @api private
74
+ def configuration_schemas
75
+ @configuration_schemas ||= ConfigurationSchemas.load(configuration_schema_load_path)
76
+ end
77
+
58
78
  # Determine which vendors a content element will require consent
59
79
  # for. Based on the vendor name returned here, the following
60
80
  # translations will be used in consent UI components.
@@ -80,18 +100,32 @@ module PageflowScrolled
80
100
  # @since 16.1
81
101
  attr_reader :content_element_consent_vendors
82
102
 
83
- # Mapping from URL hosts to consent vendor names. Used for iframe
84
- # embed opt-in.
103
+ # Mapping from URL host+path patterns to consent vendor names.
104
+ # Used for iframe embed opt-in.
85
105
  #
86
106
  # @exmaple
87
107
  #
88
- # entry_type_config.consent_vendor_host_matchers = {
89
- # /\.some-vendor\.com$/ => 'someVendor'
108
+ # entry_type_config.consent_vendor_url_matchers = {
109
+ # /\.some-vendor\.com\// => 'someVendor',
110
+ # /google\.com\/maps\/embed/ => 'googleMaps'
90
111
  # }
91
112
  #
92
113
  # @return [Hash<RegExp, String>]
114
+ # @since 17.2
115
+ attr_accessor :consent_vendor_url_matchers
116
+
117
+ # @deprecated Use {#consent_vendor_url_matchers=} instead.
118
+ # Rewrites trailing `$` in patterns to `/` and merges
119
+ # into {#consent_vendor_url_matchers}.
93
120
  # @since 16.1
94
- attr_accessor :consent_vendor_host_matchers
121
+ def consent_vendor_host_matchers=(matchers)
122
+ rewritten = matchers.transform_keys do |key|
123
+ source = key.source.sub(/\$$/, '/')
124
+ Regexp.new(source, key.options)
125
+ end
126
+
127
+ @consent_vendor_url_matchers.merge!(rewritten)
128
+ end
95
129
 
96
130
  # Migrate typography variants to palette colors. Before palette
97
131
  # colors for text blocks and headings were introduced, it was
@@ -147,6 +181,14 @@ module PageflowScrolled
147
181
  # @since 16.1
148
182
  attr_accessor :legacy_typography_variants
149
183
 
184
+ # Whether to include the legacy JavaScript Sprockets asset
185
+ # (`pageflow_scrolled/legacy`) in the head of published entries and
186
+ # previews. Defaults to `true`. Set to `false` once no code relies
187
+ # on the legacy bundle anymore.
188
+ #
189
+ # @since 17.2
190
+ attr_accessor :include_legacy_frontend_javascript
191
+
150
192
  def initialize(*)
151
193
  super
152
194
  @additional_frontend_packs = AdditionalPacks.new
@@ -154,10 +196,13 @@ module PageflowScrolled
154
196
 
155
197
  @additional_frontend_seed_data = AdditionalSeedData.new
156
198
  @additional_theme_assets = AdditionalThemeAssets.new
199
+ @configuration_schema_load_path = []
157
200
  @content_element_consent_vendors = ContentElementConsentVendors.new
158
- @consent_vendor_host_matchers = {}
201
+ @consent_vendor_url_matchers = {}
159
202
 
160
203
  @legacy_typography_variants = {}
204
+
205
+ @include_legacy_frontend_javascript = true
161
206
  end
162
207
  end
163
208
  end
@@ -0,0 +1,91 @@
1
+ module PageflowScrolled
2
+ # Look up schemas describing the shape of configuration data by the
3
+ # subject they apply to.
4
+ class ConfigurationSchemas
5
+ # Read schemas from JSON files. Each file contains either a single
6
+ # schema or an array of schemas.
7
+ #
8
+ # @param load_path [Array<String>] Paths or globs of JSON files.
9
+ #
10
+ # @api private
11
+ def self.load(load_path)
12
+ new(load_path.flat_map { |path| Dir[path] }.uniq.sort.flat_map { |file| documents_in(file) })
13
+ end
14
+
15
+ # Configuration objects are rebuilt for each request, so parsing
16
+ # results outlive them.
17
+ #
18
+ # @api private
19
+ def self.documents_in(file)
20
+ mtime = File.mtime(file)
21
+ cached_mtime, documents = cache[file]
22
+
23
+ return documents if cached_mtime == mtime
24
+
25
+ cache[file] = [mtime, Array.wrap(JSON.parse(File.read(file)))]
26
+ cache[file].last
27
+ end
28
+
29
+ # @api private
30
+ def self.cache
31
+ @cache ||= {}
32
+ end
33
+
34
+ # @api private
35
+ def initialize(documents)
36
+ @documents = documents
37
+ end
38
+
39
+ # @api private
40
+ def find(model:, type_name: nil)
41
+ by_subject[[model, type_name]]
42
+ end
43
+
44
+ # @api private
45
+ def find_by_id(id)
46
+ by_id[id]
47
+ end
48
+
49
+ # @api private
50
+ def type_names(model:)
51
+ by_subject.keys.filter_map { |subject_model, type_name| type_name if subject_model == model }
52
+ end
53
+
54
+ private
55
+
56
+ def by_subject
57
+ @by_subject ||= @documents.each_with_object({}) do |document, result|
58
+ subject = document['x-subject']
59
+ next unless subject
60
+
61
+ key = [subject['model'], subject['typeName']]
62
+ result[key] = result.key?(key) ? merge(result[key], document) : document
63
+ end
64
+ end
65
+
66
+ def merge(document, other)
67
+ document.merge(other) do |key, value, other_value|
68
+ if %w[properties $defs].include?(key)
69
+ merge_disjoint(value, other_value, key)
70
+ else
71
+ other_value
72
+ end
73
+ end
74
+ end
75
+
76
+ def merge_disjoint(value, other_value, key)
77
+ duplicates = value.keys & other_value.keys
78
+
79
+ if duplicates.any?
80
+ raise(ArgumentError,
81
+ "Conflicting #{key} in configuration schemas: #{duplicates.join(', ')}")
82
+ end
83
+
84
+ value.merge(other_value)
85
+ end
86
+
87
+ def by_id
88
+ @by_id ||= @documents.index_by { |document| document['$id'] }
89
+ end
90
+ end
91
+ end
@@ -21,7 +21,8 @@ module PageflowScrolled
21
21
  config.i18n.load_path += Dir[config.root.join('config', 'locales', '**', '*.yml').to_s]
22
22
 
23
23
  initializer 'pageflow_scrolled.assets.precompile' do |app|
24
- app.config.assets.precompile += %w[pageflow_scrolled/legacy.js]
24
+ app.config.assets.precompile += %w[pageflow_scrolled/legacy.js
25
+ pageflow_scrolled/ui.css]
25
26
  end
26
27
  end
27
28
  end
@@ -0,0 +1,71 @@
1
+ module PageflowScrolled
2
+ # Describe the places where the configurations of an entry can
3
+ # reference files.
4
+ #
5
+ # @api private
6
+ class EntryFileReferenceLocations
7
+ def initialize(entry_config, content_elements, include_unused: false)
8
+ @entry_config = entry_config
9
+ @content_elements = content_elements
10
+ @include_unused = include_unused
11
+ end
12
+
13
+ def content_element_locations
14
+ content_element_type_names.each_with_object({}) do |type_name, result|
15
+ schema = schemas.find(model: 'contentElement', type_name:)
16
+
17
+ if schema
18
+ result[type_name] = locations.for(schema)
19
+ else
20
+ log_missing_schema(type_name)
21
+ end
22
+ end
23
+ end
24
+
25
+ def section_locations
26
+ locations_for(model: 'section')
27
+ end
28
+
29
+ def entry_locations
30
+ locations_for(model: 'entry')
31
+ end
32
+
33
+ private
34
+
35
+ def locations_for(model:)
36
+ schema = schemas.find(model:)
37
+
38
+ unless schema
39
+ raise("Missing configuration schema for #{model}. Configuration schemas are " \
40
+ 'generated by the JavaScript build or by running ' \
41
+ 'yarn build-configuration-schemas inside the scrolled package.')
42
+ end
43
+
44
+ locations.for(schema)
45
+ end
46
+
47
+ # Content elements of any type can be added in the editor without
48
+ # reloading the seed.
49
+ def content_element_type_names
50
+ if @include_unused
51
+ schemas.type_names(model: 'contentElement')
52
+ else
53
+ @content_elements.map(&:type_name).uniq
54
+ end
55
+ end
56
+
57
+ def log_missing_schema(type_name)
58
+ return unless @entry_config.features.enabled?('file_rights_from_references')
59
+
60
+ Rails.logger.warn("Missing configuration schema for content element type '#{type_name}'")
61
+ end
62
+
63
+ def schemas
64
+ @schemas ||= @entry_config.configuration_schemas
65
+ end
66
+
67
+ def locations
68
+ @locations ||= FileReferenceLocations.new(schemas)
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,58 @@
1
+ module PageflowScrolled
2
+ module EntryStructuredDataTypes
3
+ # Generates Schema.org FAQPage structured data from question content elements
4
+ class FaqPage
5
+ def initialize(content_element_type_names: ['question'])
6
+ @content_element_type_names = content_element_type_names
7
+ end
8
+
9
+ def call(entry)
10
+ content_elements = PageflowScrolled::ContentElement
11
+ .all_for_revision(entry.revision)
12
+ .where(type_name: @content_element_type_names)
13
+
14
+ main_entity = content_elements.map { |element|
15
+ question_text = extract_text(element.configuration['question'])
16
+ answer_text = extract_text(element.configuration['answer'])
17
+
18
+ next if question_text.blank? || answer_text.blank?
19
+
20
+ {
21
+ '@type' => 'Question',
22
+ 'name' => question_text,
23
+ 'acceptedAnswer' => {
24
+ '@type' => 'Answer',
25
+ 'text' => answer_text
26
+ }
27
+ }
28
+ }.compact
29
+
30
+ {
31
+ '@type' => 'FAQPage',
32
+ 'mainEntity' => main_entity
33
+ }
34
+ end
35
+
36
+ private
37
+
38
+ def extract_text(slate_json)
39
+ return '' if slate_json.blank?
40
+
41
+ texts = []
42
+ collect_text(slate_json, texts)
43
+ texts.join.strip
44
+ end
45
+
46
+ def collect_text(nodes, texts)
47
+ return unless nodes.is_a?(Array)
48
+
49
+ nodes.each do |node|
50
+ if node.is_a?(Hash)
51
+ texts << node['text'] if node['text']
52
+ collect_text(node['children'], texts) if node['children']
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,69 @@
1
+ module PageflowScrolled
2
+ # Flatten a configuration schema into the places where references to
3
+ # files can occur.
4
+ class FileReferenceLocations
5
+ # @api private
6
+ def initialize(schemas)
7
+ @schemas = schemas
8
+ end
9
+
10
+ # @api private
11
+ def for(schema)
12
+ collect(schema, document: schema, path: [], seen: [])
13
+ end
14
+
15
+ private
16
+
17
+ def collect(schema, document:, path:, seen:)
18
+ if (ref = schema['$ref'])
19
+ return [] if seen.include?(ref)
20
+
21
+ schema, document = resolve(ref, document:)
22
+ seen += [ref]
23
+ end
24
+
25
+ return [] unless schema.is_a?(Hash)
26
+
27
+ references = schema['x-fileCollection'] ? [reference(schema, path)] : []
28
+
29
+ references +
30
+ branches(schema).flat_map { |branch| collect(branch, document:, path:, seen:) } +
31
+ children(schema).flat_map do |name, child|
32
+ collect(child, document:, path: path + [name], seen:)
33
+ end
34
+ end
35
+
36
+ def branches(schema)
37
+ Array(schema['anyOf']) + Array(schema['oneOf'])
38
+ end
39
+
40
+ def reference(schema, path)
41
+ {
42
+ 'path' => path,
43
+ 'collection' => schema['x-fileCollection'].camelize(:lower),
44
+ 'activeIf' => schema['x-activeIf']
45
+ }.compact
46
+ end
47
+
48
+ def children(schema)
49
+ children = schema['properties']&.dup || {}
50
+ nested = schema['items'] || schema['additionalProperties']
51
+
52
+ children['*'] = nested if nested.is_a?(Hash)
53
+ children
54
+ end
55
+
56
+ def resolve(ref, document:)
57
+ id, pointer = ref.split('#', 2)
58
+ target = id.empty? ? document : @schemas.find_by_id(id)
59
+
60
+ target ? [dig(target, pointer), target] : [nil, nil]
61
+ end
62
+
63
+ def dig(document, pointer)
64
+ return document if pointer.blank? || pointer == '/'
65
+
66
+ document.dig(*pointer.delete_prefix('/').split('/'))
67
+ end
68
+ end
69
+ end