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,19 +1,44 @@
1
1
  import $ from 'jquery';
2
2
  import _ from 'underscore';
3
- import { Object as Object$1 } from 'pageflow/ui';
3
+ import { Object } from 'pageflow/ui';
4
+ import { within } from '@testing-library/dom';
4
5
  import Backbone from 'backbone';
5
- import { Entry, Theme, FileTypes, FilesCollection, SubsetCollection, ImageFile, WidgetTypes, EditorApi, WidgetsCollection, VideoFile, TextTrackFile } from 'pageflow/editor';
6
- import { browser } from 'pageflow/frontend';
6
+ import { Entry, Theme, FileTypes, FilesCollection, SubsetCollection, ImageFile, WidgetTypes, EditorApi, FileFoldersCollection, WidgetsCollection, VideoFile, TextTrackFile } from 'pageflow/editor';
7
+ import { ReviewSession } from 'pageflow/review';
8
+ import { browser, features } from 'pageflow/frontend';
7
9
  import I18n from 'i18n-js';
8
10
 
9
- var Base = Object$1.extend({
10
- initialize: function initialize($el) {
11
+ let container;
12
+ afterEach(() => {
13
+ if (container) {
14
+ container.remove();
15
+ container = null;
16
+ }
17
+ });
18
+ function ensureContainer() {
19
+ if (!container) {
20
+ container = document.createElement('div');
21
+ document.body.appendChild(container);
22
+ }
23
+ }
24
+ function renderBackboneView(view) {
25
+ ensureContainer();
26
+ view.render();
27
+ container.appendChild(view.el);
28
+ if (view.onShow) {
29
+ view.onShow();
30
+ }
31
+ return within(view.el);
32
+ }
33
+
34
+ const Base = Object.extend({
35
+ initialize: function ($el) {
11
36
  this.$el = $el;
12
37
  }
13
38
  });
14
39
  Base.classMethods = function (Constructor) {
15
40
  return {
16
- find: function find(viewOrParentElement) {
41
+ find: function (viewOrParentElement) {
17
42
  var selector = Constructor.prototype.selector;
18
43
  var parentElement = viewOrParentElement.$el || viewOrParentElement;
19
44
  var element = parentElement.find(selector);
@@ -25,7 +50,7 @@ Base.classMethods = function (Constructor) {
25
50
  }
26
51
  return new Constructor(element);
27
52
  },
28
- findAll: function findAll(viewOrParentElement) {
53
+ findAll: function (viewOrParentElement) {
29
54
  var selector = Constructor.prototype.selector;
30
55
  var parentElement = viewOrParentElement.$el || viewOrParentElement;
31
56
  var elements = parentElement.find(selector);
@@ -33,7 +58,7 @@ Base.classMethods = function (Constructor) {
33
58
  return new Constructor($(this));
34
59
  }).get();
35
60
  },
36
- findBy: function findBy(predicate, options) {
61
+ findBy: function (predicate, options) {
37
62
  var predicateString = options.predicateName ? ' filtered by ' + options.predicateName : '';
38
63
  var selector = Constructor.prototype.selector;
39
64
  var selectorString = 'Selector "' + selector + '"' + predicateString;
@@ -49,35 +74,32 @@ Base.classMethods = function (Constructor) {
49
74
  }
50
75
  return new Constructor(element);
51
76
  },
52
- render: function render(view, options) {
53
- view.render();
54
- if (options && options.appendTo) {
55
- options.appendTo.append(view.$el);
56
- }
77
+ render: function (view) {
78
+ renderBackboneView(view);
57
79
  return new Constructor(view.$el);
58
80
  }
59
81
  };
60
82
  };
61
83
  Base.extend = function /* arguments */
62
84
  () {
63
- var result = Object$1.extend.apply(this, arguments);
85
+ var result = Object.extend.apply(this, arguments);
64
86
  _.extend(result, Base.classMethods(result));
65
87
  return result;
66
88
  };
67
89
 
68
- var DropDownButton = Base.extend({
90
+ const DropDownButton = Base.extend({
69
91
  selector: '.drop_down_button',
70
- menuItemNames: function menuItemNames() {
92
+ menuItemNames: function () {
71
93
  return this.$el.find('li:not(.is_hidden)').map(function () {
72
94
  return $(this).data('name');
73
95
  }).get();
74
96
  },
75
- menuItemLabels: function menuItemLabels() {
97
+ menuItemLabels: function () {
76
98
  return this.$el.find('li:not(.is_hidden) a').map(function () {
77
99
  return $(this).text();
78
100
  }).get();
79
101
  },
80
- selectMenuItemByName: function selectMenuItemByName(name) {
102
+ selectMenuItemByName: function (name) {
81
103
  var menuItem = this.$el.find('li:not(.is_hidden)').filter(function () {
82
104
  return $(this).data('name') == name;
83
105
  });
@@ -86,7 +108,7 @@ var DropDownButton = Base.extend({
86
108
  }
87
109
  menuItem.find('a').trigger('click');
88
110
  },
89
- selectMenuItemByLabel: function selectMenuItemByLabel(label) {
111
+ selectMenuItemByLabel: function (label) {
90
112
  var menuItemLink = this.$el.find('li:not(.is_hidden) a').filter(function () {
91
113
  return $(this).text() == label;
92
114
  });
@@ -97,48 +119,70 @@ var DropDownButton = Base.extend({
97
119
  }
98
120
  });
99
121
 
100
- var FileMetaDataTable = Base.extend({
122
+ const FileMetaDataTable = Base.extend({
101
123
  selector: '.file_meta_data table',
102
- values: function values() {
124
+ values: function () {
103
125
  return this.$el.find('.value').map(function () {
104
126
  return $(this).text();
105
127
  }).get();
106
128
  }
107
129
  });
108
130
 
109
- var FileStageItem = Base.extend({
131
+ const FileStageItem = Base.extend({
110
132
  selector: '.file_stage_item'
111
133
  });
112
134
 
113
- var FileThumbnail = Base.extend({
135
+ const FileThumbnail = Base.extend({
114
136
  selector: '.file_thumbnail',
115
- backgroundImage: function backgroundImage() {
137
+ backgroundImage: function () {
116
138
  return this.$el.css('backgroundImage');
117
139
  }
118
140
  });
119
141
 
120
- var ReferenceInput = Base.extend({
121
- clickChooseButton: function clickChooseButton() {
142
+ const Base$1 = Base.extend({
143
+ selector: '.input'
144
+ });
145
+ Base$1.findByPropertyName = function (propertyName, {
146
+ visible,
147
+ ...options
148
+ } = {}) {
149
+ return this.findBy(el => el.data('inputPropertyName') === propertyName && (!visible || !el.hasClass('hidden_via_binding')), {
150
+ predicateName: `${visible ? 'visible ' : ''}input property name '${propertyName}'`,
151
+ ...options
152
+ });
153
+ };
154
+
155
+ const FileInput = Base$1.extend({
156
+ menuItemNames: function () {
157
+ return DropDownButton.find(this.$el).menuItemNames();
158
+ },
159
+ selectMenuItemByName: function (name) {
160
+ DropDownButton.find(this.$el).selectMenuItemByName(name);
161
+ }
162
+ });
163
+
164
+ const ReferenceInput = Base.extend({
165
+ clickChooseButton: function () {
122
166
  this.$el.find('.choose').trigger('click');
123
167
  }
124
168
  });
125
169
 
126
- var StaticThumbnail = Base.extend({
170
+ const StaticThumbnail = Base.extend({
127
171
  selector: '.static_thumbnail',
128
- backgroundImage: function backgroundImage() {
172
+ backgroundImage: function () {
129
173
  return this.$el.css('backgroundImage');
130
174
  }
131
175
  });
132
176
 
133
- var ThemeItem = Base.extend({
177
+ const ThemeItem = Base.extend({
134
178
  selector: '.theme_item',
135
- hover: function hover() {
179
+ hover: function () {
136
180
  this.$el.trigger('mouseenter');
137
181
  },
138
- click: function click() {
182
+ click: function () {
139
183
  this.$el.trigger('click');
140
184
  },
141
- clickUseButton: function clickUseButton() {
185
+ clickUseButton: function () {
142
186
  this.$el.find('.use_theme').trigger('click');
143
187
  }
144
188
  });
@@ -150,177 +194,103 @@ ThemeItem.findByName = function (themeName, options) {
150
194
  }, options));
151
195
  };
152
196
 
153
- var ConfigurationEditorTab = Base.extend({
197
+ const ConfigurationEditorTab = Base.extend({
154
198
  selector: '.configuration_editor_tab',
155
- inputPropertyNames: function inputPropertyNames() {
199
+ inputPropertyNames: function () {
156
200
  return this.$el.find('.input').map(function () {
157
201
  return $(this).data('inputPropertyName');
158
202
  }).get();
159
203
  },
160
- visibleInputPropertyNames: function visibleInputPropertyNames() {
204
+ visibleInputPropertyNames: function () {
161
205
  return this.$el.find('.input:not(.hidden_via_binding)').map(function () {
162
206
  return $(this).data('inputPropertyName');
163
207
  }).get();
164
208
  },
165
- inputLabels: function inputLabels() {
209
+ inputLabels: function () {
166
210
  return this.$el.find('.input').map(function () {
167
211
  return $(this).data('labelText');
168
212
  }).get();
169
213
  },
170
- inlineHelpTexts: function inlineHelpTexts() {
214
+ inlineHelpTexts: function () {
171
215
  return this.$el.find('.input').map(function () {
172
216
  return $(this).data('inlineHelpText');
173
217
  }).get();
174
218
  }
175
219
  });
176
220
 
177
- var Tabs = Base.extend({
221
+ const Tabs = Base.extend({
178
222
  selector: '.tabs_view',
179
- tabNames: function tabNames() {
223
+ tabNames: function () {
180
224
  return this.$el.find('[data-tab-name]').map(function () {
181
225
  return $(this).data('tabName');
182
226
  }).get();
183
227
  },
184
- tabLabels: function tabLabels() {
228
+ tabLabels: function () {
185
229
  return this.$el.find('[data-tab-name]').map(function () {
186
230
  return $(this).text();
187
231
  }).get();
188
232
  }
189
233
  });
190
234
 
191
- var ConfigurationEditor = Base.extend({
235
+ const ConfigurationEditor = Base.extend({
192
236
  selector: '.configuration_editor',
193
- tabNames: function tabNames() {
237
+ tabNames: function () {
194
238
  return Tabs.find(this.$el).tabNames();
195
239
  },
196
- tabLabels: function tabLabels() {
240
+ tabLabels: function () {
197
241
  return Tabs.find(this.$el).tabLabels();
198
242
  },
199
- inputPropertyNames: function inputPropertyNames() {
243
+ inputPropertyNames: function () {
200
244
  return ConfigurationEditorTab.find(this.$el).inputPropertyNames();
201
245
  },
202
- visibleInputPropertyNames: function visibleInputPropertyNames() {
246
+ visibleInputPropertyNames: function () {
203
247
  return ConfigurationEditorTab.find(this.$el).visibleInputPropertyNames();
204
248
  },
205
- inputLabels: function inputLabels() {
249
+ inputLabels: function () {
206
250
  return ConfigurationEditorTab.find(this.$el).inputLabels();
207
251
  },
208
- inlineHelpTexts: function inlineHelpTexts() {
252
+ inlineHelpTexts: function () {
209
253
  return ConfigurationEditorTab.find(this.$el).inlineHelpTexts();
210
254
  }
211
255
  });
212
256
 
213
- var Table = Base.extend({
257
+ const Table = Base.extend({
214
258
  selector: '.table_view',
215
- columnNames: function columnNames() {
259
+ columnNames: function () {
216
260
  return this.$el.find('th').map(function () {
217
261
  return $(this).data('columnName');
218
262
  }).get();
219
263
  }
220
264
  });
221
265
 
222
- var ColorInput = Base.extend({
223
- value: function value() {
224
- return this._input().val();
225
- },
226
- fillIn: function fillIn(value, clock) {
227
- this._input().val(value);
228
- this._input().trigger('keyup');
229
- clock.tick(500);
230
- },
231
- swatches: function swatches() {
232
- return this.$el.find('.minicolors-swatches span').map(function () {
233
- return window.getComputedStyle(this)['background-color'];
234
- }).get();
235
- },
236
- _input: function _input() {
237
- return this.$el.find('input');
238
- }
239
- });
240
-
241
- function _defineProperty(obj, key, value) {
242
- if (key in obj) {
243
- Object.defineProperty(obj, key, {
244
- value: value,
245
- enumerable: true,
246
- configurable: true,
247
- writable: true
248
- });
249
- } else {
250
- obj[key] = value;
251
- }
252
-
253
- return obj;
254
- }
255
-
256
- function ownKeys(object, enumerableOnly) {
257
- var keys = Object.keys(object);
258
-
259
- if (Object.getOwnPropertySymbols) {
260
- var symbols = Object.getOwnPropertySymbols(object);
261
- if (enumerableOnly) symbols = symbols.filter(function (sym) {
262
- return Object.getOwnPropertyDescriptor(object, sym).enumerable;
263
- });
264
- keys.push.apply(keys, symbols);
265
- }
266
-
267
- return keys;
268
- }
269
-
270
- function _objectSpread2(target) {
271
- for (var i = 1; i < arguments.length; i++) {
272
- var source = arguments[i] != null ? arguments[i] : {};
273
-
274
- if (i % 2) {
275
- ownKeys(Object(source), true).forEach(function (key) {
276
- _defineProperty(target, key, source[key]);
277
- });
278
- } else if (Object.getOwnPropertyDescriptors) {
279
- Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
280
- } else {
281
- ownKeys(Object(source)).forEach(function (key) {
282
- Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
283
- });
284
- }
285
- }
286
-
287
- return target;
288
- }
289
-
290
- var Base$1 = Base.extend({
291
- selector: '.input'
292
- });
293
- Base$1.findByPropertyName = function (propertyName, options) {
294
- return this.findBy(function (el) {
295
- return el.data('inputPropertyName') === propertyName;
296
- }, _objectSpread2({
297
- predicateName: "input property name '".concat(propertyName, "'")
298
- }, options));
299
- };
300
-
301
- var RadioButtonGroupInput = Base$1.extend({
302
- values: function values() {
266
+ const RadioButtonGroupInput = Base$1.extend({
267
+ values: function () {
303
268
  return this.$el.find('input').map(function () {
304
269
  return $(this).attr('value');
305
270
  }).get();
306
271
  },
307
- enabledValues: function enabledValues() {
272
+ enabledValues: function () {
308
273
  return this.$el.find('input:not([disabled])').map(function () {
309
274
  return $(this).attr('value');
310
275
  }).get();
311
276
  }
312
277
  });
313
278
 
314
- var SelectInput = Base$1.extend({
315
- value: function value() {
279
+ const SelectInput = Base$1.extend({
280
+ value: function () {
316
281
  return this.$el.find('select').val();
317
282
  },
318
- values: function values() {
283
+ values: function () {
319
284
  return this.$el.find('option').map(function () {
320
285
  return $(this).attr('value');
321
286
  }).get();
322
287
  },
323
- enabledValues: function enabledValues() {
288
+ texts: function () {
289
+ return this.$el.find('option').map(function () {
290
+ return $(this).text();
291
+ }).get();
292
+ },
293
+ enabledValues: function () {
324
294
  return this.$el.find('option:not([disabled])').map(function () {
325
295
  return $(this).attr('value');
326
296
  }).get();
@@ -330,7 +300,7 @@ var SelectInput = Base$1.extend({
330
300
  /**
331
301
  * Build editor Backbone models for tests.
332
302
  */
333
- var factories = {
303
+ const factories = {
334
304
  /**
335
305
  * Build an entry model.
336
306
  *
@@ -355,17 +325,18 @@ var factories = {
355
325
  * }
356
326
  * });
357
327
  */
358
- entry: function entry(model, attributes) {
359
- var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
328
+ entry: function entry(model, attributes, options = {}) {
360
329
  if (typeof model !== 'function') {
361
330
  return factories.entry(Entry, model, attributes);
362
331
  }
363
332
  ensureFileTypes(options);
364
333
  ensureFilesCollections(options);
334
+ ensureFileFoldersCollection(options);
365
335
  ensureWidgetsCollections(options);
366
- var entry = new model(_objectSpread2({
367
- id: 1
368
- }, attributes), _.extend({
336
+ const entry = new model({
337
+ id: 1,
338
+ ...attributes
339
+ }, _.extend({
369
340
  storylines: new Backbone.Collection(),
370
341
  chapters: new Backbone.Collection()
371
342
  }, options));
@@ -377,6 +348,42 @@ var factories = {
377
348
  theme: function theme(attributes, options) {
378
349
  return new Theme(attributes, options);
379
350
  },
351
+ /**
352
+ * Build a real `ReviewSession` pre-populated with state — suitable for
353
+ * Backbone view specs that would otherwise stub out the session.
354
+ *
355
+ * Commenting UI is always gated on a signed-in user; the `currentUser`
356
+ * default reflects that. Specs override it only when they care about
357
+ * the current user's identity (permissions, ownership, etc.).
358
+ *
359
+ * @param {Object} [options]
360
+ * @param {Object} [options.currentUser] - Current user exposed via `session.state.currentUser`.
361
+ * @param {Array} [options.commentThreads] - Seed threads exposed via `session.state.commentThreads`.
362
+ * @param {Object} [options.entryId] - Entry id used when constructing request URLs.
363
+ * @param {Function} [options.request] - Override the request function. Defaults to a jest mock resolving to the seeded state.
364
+ * @returns {ReviewSession}
365
+ */
366
+ reviewSession: function reviewSession({
367
+ currentUser = {
368
+ id: 1,
369
+ name: 'Test User'
370
+ },
371
+ commentThreads = [],
372
+ entryId = 1,
373
+ request
374
+ } = {}) {
375
+ return new ReviewSession({
376
+ entryId,
377
+ request: request || jest.fn().mockResolvedValue({
378
+ currentUser,
379
+ commentThreads
380
+ }),
381
+ initialState: {
382
+ currentUser,
383
+ commentThreads
384
+ }
385
+ });
386
+ },
380
387
  /**
381
388
  * Construct a file type registry that can be passed to {@link
382
389
  * #factoriesentry factories.entry}.
@@ -391,11 +398,11 @@ var factories = {
391
398
  * @param {Function} fn - Build function.
392
399
  * @returns {FileTypes} - A file Type registry
393
400
  */
394
- fileTypes: function fileTypes(fn) {
401
+ fileTypes: function (fn) {
395
402
  var fileTypes = new FileTypes();
396
403
  var fileTypesSetupArray = [];
397
404
  var builder = {
398
- withImageFileType: function withImageFileType(options) {
405
+ withImageFileType: function (options) {
399
406
  fileTypes.register('image_files', _.extend({
400
407
  model: ImageFile,
401
408
  matchUpload: /^image/,
@@ -408,7 +415,7 @@ var factories = {
408
415
  });
409
416
  return this;
410
417
  },
411
- withVideoFileType: function withVideoFileType(options) {
418
+ withVideoFileType: function (options) {
412
419
  fileTypes.register('video_files', _.extend({
413
420
  model: VideoFile,
414
421
  matchUpload: /^video/,
@@ -424,7 +431,7 @@ var factories = {
424
431
  });
425
432
  return this;
426
433
  },
427
- withAudioFileType: function withAudioFileType(options) {
434
+ withAudioFileType: function (options) {
428
435
  fileTypes.register('audio_files', _.extend({
429
436
  model: VideoFile,
430
437
  matchUpload: /^audio/,
@@ -440,7 +447,7 @@ var factories = {
440
447
  });
441
448
  return this;
442
449
  },
443
- withTextTrackFileType: function withTextTrackFileType(options) {
450
+ withTextTrackFileType: function (options) {
444
451
  fileTypes.register('text_track_files', _.extend({
445
452
  model: TextTrackFile,
446
453
  matchUpload: /vtt$/
@@ -465,26 +472,26 @@ var factories = {
465
472
  * @param {Object} options - File type options passed to withImageFileType,
466
473
  * @returns {FileTypes} - A file Type registry.
467
474
  */
468
- fileTypesWithImageFileType: function fileTypesWithImageFileType(options) {
475
+ fileTypesWithImageFileType: function (options) {
469
476
  return this.fileTypes(function () {
470
477
  this.withImageFileType(options);
471
478
  });
472
479
  },
473
- imageFileType: function imageFileType(options) {
480
+ imageFileType: function (options) {
474
481
  return factories.fileTypesWithImageFileType(options).first();
475
482
  },
476
- fileType: function fileType(options) {
483
+ fileType: function (options) {
477
484
  return factories.imageFileType(options);
478
485
  },
479
- filesCollection: function filesCollection(options) {
486
+ filesCollection: function (options) {
480
487
  return FilesCollection.createForFileType(options.fileType, [{}, {}]);
481
488
  },
482
- nestedFilesCollection: function nestedFilesCollection(options) {
489
+ nestedFilesCollection: function (options) {
483
490
  return new SubsetCollection({
484
491
  parentModel: factories.file({
485
492
  file_name: options.parentFileName
486
493
  }),
487
- filter: function filter() {
494
+ filter: function () {
488
495
  return true;
489
496
  },
490
497
  parent: factories.filesCollection({
@@ -492,7 +499,7 @@ var factories = {
492
499
  })
493
500
  });
494
501
  },
495
- videoFileWithTextTrackFiles: function videoFileWithTextTrackFiles(options) {
502
+ videoFileWithTextTrackFiles: function (options) {
496
503
  var fileTypes = this.fileTypes(function () {
497
504
  this.withVideoFileType(options.videoFileTypeOptions);
498
505
  this.withTextTrackFileType(options.textTrackFileTypeOptions);
@@ -522,7 +529,7 @@ var factories = {
522
529
  textTrackFiles: textTrackFiles
523
530
  };
524
531
  },
525
- imageFilesFixture: function imageFilesFixture(options) {
532
+ imageFilesFixture: function (options) {
526
533
  var fileTypes = this.fileTypes(function () {
527
534
  this.withImageFileType(options.fileTypeOptions);
528
535
  });
@@ -543,15 +550,15 @@ var factories = {
543
550
  imageFiles: imageFiles
544
551
  };
545
552
  },
546
- imageFile: function imageFile(attributes, options) {
553
+ imageFile: function (attributes, options) {
547
554
  return new ImageFile(attributes, _.extend({
548
555
  fileType: this.imageFileType()
549
556
  }, options));
550
557
  },
551
- file: function file(attributes, options) {
558
+ file: function (attributes, options) {
552
559
  return this.imageFile(attributes, options);
553
560
  },
554
- widgetTypes: function widgetTypes(attributesList, beforeSetup) {
561
+ widgetTypes: function (attributesList, beforeSetup) {
555
562
  var widgetTypes = new WidgetTypes();
556
563
  var attributesListsByRole = {};
557
564
  _(attributesList).each(function (attributes) {
@@ -566,11 +573,12 @@ var factories = {
566
573
  widgetTypes.setup(attributesListsByRole);
567
574
  return widgetTypes;
568
575
  },
569
- editorApi: function editorApi(beforeSetup) {
576
+ editorApi: function (beforeSetup) {
570
577
  var api = new EditorApi({
571
578
  router: {
572
- navigate: function navigate(path, _ref) {
573
- var trigger = _ref.trigger;
579
+ navigate(path, {
580
+ trigger
581
+ }) {
574
582
  if (trigger) {
575
583
  api.trigger('navigate', path);
576
584
  }
@@ -603,6 +611,11 @@ function ensureFilesCollections(options) {
603
611
  options.files = FilesCollection.createForFileTypes(options.fileTypes, options.filesAttributes);
604
612
  }
605
613
  }
614
+ function ensureFileFoldersCollection(options) {
615
+ if (!options.fileFolders) {
616
+ options.fileFolders = new FileFoldersCollection(options.fileFoldersAttributes);
617
+ }
618
+ }
606
619
  function ensureWidgetsCollections(options) {
607
620
  if (!options.widgets) {
608
621
  options.widgets = new WidgetsCollection(options.widgetsAttributes, {
@@ -611,7 +624,7 @@ function ensureWidgetsCollections(options) {
611
624
  }
612
625
  }
613
626
 
614
- var userAgents = {
627
+ const userAgents = {
615
628
  'Safari on iPhone': 'Mozilla/5.0 (iPhone; CPU iPhone OS 10_0_1 like Mac OS X) ' + 'AppleWebKit/602.1.50 (KHTML, like Gecko) Version/10.0' + 'Mobile/14A403 Safari/602.1',
616
629
  'Safari on macOS': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14) ' + 'AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 ' + 'Safari/605.1.15',
617
630
  'Chrome on Android': 'Mozilla/5.0 (Linux; Android 10) ' + 'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106' + 'Mobile Safari/537.36',
@@ -620,12 +633,12 @@ var userAgents = {
620
633
  };
621
634
  function fakeBrowserAgent(name) {
622
635
  if (!userAgents[name]) {
623
- throw new Error("Unknown browser ".concat(name, "."));
636
+ throw new Error(`Unknown browser ${name}.`);
624
637
  }
625
638
  return new browser.Agent(userAgents[name]);
626
639
  }
627
640
 
628
- var state = window.pageflow || {};
641
+ const state = window.pageflow || {};
629
642
 
630
643
  /**
631
644
  * Setup global state for testing Backbone editor components.
@@ -639,16 +652,16 @@ var state = window.pageflow || {};
639
652
  * Properties to set on the global state. Functions as values will
640
653
  * be evaluated and the return value will be assigned instead.
641
654
  */
642
- var setupGlobals = function setupGlobals(mapping) {
643
- var globalsBackup;
644
- beforeEach(function () {
655
+ const setupGlobals = function (mapping) {
656
+ let globalsBackup;
657
+ beforeEach(() => {
645
658
  if (globalsBackup) {
646
659
  throw new Error('There can only be one setupGlobals call per test.');
647
660
  }
648
661
  globalsBackup = {};
649
662
  setGlobals(mapping);
650
663
  });
651
- afterEach(function () {
664
+ afterEach(() => {
652
665
  _.each(mapping, function (_, key) {
653
666
  state[key] = globalsBackup[key];
654
667
  });
@@ -662,13 +675,60 @@ var setupGlobals = function setupGlobals(mapping) {
662
675
  return mapping;
663
676
  }
664
677
  return {
665
- setGlobals: setGlobals
678
+ setGlobals
666
679
  };
667
680
  };
668
681
 
682
+ /**
683
+ * Enable feature flags for the surrounding describe block.
684
+ *
685
+ * Each `beforeEach` calls `features.enable(scope, names)`, which both
686
+ * flips `features.isEnabled` to true for the given names and runs any
687
+ * functions registered via `features.register` for them. Each
688
+ * `afterEach` restores the set of enabled features to whatever was
689
+ * enabled before the helper was invoked, so suites do not leak state
690
+ * into each other.
691
+ *
692
+ * Multiple calls within the same describe block (or across nested
693
+ * describes) compose: each call adds its own features on top of
694
+ * whatever previous `useFakeFeatures` calls already enabled.
695
+ *
696
+ * @param {String} scope -
697
+ * Name of the scope to enable the features in (e.g. `'frontend'`,
698
+ * `'editor'`).
699
+ * @param {String[]} names -
700
+ * Feature names to enable in the given scope.
701
+ *
702
+ * @example
703
+ * import {useFakeFeatures} from 'pageflow/testHelpers';
704
+ * import {features} from 'pageflow/frontend';
705
+ *
706
+ * describe('...', () => {
707
+ * useFakeFeatures('frontend', ['commenting']);
708
+ *
709
+ * it('...', () => {
710
+ * expect(features.isEnabled('commenting')).toBe(true);
711
+ * });
712
+ * });
713
+ */
714
+ function useFakeFeatures(scope, names) {
715
+ let originalEnabledFeatureNames;
716
+ beforeEach(() => {
717
+ originalEnabledFeatureNames = features.enabledFeatureNames;
718
+ features.enable(scope, names);
719
+ });
720
+ afterEach(() => {
721
+ features.enabledFeatureNames = originalEnabledFeatureNames;
722
+ });
723
+ }
724
+
669
725
  /**
670
726
  * Define translations to use in tests.
671
727
  *
728
+ * Multiple calls within the same describe block (or across nested
729
+ * describes) compose: each call's translations are merged on top of
730
+ * whatever previous `useFakeTranslations` calls already provided.
731
+ *
672
732
  * @param {Object} translations -
673
733
  * A mapping of either the form `(translation key => translated
674
734
  * text)`. Translation keys can contains dots.
@@ -706,35 +766,35 @@ var setupGlobals = function setupGlobals(mapping) {
706
766
  * });
707
767
  * });
708
768
  */
709
- function useFakeTranslations(translations) {
710
- var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
711
- multiLocale = _ref.multiLocale;
712
- var originalTranslations;
769
+ function useFakeTranslations(translations, {
770
+ multiLocale
771
+ } = {}) {
772
+ let originalTranslations;
713
773
  beforeEach(function () {
714
774
  originalTranslations = I18n.translations;
775
+ const base = I18n.translations ? JSON.parse(JSON.stringify(I18n.translations)) : {};
715
776
  if (multiLocale) {
716
- I18n.translations = keysWithDotsToNestedObjects(translations);
777
+ applyTranslations(base, translations);
717
778
  } else {
718
- I18n.translations = {
719
- en: keysWithDotsToNestedObjects(translations)
720
- };
779
+ base.en = base.en || {};
780
+ applyTranslations(base.en, translations);
721
781
  }
782
+ I18n.translations = base;
722
783
  });
723
- afterEach(function () {
784
+ afterEach(() => {
724
785
  I18n.translations = originalTranslations;
725
786
  });
726
787
  }
727
- function keysWithDotsToNestedObjects(translations) {
728
- return _(translations).reduce(function (result, value, key) {
729
- var keys = key.split('.');
730
- var last = keys.pop();
731
- var inner = _(keys).reduce(function (r, key) {
732
- r[key] = r[key] || {};
733
- return r[key];
734
- }, result);
788
+ function applyTranslations(target, translations) {
789
+ _(translations).each((value, key) => {
790
+ const keys = key.split('.');
791
+ const last = keys.pop();
792
+ const inner = _(keys).reduce((r, k) => {
793
+ r[k] = r[k] || {};
794
+ return r[k];
795
+ }, target);
735
796
  inner[last] = value;
736
- return result;
737
- }, {});
797
+ });
738
798
  }
739
799
 
740
- export { ColorInput, ConfigurationEditor, ConfigurationEditorTab, DropDownButton, FileMetaDataTable, FileStageItem, FileThumbnail, RadioButtonGroupInput, ReferenceInput, SelectInput, StaticThumbnail, Table, Tabs, ThemeItem, factories, fakeBrowserAgent, setupGlobals, useFakeTranslations };
800
+ export { ConfigurationEditor, ConfigurationEditorTab, DropDownButton, FileInput, FileMetaDataTable, FileStageItem, FileThumbnail, Base$1 as Input, RadioButtonGroupInput, ReferenceInput, SelectInput, StaticThumbnail, Table, Tabs, ThemeItem, factories, fakeBrowserAgent, renderBackboneView, setupGlobals, useFakeFeatures, useFakeTranslations };