pageflow 17.0.5 → 17.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +342 -41
- data/README.md +3 -5
- data/admins/pageflow/accounts.rb +22 -20
- data/admins/pageflow/entry.rb +76 -26
- data/admins/pageflow/entry_templates.rb +10 -9
- data/admins/pageflow/folder.rb +1 -1
- data/admins/pageflow/membership.rb +15 -15
- data/admins/pageflow/revisions.rb +5 -5
- data/admins/pageflow/site_root_entry.rb +64 -0
- data/admins/pageflow/sites.rb +12 -3
- data/admins/pageflow/translations.rb +75 -0
- data/admins/pageflow/user.rb +21 -35
- data/app/assets/images/pageflow/admin/icons/comment.svg +1 -0
- data/app/assets/javascripts/pageflow/admin/entries.js +30 -5
- data/app/assets/javascripts/pageflow/dist/ui.js +4228 -900
- data/app/assets/javascripts/pageflow/editor/vendor.js +0 -1
- data/app/assets/javascripts/pageflow/ui.js +0 -1
- data/app/assets/stylesheets/pageflow/admin/entries/index_table.scss +2 -1
- data/app/assets/stylesheets/pageflow/admin/entry_comments_indicator.scss +45 -0
- data/app/assets/stylesheets/pageflow/admin/permalink_input.scss +8 -0
- data/app/assets/stylesheets/pageflow/admin.scss +1 -0
- data/app/assets/stylesheets/pageflow/animations/spin.scss +9 -0
- data/app/assets/stylesheets/pageflow/animations.scss +1 -0
- data/app/assets/stylesheets/pageflow/editor/background_positioning.scss +27 -5
- data/app/assets/stylesheets/pageflow/editor/base.scss +11 -1
- data/app/assets/stylesheets/pageflow/editor/drop_down_button.scss +20 -2
- data/app/assets/stylesheets/pageflow/editor/edit_configuration_view.scss +5 -0
- data/app/assets/stylesheets/pageflow/editor/file_folders.scss +127 -0
- data/app/assets/stylesheets/pageflow/editor/file_meta_data.scss +5 -2
- data/app/assets/stylesheets/pageflow/editor/file_meta_data_overlay.scss +45 -0
- data/app/assets/stylesheets/pageflow/editor/file_preview.scss +138 -0
- data/app/assets/stylesheets/pageflow/editor/file_references.scss +68 -0
- data/app/assets/stylesheets/pageflow/editor/file_settings_dialog.scss +1 -1
- data/app/assets/stylesheets/pageflow/editor/file_stage_icons.scss +17 -0
- data/app/assets/stylesheets/pageflow/editor/file_stages.scss +25 -32
- data/app/assets/stylesheets/pageflow/editor/file_thumbnails.scss +31 -48
- data/app/assets/stylesheets/pageflow/editor/file_type_pills.scss +73 -0
- data/app/assets/stylesheets/pageflow/editor/files.scss +242 -50
- data/app/assets/stylesheets/pageflow/editor/filtered_files.scss +161 -9
- data/app/assets/stylesheets/pageflow/editor/folder_breadcrumb.scss +40 -0
- data/app/assets/stylesheets/pageflow/editor/info_box.scss +23 -3
- data/app/assets/stylesheets/pageflow/editor/inputs/edit_defaults_button.scss +15 -0
- data/app/assets/stylesheets/pageflow/editor/inputs.scss +1 -0
- data/app/assets/stylesheets/pageflow/editor/list.scss +89 -37
- data/app/assets/stylesheets/pageflow/editor/list_search_field.scss +52 -0
- data/app/assets/stylesheets/pageflow/editor/manage_files.scss +9 -0
- data/app/assets/stylesheets/pageflow/editor/menu.scss +14 -0
- data/app/assets/stylesheets/pageflow/editor/move_to_folder_dialog.scss +83 -0
- data/app/assets/stylesheets/pageflow/editor/outline.scss +0 -13
- data/app/assets/stylesheets/pageflow/editor/sortable.scss +12 -0
- data/app/assets/stylesheets/pageflow/mixins/buttons.scss +4 -4
- data/app/assets/stylesheets/pageflow/mixins/pageflow.scss +9 -5
- data/app/assets/stylesheets/pageflow/ui/color_picker.scss +230 -0
- data/app/assets/stylesheets/pageflow/ui/forms.scss +38 -4
- data/app/assets/stylesheets/pageflow/ui/functions.scss +12 -2
- data/app/assets/stylesheets/pageflow/ui/input/color_input.scss +9 -8
- data/app/assets/stylesheets/pageflow/ui/input/file_name_input.scss +37 -0
- data/app/assets/stylesheets/pageflow/ui/input/text_area_input.scss +15 -0
- data/app/assets/stylesheets/pageflow/ui/overrides.scss +8 -0
- data/app/assets/stylesheets/pageflow/ui/properties.scss +34 -0
- data/app/assets/stylesheets/pageflow/ui/tabs_view.scss +8 -3
- data/app/assets/stylesheets/pageflow/ui.scss +4 -1
- data/app/controllers/concerns/pageflow/controller_delegation.rb +1 -1
- data/app/controllers/concerns/pageflow/edit_locking.rb +17 -10
- data/app/controllers/concerns/pageflow/entry_password_protection.rb +1 -0
- data/app/controllers/concerns/pageflow/public_https_mode.rb +2 -1
- data/app/controllers/concerns/pageflow/quota_verification.rb +5 -4
- data/app/controllers/pageflow/admin/initial_passwords_controller.rb +1 -0
- data/app/controllers/pageflow/application_controller.rb +19 -19
- data/app/controllers/pageflow/chapters_controller.rb +3 -2
- data/app/controllers/pageflow/edit_locks_controller.rb +3 -2
- data/app/controllers/pageflow/editor/encoding_confirmations_controller.rb +1 -0
- data/app/controllers/pageflow/editor/entries_controller.rb +3 -1
- data/app/controllers/pageflow/editor/entry_publications_controller.rb +1 -0
- data/app/controllers/pageflow/editor/file_folders_controller.rb +80 -0
- data/app/controllers/pageflow/editor/file_import_controller.rb +4 -3
- data/app/controllers/pageflow/editor/files_controller.rb +20 -10
- data/app/controllers/pageflow/editor/oembeds_controller.rb +21 -0
- data/app/controllers/pageflow/editor/widgets_controller.rb +1 -0
- data/app/controllers/pageflow/entries_controller.rb +85 -21
- data/app/controllers/pageflow/feeds_controller.rb +1 -1
- data/app/controllers/pageflow/files_controller.rb +1 -0
- data/app/controllers/pageflow/pages_controller.rb +4 -2
- data/app/controllers/pageflow/review/comment_thread_reads_controller.rb +30 -0
- data/app/controllers/pageflow/review/comment_threads_controller.rb +60 -0
- data/app/controllers/pageflow/review/comments_controller.rb +53 -0
- data/app/controllers/pageflow/revisions_controller.rb +5 -1
- data/app/controllers/pageflow/sitemaps_controller.rb +1 -1
- data/app/controllers/pageflow/storylines_controller.rb +1 -0
- data/app/helpers/pageflow/admin/cutoff_modes_helper.rb +12 -0
- data/app/helpers/pageflow/admin/entries_helper.rb +41 -1
- data/app/helpers/pageflow/admin/entry_translations_helper.rb +18 -0
- data/app/helpers/pageflow/admin/features_helper.rb +1 -1
- data/app/helpers/pageflow/admin/form_helper.rb +3 -3
- data/app/helpers/pageflow/admin/locales_helper.rb +10 -2
- data/app/helpers/pageflow/admin/memberships_helper.rb +32 -32
- data/app/helpers/pageflow/admin/revisions_helper.rb +1 -1
- data/app/helpers/pageflow/admin/sites_helper.rb +22 -0
- data/app/helpers/pageflow/admin/users_helper.rb +7 -5
- data/app/helpers/pageflow/admin/widgets_helper.rb +5 -5
- data/app/helpers/pageflow/asset_urls_helper.rb +1 -1
- data/app/helpers/pageflow/audio_files_helper.rb +5 -2
- data/app/helpers/pageflow/background_image_helper.rb +7 -6
- data/app/helpers/pageflow/common_entry_seed_helper.rb +7 -7
- data/app/helpers/pageflow/editor/config_helper.rb +3 -1
- data/app/helpers/pageflow/editor/files_helper.rb +1 -1
- data/app/helpers/pageflow/embed_code_helper.rb +3 -3
- data/app/helpers/pageflow/entries_helper.rb +52 -46
- data/app/helpers/pageflow/entry_json_seed_helper.rb +7 -6
- data/app/helpers/pageflow/feeds_helper.rb +2 -2
- data/app/helpers/pageflow/file_background_images_helper.rb +2 -2
- data/app/helpers/pageflow/file_thumbnails_helper.rb +4 -3
- data/app/helpers/pageflow/files_helper.rb +5 -4
- data/app/helpers/pageflow/folders_helper.rb +8 -5
- data/app/helpers/pageflow/help_entries_helper.rb +2 -2
- data/app/helpers/pageflow/hreflang_links_helper.rb +37 -0
- data/app/helpers/pageflow/info_box_helper.rb +7 -11
- data/app/helpers/pageflow/media_query_helper.rb +3 -3
- data/app/helpers/pageflow/navigation_bar_helper.rb +1 -1
- data/app/helpers/pageflow/overview_helper.rb +1 -1
- data/app/helpers/pageflow/page_types_helper.rb +5 -5
- data/app/helpers/pageflow/pages_helper.rb +29 -15
- data/app/helpers/pageflow/public_i18n_helper.rb +10 -9
- data/app/helpers/pageflow/quota_helper.rb +4 -4
- data/app/helpers/pageflow/render_json_helper.rb +6 -3
- data/app/helpers/pageflow/revision_file_helper.rb +2 -1
- data/app/helpers/pageflow/sites_helper.rb +3 -3
- data/app/helpers/pageflow/social_share_helper.rb +24 -10
- data/app/helpers/pageflow/social_share_links_helper.rb +12 -9
- data/app/helpers/pageflow/structured_data_helper.rb +5 -2
- data/app/helpers/pageflow/stub_page_configuration.rb +7 -3
- data/app/helpers/pageflow/text_direction_helper.rb +1 -1
- data/app/helpers/pageflow/themes_helper.rb +2 -4
- data/app/helpers/pageflow/video_files_helper.rb +29 -13
- data/app/helpers/pageflow/widgets_helper.rb +8 -6
- data/app/inputs/pageflow_permalink_input.rb +8 -3
- data/app/jobs/pageflow/application_job.rb +1 -0
- data/app/jobs/pageflow/entry_export_import/upload_and_publish_file_job.rb +1 -1
- data/app/jobs/pageflow/poll_meta_data_from_zencoder_job.rb +1 -0
- data/app/jobs/pageflow/poll_zencoder_job.rb +3 -2
- data/app/jobs/pageflow/process_image_or_text_track_job.rb +1 -0
- data/app/jobs/pageflow/prune_auto_snapshots_job.rb +1 -0
- data/app/jobs/pageflow/request_meta_data_from_zencoder_job.rb +1 -0
- data/app/jobs/pageflow/submit_file_to_zencoder_job.rb +1 -0
- data/app/mailers/pageflow/user_mailer.rb +1 -0
- data/app/models/concerns/pageflow/auto_generated_perma_id.rb +20 -1
- data/app/models/concerns/pageflow/entry_publication_states.rb +7 -3
- data/app/models/concerns/pageflow/feature_target.rb +8 -4
- data/app/models/concerns/pageflow/output_source.rb +3 -3
- data/app/models/concerns/pageflow/permalinkable.rb +2 -1
- data/app/models/concerns/pageflow/reusable_file.rb +24 -24
- data/app/models/concerns/pageflow/serialization_blacklist.rb +3 -5
- data/app/models/concerns/pageflow/suspendable.rb +5 -3
- data/app/models/concerns/pageflow/theme_referencer.rb +1 -1
- data/app/models/concerns/pageflow/translatable.rb +62 -0
- data/app/models/concerns/pageflow/translated_attributes.rb +101 -0
- data/app/models/concerns/pageflow/uploadable_file.rb +6 -6
- data/app/models/pageflow/account.rb +6 -5
- data/app/models/pageflow/account_member_query.rb +1 -1
- data/app/models/pageflow/account_role_query.rb +1 -1
- data/app/models/pageflow/application_query.rb +1 -1
- data/app/models/pageflow/application_record.rb +1 -1
- data/app/models/pageflow/audio_file.rb +4 -4
- data/app/models/pageflow/audio_file_url_templates.rb +1 -1
- data/app/models/pageflow/authentication_token.rb +2 -2
- data/app/models/pageflow/chapter.rb +6 -1
- data/app/models/pageflow/chapter_scaffold.rb +2 -4
- data/app/models/pageflow/cname_site_request_scope.rb +1 -1
- data/app/models/pageflow/comment.rb +30 -0
- data/app/models/pageflow/comment_thread.rb +65 -0
- data/app/models/pageflow/comment_thread_read.rb +22 -0
- data/app/models/pageflow/customized_theme.rb +9 -8
- data/app/models/pageflow/draft_entry.rb +49 -9
- data/app/models/pageflow/edit_lock.rb +19 -21
- data/app/models/pageflow/encoding_confirmation.rb +2 -2
- data/app/models/pageflow/entries_feed.rb +2 -2
- data/app/models/pageflow/entry.rb +46 -30
- data/app/models/pageflow/entry_at_revision.rb +14 -2
- data/app/models/pageflow/entry_comment_summary.rb +114 -0
- data/app/models/pageflow/entry_duplicate.rb +8 -5
- data/app/models/pageflow/entry_publication.rb +2 -2
- data/app/models/pageflow/entry_role_query.rb +4 -4
- data/app/models/pageflow/entry_template.rb +4 -4
- data/app/models/pageflow/entry_title_or_account_name_query.rb +2 -2
- data/app/models/pageflow/entry_translation_group.rb +42 -0
- data/app/models/pageflow/file_folder.rb +74 -0
- data/app/models/pageflow/file_reuse.rb +5 -4
- data/app/models/pageflow/file_usage.rb +18 -3
- data/app/models/pageflow/folder.rb +2 -2
- data/app/models/pageflow/home_button.rb +7 -7
- data/app/models/pageflow/image_file.rb +44 -25
- data/app/models/pageflow/image_file_url_templates.rb +4 -4
- data/app/models/pageflow/invitation_form.rb +2 -1
- data/app/models/pageflow/legal_info.rb +38 -0
- data/app/models/pageflow/managed_user_query.rb +1 -1
- data/app/models/pageflow/membership.rb +5 -5
- data/app/models/pageflow/nested_revision_component_copy.rb +263 -0
- data/app/models/pageflow/null_user.rb +1 -1
- data/app/models/pageflow/overview_button.rb +1 -1
- data/app/models/pageflow/page.rb +7 -3
- data/app/models/pageflow/permalink.rb +24 -2
- data/app/models/pageflow/permalink_directory.rb +7 -0
- data/app/models/pageflow/permalink_redirect.rb +7 -0
- data/app/models/pageflow/positioned_file.rb +5 -5
- data/app/models/pageflow/potential_entry_translations.rb +55 -0
- data/app/models/pageflow/potential_memberships.rb +5 -4
- data/app/models/pageflow/published_entry.rb +62 -11
- data/app/models/pageflow/revision.rb +29 -16
- data/app/models/pageflow/roles.rb +14 -18
- data/app/models/pageflow/site.rb +46 -3
- data/app/models/pageflow/site_root_entry_form.rb +27 -0
- data/app/models/pageflow/sitemaps.rb +10 -1
- data/app/models/pageflow/storyline.rb +5 -2
- data/app/models/pageflow/storyline_scaffold.rb +1 -1
- data/app/models/pageflow/text_track_file.rb +1 -1
- data/app/models/pageflow/text_track_file_url_templates.rb +1 -1
- data/app/models/pageflow/theme_customization_file.rb +3 -2
- data/app/models/pageflow/thumbnail_file_resolver.rb +1 -1
- data/app/models/pageflow/url_template.rb +1 -1
- data/app/models/pageflow/used_file.rb +13 -3
- data/app/models/pageflow/user_name_query.rb +2 -2
- data/app/models/pageflow/video_file.rb +22 -15
- data/app/models/pageflow/video_file_url_templates.rb +6 -4
- data/app/models/pageflow/widget.rb +5 -4
- data/app/models/pageflow/with_file_usage_extension.rb +1 -1
- data/app/models/pageflow/zencoder_attachment.rb +8 -8
- data/app/policies/pageflow/account_policy.rb +3 -1
- data/app/policies/pageflow/admin/admin_only_tab_policy.rb +1 -0
- data/app/policies/pageflow/admin/entry_tab_policy.rb +1 -0
- data/app/policies/pageflow/application_policy.rb +2 -0
- data/app/policies/pageflow/entry_policy.rb +7 -1
- data/app/policies/pageflow/entry_template_policy.rb +2 -1
- data/app/policies/pageflow/file_policy.rb +4 -7
- data/app/policies/pageflow/folder_policy.rb +18 -8
- data/app/policies/pageflow/membership_policy.rb +6 -4
- data/app/policies/pageflow/site_policy.rb +10 -3
- data/app/policies/pageflow/user_policy.rb +6 -4
- data/app/state_machines/pageflow/image_and_text_track_processing_state_machine.rb +3 -2
- data/app/state_machines/pageflow/media_encoding_state_machine.rb +5 -4
- data/app/views/admin/accounts/_entry_template_details.html.arb +2 -2
- data/app/views/admin/entries/_attributes_table.html.arb +6 -5
- data/app/views/admin/entries/_form.html.erb +2 -1
- data/app/views/admin/entries/_permalink_inputs.html.erb +9 -2
- data/app/views/admin/entry_templates/_form.html.erb +1 -3
- data/app/views/admin/site_root_entry/choose.html.erb +19 -0
- data/app/views/admin/sites/_fields.html.erb +14 -1
- data/app/views/admin/translations/_form.html.erb +31 -0
- data/app/views/admin/users/_attributes_table.html.arb +13 -0
- data/app/views/components/pageflow/admin/add_membership_button.rb +13 -12
- data/app/views/components/pageflow/admin/custom_scopes_renderer.rb +1 -0
- data/app/views/components/pageflow/admin/embed_code_field.rb +1 -0
- data/app/views/components/pageflow/admin/embedded_index_table.rb +9 -10
- data/app/views/components/pageflow/admin/entries_tab.rb +1 -0
- data/app/views/components/pageflow/admin/entry_publication_state_indicator.rb +6 -5
- data/app/views/components/pageflow/admin/entry_templates_tab.rb +2 -1
- data/app/views/components/pageflow/admin/entry_translations_tab.rb +102 -0
- data/app/views/components/pageflow/admin/entry_user_badge_list.rb +1 -0
- data/app/views/components/pageflow/admin/extensible_attributes_table.rb +9 -8
- data/app/views/components/pageflow/admin/features_tab.rb +1 -0
- data/app/views/components/pageflow/admin/grouped_folder_list.rb +1 -0
- data/app/views/components/pageflow/admin/icon_link_to.rb +1 -0
- data/app/views/components/pageflow/admin/members_tab.rb +4 -3
- data/app/views/components/pageflow/admin/membership_role_with_tooltip.rb +3 -2
- data/app/views/components/pageflow/admin/revisions_tab.rb +14 -10
- data/app/views/components/pageflow/admin/sites_tab.rb +1 -0
- data/app/views/components/pageflow/admin/tabs_view.rb +1 -0
- data/app/views/components/pageflow/admin/timestamp.rb +6 -5
- data/app/views/components/pageflow/admin/user_account_badge_list.rb +2 -3
- data/app/views/components/pageflow/admin/user_accounts_tab.rb +1 -0
- data/app/views/components/pageflow/admin/user_entries_tab.rb +1 -0
- data/app/views/components/pageflow/admin/users_tab.rb +1 -0
- data/app/views/pageflow/audio_files/_audio_file.json.jbuilder +0 -1
- data/app/views/pageflow/editor/config/_seeds.json.jbuilder +5 -3
- data/app/views/pageflow/editor/entries/_entry.json.jbuilder +2 -1
- data/app/views/pageflow/editor/entries/index.json.jbuilder +1 -1
- data/app/views/pageflow/editor/entries/seed.json.erb +1 -0
- data/app/views/pageflow/editor/entries/show.json.jbuilder +1 -1
- data/app/views/pageflow/editor/entry_publications/check.json.jbuilder +2 -2
- data/app/views/pageflow/editor/file_folders/_file_folder.json.jbuilder +5 -0
- data/app/views/pageflow/editor/file_folders/create.json.jbuilder +1 -0
- data/app/views/pageflow/editor/file_folders/index.json.jbuilder +3 -0
- data/app/views/pageflow/editor/files/_file.json.jbuilder +7 -14
- data/app/views/pageflow/editor/files/create.json.jbuilder +1 -1
- data/app/views/pageflow/editor/files/index.json.jbuilder +1 -1
- data/app/views/pageflow/editor/image_files/_image_file.json.jbuilder +3 -0
- data/app/views/pageflow/editor/sites/_site.json.jbuilder +1 -0
- data/app/views/pageflow/editor/video_files/_video_file.json.jbuilder +4 -3
- data/app/views/pageflow/entries/share_menu/_bluesky_link.html.erb +8 -0
- data/app/views/pageflow/entries/share_menu/_threads_link.html.erb +8 -0
- data/app/views/pageflow/files/_file.json.jbuilder +5 -3
- data/app/views/pageflow/image_files/_image_file.json.jbuilder +0 -1
- data/app/views/pageflow/review/comment_threads/_comment_thread.json.jbuilder +20 -0
- data/app/views/pageflow/review/comment_threads/create.json.jbuilder +2 -0
- data/app/views/pageflow/review/comment_threads/index.json.jbuilder +13 -0
- data/app/views/pageflow/review/comments/_comment.json.jbuilder +13 -0
- data/app/views/pageflow/review/comments/create.json.jbuilder +1 -0
- data/app/views/pageflow/sitemaps/index.xml.builder +9 -1
- data/app/views/pageflow/social_share/_entry_meta_tags.html.erb +1 -1
- data/app/views/pageflow/social_share/_page_meta_tags.html.erb +1 -1
- data/app/views/pageflow/structured_data/_entry.json.jbuilder +2 -3
- data/app/views/pageflow/video_files/_video_file.json.jbuilder +0 -1
- data/config/initializers/active_admin_patches.rb +3 -6
- data/config/initializers/admin_resource_tabs.rb +3 -0
- data/config/initializers/paperclip.rb +1 -0
- data/config/initializers/symmetric_encryption.rb +1 -1
- data/config/initializers/zencoder.rb +24 -13
- data/config/locales/de.yml +256 -12
- data/config/locales/en.yml +253 -15
- data/config/routes.rb +29 -13
- data/config/spring.rb +2 -1
- data/db/migrate/20140418225525_setup_schema.rb +2 -2
- data/db/migrate/20190306161431_copy_file_attributes_of_failed_uploads.rb +2 -2
- data/db/migrate/20190820152900_drop_accounts_themes.rb +2 -1
- data/db/migrate/20191202145757_create_pageflow_scrolled_sections.rb +11 -11
- data/db/migrate/20191202150657_create_pageflow_scrolled_chapters.rb +1 -1
- data/db/migrate/20191202154723_create_pageflow_scrolled_content_elements.rb +9 -9
- data/db/migrate/20191219143450_add_position_to_content_elements.rb +2 -1
- data/db/migrate/20200117133200_change_revision_appearance_option_default_and_null.rb +2 -1
- data/db/migrate/20200122115400_create_pageflow_entry_templates.rb +25 -25
- data/db/migrate/20200206134400_convert_legacy_scrolled_content_element_types.rb +3 -3
- data/db/migrate/20221215120856_associate_entry_templates_with_sites.rb +2 -2
- data/db/migrate/20230120092923_create_other_files.rb +2 -1
- data/db/migrate/20230419083307_create_pageflow_entry_translation_group.rb +9 -0
- data/db/migrate/20240612110434_add_cutoff_mode_name_to_sites.rb +5 -0
- data/db/migrate/20240918084059_create_pageflow_permalink_redirects.rb +14 -0
- data/db/migrate/20250508172234_ensure_scrolled_entries_have_main_storyline.rb +14 -0
- data/db/migrate/20250617090048_add_custom404_entry_to_sites.rb +5 -0
- data/db/migrate/20250617100000_add_perma_id_counter_to_entries.rb +28 -0
- data/db/migrate/20250722174123_add_perma_id_to_chapters.rb +10 -0
- data/db/migrate/20250725080603_add_perma_id_indexes_to_revision_components.rb +13 -0
- data/db/migrate/20250726000000_add_display_name_to_file_usages.rb +5 -0
- data/db/migrate/20251015000000_add_structured_data_type_name_to_revisions.rb +5 -0
- data/db/migrate/20251029142849_convert_legacy_social_embeds_to_unified_social_embed.rb +38 -0
- data/db/migrate/20251119083347_fix_main_storyline_positions.rb +16 -0
- data/db/migrate/20251119083348_ensure_scrolled_entries_have_excursion_storyline.rb +15 -0
- data/db/migrate/20260303000000_add_layout_version_to_revisions.rb +6 -0
- data/db/migrate/20260323000000_create_comment_threads_and_comments.rb +30 -0
- data/db/migrate/20260414000000_add_subject_range_to_comment_threads.rb +5 -0
- data/db/migrate/20260415000000_add_section_perma_id_to_comment_threads.rb +5 -0
- data/db/migrate/20260727000000_add_quote_to_comments.rb +5 -0
- data/db/migrate/20260728000000_create_file_folders.rb +17 -0
- data/db/migrate/20260805000000_add_attribute_translations_to_sites.rb +5 -0
- data/db/migrate/20260806000000_add_edited_at_to_comments.rb +5 -0
- data/db/migrate/20260810000000_create_pageflow_scrolled_lottie_files.rb +24 -0
- data/db/migrate/20260817000000_create_comment_thread_reads.rb +16 -0
- data/db/migrate/20260819000000_add_unread_comments_since_at_to_users.rb +18 -0
- data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/editor.js +12599 -5398
- data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/frontend.js +1275 -4560
- data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/react-client.js +20204 -22
- data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/react-server.js +18657 -19
- data/entry_types/paged/app/controllers/pageflow_paged/entries_controller.rb +1 -0
- data/entry_types/paged/app/helpers/pageflow_paged/page_background_asset_helper.rb +1 -1
- data/entry_types/paged/app/helpers/pageflow_paged/third_party_embed_consent_helper.rb +7 -7
- data/entry_types/paged/app/views/pageflow_paged/editor/entries/_seed.json.jbuilder +1 -0
- data/entry_types/paged/app/views/pageflow_paged/entries/show.html.erb +1 -0
- data/entry_types/paged/lib/pageflow_paged/plugin.rb +4 -0
- data/entry_types/paged/lib/pageflow_paged/react/page_type.rb +1 -1
- data/entry_types/paged/lib/pageflow_paged/react/widget_type.rb +3 -3
- data/entry_types/paged/lib/pageflow_paged.rb +1 -1
- data/entry_types/scrolled/app/assets/stylesheets/pageflow_scrolled/ui.scss +2 -0
- data/entry_types/scrolled/app/controllers/pageflow_scrolled/editor/chapters_controller.rb +5 -3
- data/entry_types/scrolled/app/controllers/pageflow_scrolled/editor/content_elements_controller.rb +35 -5
- data/entry_types/scrolled/app/controllers/pageflow_scrolled/editor/sections_controller.rb +4 -5
- data/entry_types/scrolled/app/controllers/pageflow_scrolled/entries_controller.rb +23 -2
- data/entry_types/scrolled/app/helpers/pageflow_scrolled/cache_helper.rb +3 -3
- data/entry_types/scrolled/app/helpers/pageflow_scrolled/editor/entry_json_seed_helper.rb +8 -5
- data/entry_types/scrolled/app/helpers/pageflow_scrolled/editor/seed_html_helper.rb +7 -3
- data/entry_types/scrolled/app/helpers/pageflow_scrolled/entry_json_seed_helper.rb +72 -10
- data/entry_types/scrolled/app/helpers/pageflow_scrolled/i18n_helper.rb +28 -13
- data/entry_types/scrolled/app/helpers/pageflow_scrolled/packs_helper.rb +41 -12
- data/entry_types/scrolled/app/helpers/pageflow_scrolled/react_server_side_rendering_helper.rb +23 -25
- data/entry_types/scrolled/app/helpers/pageflow_scrolled/sprockets_helper.rb +16 -0
- data/entry_types/scrolled/app/helpers/pageflow_scrolled/themes_helper.rb +189 -3
- data/entry_types/scrolled/app/models/pageflow_scrolled/chapter.rb +15 -14
- data/entry_types/scrolled/app/models/pageflow_scrolled/content_element.rb +61 -7
- data/entry_types/scrolled/app/models/pageflow_scrolled/lottie_file.rb +6 -0
- data/entry_types/scrolled/app/models/pageflow_scrolled/lottie_file_url_templates.rb +16 -0
- data/entry_types/scrolled/app/models/pageflow_scrolled/section.rb +12 -1
- data/entry_types/scrolled/app/models/pageflow_scrolled/storyline.rb +20 -1
- data/entry_types/scrolled/app/views/pageflow_scrolled/editor/entries/_head.html.erb +1 -0
- data/entry_types/scrolled/app/views/pageflow_scrolled/editor/sections/_section_with_content_elements.json.jbuilder +2 -2
- data/entry_types/scrolled/app/views/pageflow_scrolled/entries/show.html.erb +15 -12
- data/entry_types/scrolled/app/views/pageflow_scrolled/entry_json_seed/_entry.json.jbuilder +45 -17
- data/entry_types/scrolled/app/views/pageflow_scrolled/entry_json_seed/_entry_translations.json.jbuilder +14 -0
- data/entry_types/scrolled/app/views/pageflow_scrolled/entry_json_seed/_theme.json.jbuilder +34 -5
- data/entry_types/scrolled/app/views/pageflow_scrolled/favicons/_entry.html.erb +1 -1
- data/entry_types/scrolled/app/views/pageflow_scrolled/storylines/_storyline.json.jbuilder +7 -0
- data/entry_types/scrolled/config/configuration_schemas/pageflow-scrolled.json +414 -0
- data/entry_types/scrolled/config/locales/de.yml +1094 -78
- data/entry_types/scrolled/config/locales/en.yml +1083 -78
- data/entry_types/scrolled/config/routes.rb +18 -8
- data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/install_generator.rb +11 -11
- data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/templates/theme/logoDarkVariantDesktop.svg +56 -0
- data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/templates/theme/logoDarkVariantMobile.svg +22 -0
- data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/templates/themes_plugin.rb.tt +26 -11
- data/entry_types/scrolled/lib/pageflow_scrolled/additional_packs.rb +27 -8
- data/entry_types/scrolled/lib/pageflow_scrolled/additional_seed_data.rb +2 -2
- data/entry_types/scrolled/lib/pageflow_scrolled/additional_theme_assets.rb +27 -0
- data/entry_types/scrolled/lib/pageflow_scrolled/configuration.rb +67 -10
- data/entry_types/scrolled/lib/pageflow_scrolled/configuration_schemas.rb +91 -0
- data/entry_types/scrolled/lib/pageflow_scrolled/content_element_consent_vendors.rb +1 -1
- data/entry_types/scrolled/lib/pageflow_scrolled/engine.rb +2 -1
- data/entry_types/scrolled/lib/pageflow_scrolled/entry_file_reference_locations.rb +71 -0
- data/entry_types/scrolled/lib/pageflow_scrolled/entry_structured_data_types/faq_page.rb +58 -0
- data/entry_types/scrolled/lib/pageflow_scrolled/file_reference_locations.rb +69 -0
- data/entry_types/scrolled/lib/pageflow_scrolled/plugin.rb +222 -19
- data/entry_types/scrolled/lib/pageflow_scrolled/react_widget_type.rb +2 -4
- data/entry_types/scrolled/lib/pageflow_scrolled/seeds.rb +76 -54
- data/entry_types/scrolled/lib/pageflow_scrolled/theme_options_default_scale.rb +35 -0
- data/entry_types/scrolled/lib/pageflow_scrolled.rb +14 -1
- data/entry_types/scrolled/lib/tasks/pageflow_scrolled/storybook.rake +24 -5
- data/entry_types/scrolled/package/config/configurationSchemas.js +70 -0
- data/entry_types/scrolled/package/config/rollup/configurationSchemas.js +19 -0
- data/entry_types/scrolled/package/config/webpack.js +94 -0
- data/entry_types/scrolled/package/contentElements/hotspots-frontend.css +1 -0
- data/entry_types/scrolled/package/contentElements/hotspots-frontend.js +1795 -0
- data/entry_types/scrolled/package/contentElements/inlineBeforeAfter-frontend.css +1 -0
- data/entry_types/scrolled/package/contentElements/inlineBeforeAfter-frontend.js +219 -0
- data/entry_types/scrolled/package/contentElements/lottieAnimation-frontend.css +1 -0
- data/entry_types/scrolled/package/contentElements/lottieAnimation-frontend.js +244 -0
- data/entry_types/scrolled/package/contentElements/socialEmbed-frontend.css +1 -0
- data/entry_types/scrolled/package/contentElements/socialEmbed-frontend.js +823 -0
- data/entry_types/scrolled/package/contentElements/tikTokEmbed-frontend.css +1 -0
- data/entry_types/scrolled/package/contentElements/tikTokEmbed-frontend.js +109 -0
- data/entry_types/scrolled/package/contentElements/twitterEmbed-frontend.css +1 -0
- data/entry_types/scrolled/package/contentElements/twitterEmbed-frontend.js +277 -0
- data/entry_types/scrolled/package/contentElements/videoEmbed-frontend.css +1 -0
- data/entry_types/scrolled/package/contentElements/videoEmbed-frontend.js +244 -0
- data/entry_types/scrolled/package/contentElements-editor.js +3155 -583
- data/entry_types/scrolled/package/contentElements-frontend.css +1 -1
- data/entry_types/scrolled/package/contentElements-frontend.js +3375 -1585
- data/entry_types/scrolled/package/editor.css +1 -0
- data/entry_types/scrolled/package/editor.js +8452 -2867
- data/entry_types/scrolled/package/entryState.js +1600 -0
- data/entry_types/scrolled/package/frontend/FloatingPortalRootProvider-20c600de.js +1979 -0
- data/entry_types/scrolled/package/frontend/FloatingPortalRootProvider-58189220.js +2538 -0
- data/entry_types/scrolled/package/frontend/{PhonePlatformContext-4ec6b2de.js → PhonePlatformContext-035a99fa.js} +9 -15
- data/entry_types/scrolled/package/frontend/PhonePlatformContext-9da43797.js +33 -0
- data/entry_types/scrolled/package/frontend/Placeholder.module-bf0966b4.js +5267 -0
- data/entry_types/scrolled/package/frontend/Placeholder.module-d22a9335.js +4180 -0
- data/entry_types/scrolled/package/frontend/ThemeIcon-ab834849.js +754 -0
- data/entry_types/scrolled/package/frontend/ThemeIcon-f6cb3a8f.js +773 -0
- data/entry_types/scrolled/package/frontend/ToggleFullscreenCornerButton-30fd1124.js +39 -0
- data/entry_types/scrolled/package/frontend/ToggleFullscreenCornerButton-61c25224.js +72 -0
- data/entry_types/scrolled/package/frontend/Viewer-1074fd59.js +147 -0
- data/entry_types/scrolled/package/frontend/Viewer-1482ca34.js +480 -0
- data/entry_types/scrolled/package/frontend/Viewer-70504231.js +210 -0
- data/entry_types/scrolled/package/frontend/{Viewer-1bb5597c.js → Viewer-cc8d4072.js} +100 -135
- data/entry_types/scrolled/package/frontend/Wavesurfer-656e3c36.js +302 -0
- data/entry_types/scrolled/package/frontend/Wavesurfer-b753b838.js +385 -0
- data/entry_types/scrolled/package/frontend/commenting.css +1 -0
- data/entry_types/scrolled/package/frontend/extensions-167ae143.js +1455 -0
- data/entry_types/scrolled/package/frontend/extensions-2318f92b.js +5918 -0
- data/entry_types/scrolled/package/frontend/extensions-a461fd13.js +4890 -0
- data/entry_types/scrolled/package/frontend/extensions-c98269fd.js +1982 -0
- data/entry_types/scrolled/package/frontend/i18n-493cd2a6.js +93 -0
- data/entry_types/scrolled/package/frontend/i18n-e06cac14.js +100 -0
- data/entry_types/scrolled/package/frontend/{index-11f32f10.js → index-2e5546f7.js} +39 -54
- data/entry_types/scrolled/package/frontend/index-de2b418d.js +130 -0
- data/entry_types/scrolled/package/frontend/index.css +1 -1
- data/entry_types/scrolled/package/frontend/index.js +1976 -1367
- data/entry_types/scrolled/package/frontend/inlineEditing.css +1 -0
- data/entry_types/scrolled/package/frontend/useContentElementEditorState-a084912e.js +25 -0
- data/entry_types/scrolled/package/frontend/useDelayedBoolean-a387d85b.js +24 -0
- data/entry_types/scrolled/package/frontend/usePhonePlatform-4ecb96d4.js +8 -0
- data/entry_types/scrolled/package/frontend/usePhonePlatform-ce9ff08d.js +8 -0
- data/entry_types/scrolled/package/frontend-server.js +20 -210
- data/entry_types/scrolled/package/package.json +22 -12
- data/entry_types/scrolled/package/review.css +1 -0
- data/entry_types/scrolled/package/review.js +3306 -0
- data/entry_types/scrolled/package/testHelpers.js +952 -239
- data/entry_types/scrolled/package/values/widgets.module.css +18 -0
- data/entry_types/scrolled/package/widgets/consentBar.css +1 -1
- data/entry_types/scrolled/package/widgets/consentBar.js +275 -315
- data/entry_types/scrolled/package/widgets/defaultNavigation.css +2 -2
- data/entry_types/scrolled/package/widgets/defaultNavigation.js +961 -432
- data/entry_types/scrolled/package/widgets/excursionSheet.css +1 -0
- data/entry_types/scrolled/package/widgets/excursionSheet.js +225 -0
- data/entry_types/scrolled/package/widgets/iconInlineFileRights.css +1 -1
- data/entry_types/scrolled/package/widgets/iconInlineFileRights.js +62 -32
- data/entry_types/scrolled/package/widgets/iconScrollIndicator.css +1 -0
- data/entry_types/scrolled/package/widgets/iconScrollIndicator.js +67 -0
- data/entry_types/scrolled/package/widgets/mainStorylineSheet.css +1 -0
- data/entry_types/scrolled/package/widgets/mainStorylineSheet.js +100 -0
- data/entry_types/scrolled/package/widgets/textInlineFileRights.css +1 -1
- data/entry_types/scrolled/package/widgets/textInlineFileRights.js +48 -26
- data/entry_types/scrolled/package/widgets-server.js +2 -0
- data/entry_types/scrolled/spec/factories/chapters.rb +14 -1
- data/entry_types/scrolled/spec/factories/content_elements.rb +1 -1
- data/entry_types/scrolled/spec/factories/lottie_files.rb +29 -0
- data/entry_types/scrolled/spec/fixtures/animation.lottie +0 -0
- data/entry_types/scrolled/spec/fixtures/font.woff +0 -0
- data/entry_types/scrolled/spec/fixtures/font.woff2 +0 -0
- data/lib/generators/pageflow/active_admin_initializer/active_admin_initializer_generator.rb +5 -3
- data/lib/generators/pageflow/assets/assets_generator.rb +7 -5
- data/lib/generators/pageflow/cancan/cancan_generator.rb +2 -1
- data/lib/generators/pageflow/cancan/templates/ability.rb +1 -1
- data/lib/generators/pageflow/error_pages/error_pages_generator.rb +2 -1
- data/lib/generators/pageflow/initializer/initializer_generator.rb +3 -2
- data/lib/generators/pageflow/install/install_generator.rb +2 -2
- data/lib/generators/pageflow/procfile/procfile_generator.rb +2 -1
- data/lib/generators/pageflow/resque/resque_generator.rb +4 -4
- data/lib/generators/pageflow/resque/templates/resque.rake +1 -1
- data/lib/generators/pageflow/routes/routes_generator.rb +4 -2
- data/lib/generators/pageflow/seeds/seeds_generator.rb +3 -2
- data/lib/generators/pageflow/seeds/templates/seeds.rb +6 -6
- data/lib/generators/pageflow/theme/theme_generator.rb +2 -1
- data/lib/generators/pageflow/user/user_generator.rb +2 -1
- data/lib/pageflow/ability_mixin.rb +25 -15
- data/lib/pageflow/active_admin_patches/views/attributes_table.rb +1 -0
- data/lib/pageflow/active_admin_patches/views/pages/base.rb +3 -2
- data/lib/pageflow/active_admin_patches/views/table_for.rb +1 -0
- data/lib/pageflow/additional_headers.rb +27 -0
- data/lib/pageflow/admin/attributes_table_rows.rb +3 -3
- data/lib/pageflow/admin/tabs.rb +1 -1
- data/lib/pageflow/built_in_file_type.rb +1 -1
- data/lib/pageflow/built_in_page_types_plugin.rb +1 -1
- data/lib/pageflow/built_in_widget_type.rb +2 -2
- data/lib/pageflow/built_in_widget_types_plugin.rb +2 -1
- data/lib/pageflow/configuration.rb +183 -18
- data/lib/pageflow/cutoff_modes.rb +39 -0
- data/lib/pageflow/deprecation.rb +19 -0
- data/lib/pageflow/editor_controller.rb +6 -10
- data/lib/pageflow/engine.rb +5 -6
- data/lib/pageflow/entries_controller_env_helper.rb +32 -2
- data/lib/pageflow/entry_export_import/attachment_files.rb +1 -1
- data/lib/pageflow/entry_export_import/entry_serialization.rb +9 -8
- data/lib/pageflow/entry_export_import/file_mappings.rb +1 -0
- data/lib/pageflow/entry_export_import/page_type_versions.rb +2 -2
- data/lib/pageflow/entry_export_import/revision_serialization/import.rb +11 -1
- data/lib/pageflow/entry_export_import/revision_serialization.rb +3 -0
- data/lib/pageflow/entry_export_import.rb +3 -3
- data/lib/pageflow/entry_structured_data_types.rb +43 -0
- data/lib/pageflow/entry_type_configuration.rb +1 -0
- data/lib/pageflow/entry_types.rb +2 -2
- data/lib/pageflow/feature.rb +1 -1
- data/lib/pageflow/features.rb +4 -6
- data/lib/pageflow/file_importers.rb +4 -4
- data/lib/pageflow/file_type.rb +5 -5
- data/lib/pageflow/file_types.rb +4 -4
- data/lib/pageflow/global_config_api.rb +5 -6
- data/lib/pageflow/help_entries.rb +7 -7
- data/lib/pageflow/help_entry.rb +1 -1
- data/lib/pageflow/hooks.rb +1 -1
- data/lib/pageflow/nested_revision_component.rb +9 -27
- data/lib/pageflow/news_item_api.rb +1 -1
- data/lib/pageflow/oembed_providers.rb +42 -0
- data/lib/pageflow/page_type.rb +2 -3
- data/lib/pageflow/page_types.rb +3 -3
- data/lib/pageflow/paperclip_interpolations/support.rb +1 -1
- data/lib/pageflow/paperclip_processors/vtt.rb +1 -0
- data/lib/pageflow/paperclip_processors/webp.rb +2 -2
- data/lib/pageflow/partial_editor_fragment_renderer.rb +2 -2
- data/lib/pageflow/plugin.rb +1 -2
- data/lib/pageflow/primary_domain_entry_redirect.rb +6 -0
- data/lib/pageflow/quota.rb +9 -5
- data/lib/pageflow/quotas.rb +1 -1
- data/lib/pageflow/rails_version.rb +14 -2
- data/lib/pageflow/react.rb +1 -1
- data/lib/pageflow/revision_component.rb +8 -40
- data/lib/pageflow/revision_components.rb +16 -6
- data/lib/pageflow/seeds.rb +12 -16
- data/lib/pageflow/theme.rb +1 -1
- data/lib/pageflow/theme_customizations.rb +10 -10
- data/lib/pageflow/themes.rb +44 -3
- data/lib/pageflow/user_mixin.rb +18 -6
- data/lib/pageflow/version.rb +1 -1
- data/lib/pageflow/widget_type.rb +4 -4
- data/lib/pageflow/widget_types.rb +9 -9
- data/lib/pageflow/zencoder_api.rb +32 -42
- data/lib/pageflow/zencoder_audio_output_definition.rb +14 -13
- data/lib/pageflow/zencoder_meta_data_output_definition.rb +3 -2
- data/lib/pageflow/zencoder_output_definition.rb +16 -14
- data/lib/pageflow/zencoder_video_output_definition.rb +140 -88
- data/lib/pageflow.rb +8 -2
- data/lib/tasks/pageflow_tasks.rake +1 -1
- data/package/config/eslint-rules/documented-in-toc.js +125 -0
- data/package/config/jest/index.js +0 -1
- data/package/config/webpack.js +0 -1
- data/package/config/webpack5.js +0 -1
- data/package/editor.js +4880 -2313
- data/package/frontend.js +710 -1223
- data/package/package.json +3 -1
- data/package/review.js +384 -0
- data/package/testHelpers.js +257 -243
- data/package/ui.js +1487 -813
- data/package/vendor/stubs/wysihtml5.js +2 -0
- data/spec/factories/accounts.rb +37 -22
- data/spec/factories/audio_files.rb +2 -2
- data/spec/factories/authentication_tokens.rb +4 -4
- data/spec/factories/chapters.rb +4 -4
- data/spec/factories/comment_thread_reads.rb +10 -0
- data/spec/factories/comment_threads.rb +10 -0
- data/spec/factories/comments.rb +9 -0
- data/spec/factories/draft_entries.rb +14 -6
- data/spec/factories/edit_locks.rb +1 -1
- data/spec/factories/entries.rb +28 -19
- data/spec/factories/entry_translation_groups.rb +6 -0
- data/spec/factories/file_folders.rb +8 -0
- data/spec/factories/file_usages.rb +2 -1
- data/spec/factories/folders.rb +1 -1
- data/spec/factories/image_files.rb +2 -2
- data/spec/factories/pages.rb +3 -3
- data/spec/factories/published_entries.rb +28 -8
- data/spec/factories/revisions.rb +1 -1
- data/spec/factories/sites.rb +6 -0
- data/spec/factories/test_multi_attachment_files.rb +1 -1
- data/spec/factories/text_track_files.rb +1 -1
- data/spec/factories/uploadable_files.rb +1 -1
- data/spec/factories/users.rb +6 -6
- data/spec/factories/video_files.rb +2 -2
- data/spec/factories/widgets.rb +1 -1
- data/spec/fixtures/7x15_rotated.jpg +0 -0
- data/vendor/assets/javascripts/wysihtml-toolbar.js +19288 -0
- metadata +266 -92
- data/app/assets/stylesheets/pageflow/editor/select_button.scss +0 -51
- data/config/initializers/revision_components.rb +0 -5
- data/config/locales/twitter_to_x.de.yml +0 -6
- data/config/locales/twitter_to_x.en.yml +0 -6
- data/entry_types/scrolled/app/helpers/pageflow_scrolled/generated_media_queries_helper.rb +0 -55
- data/entry_types/scrolled/config/locales/twitter_to_x.de.yml +0 -12
- data/entry_types/scrolled/config/locales/twitter_to_x.en.yml +0 -12
- data/entry_types/scrolled/config/locales/vr_image_projection.de.yml +0 -24
- data/entry_types/scrolled/config/locales/vr_image_projection.en.yml +0 -24
- data/entry_types/scrolled/package/frontend/EditableInlineText.module-ebd22921.js +0 -5497
- data/entry_types/scrolled/package/frontend/ToggleFullscreenCornerButton-b79159cc.js +0 -107
- data/entry_types/scrolled/package/frontend/Viewer-1ecf3375.js +0 -154
- data/entry_types/scrolled/package/frontend/Wavesurfer-7d9cf1b7.js +0 -333
- data/entry_types/scrolled/package/frontend/arrowRight-62998af9.js +0 -77
- data/entry_types/scrolled/package/frontend/components-024a9893.js +0 -2853
- data/entry_types/scrolled/package/frontend/createSuper-d0f30da3.js +0 -115
- data/entry_types/scrolled/package/frontend/i18n-ce13a8bf.js +0 -1129
- data/entry_types/scrolled/package/frontend/useContentElementEditorState-4f4c3cf6.js +0 -52
- data/lib/generators/pageflow/resque/templates/resque_enqueue_after_commit_patch.rb +0 -25
- data/package/vendor/jquery.minicolors.js +0 -1108
|
@@ -1,56 +1,351 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { ConfigurationEditorTabView } from 'pageflow/ui';
|
|
2
|
+
import { FileInputView } from 'pageflow/editor';
|
|
3
|
+
import { render, act } from '@testing-library/react';
|
|
4
|
+
import { renderBackboneView, ConfigurationEditor } from 'pageflow/testHelpers';
|
|
5
|
+
export { renderBackboneView as renderReactBasedBackboneView } from 'pageflow/testHelpers';
|
|
6
|
+
import { EditContentElementView, editor } from 'pageflow-scrolled/editor';
|
|
7
|
+
import React, { useEffect, useState } from 'react';
|
|
8
|
+
import { DndProvider } from 'react-dnd';
|
|
9
|
+
import { HTML5Backend } from 'react-dnd-html5-backend';
|
|
10
|
+
import BackboneEvents from 'backbone-events-standalone';
|
|
11
|
+
import { PhonePlatformContext, RootProviders, useEntryStateDispatch, ContentElementLifecycleContext, ContentElementEditorCommandEmitterContext, ContentElementEditorStateContext, MainStorylineActivity, ContentElementAttributesProvider, ContentElementViewTimelineContext } from 'pageflow-scrolled/frontend';
|
|
4
12
|
import { Consent } from 'pageflow/frontend';
|
|
5
|
-
import {
|
|
13
|
+
import { renderHook } from '@testing-library/react-hooks/dom';
|
|
6
14
|
|
|
7
|
-
function
|
|
8
|
-
if (
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
+
function styleInject(css, ref) {
|
|
16
|
+
if ( ref === void 0 ) ref = {};
|
|
17
|
+
var insertAt = ref.insertAt;
|
|
18
|
+
|
|
19
|
+
if (!css || typeof document === 'undefined') { return; }
|
|
20
|
+
|
|
21
|
+
var head = document.head || document.getElementsByTagName('head')[0];
|
|
22
|
+
var style = document.createElement('style');
|
|
23
|
+
style.type = 'text/css';
|
|
24
|
+
|
|
25
|
+
if (insertAt === 'top') {
|
|
26
|
+
if (head.firstChild) {
|
|
27
|
+
head.insertBefore(style, head.firstChild);
|
|
28
|
+
} else {
|
|
29
|
+
head.appendChild(style);
|
|
30
|
+
}
|
|
15
31
|
} else {
|
|
16
|
-
|
|
32
|
+
head.appendChild(style);
|
|
17
33
|
}
|
|
18
34
|
|
|
19
|
-
|
|
35
|
+
if (style.styleSheet) {
|
|
36
|
+
style.styleSheet.cssText = css;
|
|
37
|
+
} else {
|
|
38
|
+
style.appendChild(document.createTextNode(css));
|
|
39
|
+
}
|
|
20
40
|
}
|
|
21
41
|
|
|
22
|
-
|
|
23
|
-
|
|
42
|
+
var css = ".ContentElementBox-module_properties__1ljc9 {\n --content-element-box-box-shadow:\n var(--content-element-box-shadow, 0 0 #000),\n 0 0 0 1px var(--content-element-box-outline-color, transparent);\n}\n\n.ContentElementBox-module_wrapper__3wZgP {\n overflow: hidden;\n border-radius: var(--content-element-box-border-radius,\n var(--theme-content-element-box-border-radius));\n box-shadow: var(--content-element-box-box-shadow);\n}\n\n.ContentElementBox-module_full__AfWPr {\n border-radius: var(--content-element-box-border-radius,\n var(--theme-content-element-full-box-border-radius,\n var(--theme-content-element-box-border-radius)));\n}\n\n.ContentElementBox-module_positioned__3R1dq {\n position: relative;\n height: 100%;\n}\n";
|
|
43
|
+
var styles = {"properties":"ContentElementBox-module_properties__1ljc9","wrapper":"ContentElementBox-module_wrapper__3wZgP","full":"ContentElementBox-module_full__AfWPr","positioned":"ContentElementBox-module_positioned__3R1dq"};
|
|
44
|
+
styleInject(css);
|
|
24
45
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
});
|
|
30
|
-
keys.push.apply(keys, symbols);
|
|
31
|
-
}
|
|
46
|
+
function getElement(subject) {
|
|
47
|
+
var _subject$el;
|
|
48
|
+
return (_subject$el = subject === null || subject === void 0 ? void 0 : subject.el) !== null && _subject$el !== void 0 ? _subject$el : subject;
|
|
49
|
+
}
|
|
32
50
|
|
|
33
|
-
|
|
51
|
+
/**
|
|
52
|
+
* Assert that the subject contains a `ContentElementBox` and, optionally,
|
|
53
|
+
* that the box has specific theme styles applied. Registered via
|
|
54
|
+
* {@link useContentElementMatchers}.
|
|
55
|
+
*
|
|
56
|
+
* The subject is a DOM element, e.g. the `container` returned by
|
|
57
|
+
* {@link renderInContentElement}. Negate with `.not` to assert that no
|
|
58
|
+
* box is present.
|
|
59
|
+
*
|
|
60
|
+
* @param {Object} [options]
|
|
61
|
+
* @param {string} [options.boxShadow] - Expected box shadow theme scale, e.g. `'md'`.
|
|
62
|
+
* @param {string} [options.borderRadius] - Expected border radius theme scale, e.g. `'circle'`.
|
|
63
|
+
* @param {string} [options.outlineColor] - Expected outline color.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* expect(container).toContainContentElementBox();
|
|
67
|
+
* expect(container).toContainContentElementBox({borderRadius: 'circle', boxShadow: 'md'});
|
|
68
|
+
* expect(container).not.toContainContentElementBox();
|
|
69
|
+
*/
|
|
70
|
+
function toContainContentElementBox(subject, options = {}) {
|
|
71
|
+
const wrapper = getElement(subject).querySelector(`.${styles.wrapper}`);
|
|
72
|
+
if (!wrapper) {
|
|
73
|
+
return {
|
|
74
|
+
pass: false,
|
|
75
|
+
message: () => 'expected element to contain a content element box, but found none'
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
const mismatches = boxPropertyMismatches(wrapper, options);
|
|
79
|
+
return {
|
|
80
|
+
pass: mismatches.length === 0,
|
|
81
|
+
message: () => mismatches.length ? `expected content element box to have ${mismatches.join(', ')}` : `expected element not to contain a content element box${describeOptions(options)}`
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
const boxProperties = {
|
|
85
|
+
boxShadow: {
|
|
86
|
+
customProperty: '--content-element-box-shadow',
|
|
87
|
+
expectedValue: value => `var(--theme-content-element-box-shadow-${value})`
|
|
88
|
+
},
|
|
89
|
+
borderRadius: {
|
|
90
|
+
customProperty: '--content-element-box-border-radius',
|
|
91
|
+
expectedValue: value => `var(--theme-content-element-box-border-radius-${value})`
|
|
92
|
+
},
|
|
93
|
+
outlineColor: {
|
|
94
|
+
customProperty: '--content-element-box-outline-color',
|
|
95
|
+
expectedValue: value => value
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
function boxPropertyMismatches(wrapper, options) {
|
|
99
|
+
return Object.keys(options).reduce((mismatches, name) => {
|
|
100
|
+
const property = boxProperties[name];
|
|
101
|
+
if (property) {
|
|
102
|
+
const expected = property.expectedValue(options[name]);
|
|
103
|
+
const actual = wrapper.style.getPropertyValue(property.customProperty);
|
|
104
|
+
if (actual !== expected) {
|
|
105
|
+
mismatches.push(`${name} ${JSON.stringify(options[name])} (found ${JSON.stringify(actual)})`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return mismatches;
|
|
109
|
+
}, []);
|
|
110
|
+
}
|
|
111
|
+
function describeOptions(options) {
|
|
112
|
+
const names = Object.keys(options).filter(name => boxProperties[name]);
|
|
113
|
+
return names.length ? ` with ${names.join(', ')}` : '';
|
|
34
114
|
}
|
|
35
115
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
116
|
+
var css$1 = ".FitViewport-module_container__-awVj {\n width: 100%;\n margin: 0 auto;\n max-width: var(\n --theme-fit-viewport,\n calc(100 * var(--vh) / var(--fit-viewport-aspect-ratio) * var(--fit-viewport-scale, 1))\n );\n}\n\n.FitViewport-module_content__1_K5a {\n position: relative;\n}\n\n.FitViewport-module_content__1_K5a > div:first-child {\n padding-top: calc(100% * var(--fit-viewport-aspect-ratio));\n}\n\n.FitViewport-module_inner__3psd1 {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n}\n\n@media print {\n .FitViewport-module_container__-awVj {\n page-break-inside: avoid;\n }\n}\n";
|
|
117
|
+
var styles$1 = {"container":"FitViewport-module_container__-awVj","content":"FitViewport-module_content__1_K5a","inner":"FitViewport-module_inner__3psd1"};
|
|
118
|
+
styleInject(css$1);
|
|
39
119
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
120
|
+
/**
|
|
121
|
+
* Assert that the subject contains a `FitViewport` and, optionally, that
|
|
122
|
+
* it has a specific aspect ratio. Registered via
|
|
123
|
+
* {@link useContentElementMatchers}.
|
|
124
|
+
*
|
|
125
|
+
* The subject is a DOM element, e.g. the `container` returned by
|
|
126
|
+
* {@link renderInContentElement}. Negate with `.not` to assert that no
|
|
127
|
+
* `FitViewport` is present.
|
|
128
|
+
*
|
|
129
|
+
* @param {Object} [options]
|
|
130
|
+
* @param {string} [options.aspectRatio] -
|
|
131
|
+
* Expected aspect ratio: a theme scale name (e.g. `'square'`) or a raw
|
|
132
|
+
* ratio value (e.g. `'0.75'`).
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* expect(container).toContainFitViewport();
|
|
136
|
+
* expect(container).toContainFitViewport({aspectRatio: 'square'});
|
|
137
|
+
*/
|
|
138
|
+
function toContainFitViewport(subject, {
|
|
139
|
+
aspectRatio
|
|
140
|
+
} = {}) {
|
|
141
|
+
const container = getElement(subject).querySelector(`.${styles$1.container}`);
|
|
142
|
+
if (!container) {
|
|
143
|
+
return {
|
|
144
|
+
pass: false,
|
|
145
|
+
message: () => 'expected element to contain a FitViewport, but found none'
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
if (aspectRatio !== undefined) {
|
|
149
|
+
const actual = getAspectRatio(container);
|
|
150
|
+
if (actual !== aspectRatio) {
|
|
151
|
+
return {
|
|
152
|
+
pass: false,
|
|
153
|
+
message: () => `expected FitViewport to have aspect ratio ${JSON.stringify(aspectRatio)} ` + `(found ${JSON.stringify(actual)})`
|
|
154
|
+
};
|
|
50
155
|
}
|
|
51
156
|
}
|
|
157
|
+
return {
|
|
158
|
+
pass: true,
|
|
159
|
+
message: () => 'expected element not to contain a FitViewport'
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
function getAspectRatio(container) {
|
|
163
|
+
const cssValue = container.style.getPropertyValue('--fit-viewport-aspect-ratio');
|
|
164
|
+
const match = cssValue.match(/var\(--theme-aspect-ratio-(.+)\)/);
|
|
165
|
+
return match ? match[1] : cssValue;
|
|
166
|
+
}
|
|
52
167
|
|
|
53
|
-
|
|
168
|
+
/**
|
|
169
|
+
* Assert that all inputs rendered by a configuration editor are
|
|
170
|
+
* described by a configuration schema. Registered via
|
|
171
|
+
* {@link useConfigurationEditorMatchers}.
|
|
172
|
+
*
|
|
173
|
+
* The subject is a function that renders the configuration editor. Only
|
|
174
|
+
* inputs of the rendered form are seen. Views on nested routes render a
|
|
175
|
+
* form of their own and are checked against the part of the schema that
|
|
176
|
+
* describes the object they configure.
|
|
177
|
+
*
|
|
178
|
+
* @param {Object} schema - Configuration schema of the subject.
|
|
179
|
+
* @param {Object} [options]
|
|
180
|
+
* @param {Array<string>} [options.path] - Path of the configuration the
|
|
181
|
+
* rendered form writes, if it is not the root. `*` stands for array
|
|
182
|
+
* items and map values.
|
|
183
|
+
*
|
|
184
|
+
* @example
|
|
185
|
+
* expect(() => renderContentElementConfigurationEditor({entry, contentElement}))
|
|
186
|
+
* .toRenderInputsMatching(require('./schema.json'));
|
|
187
|
+
*
|
|
188
|
+
* @example
|
|
189
|
+
* expect(() => renderBackboneView(new SidebarEditAreaView(options)))
|
|
190
|
+
* .toRenderInputsMatching(require('../schema.json'), {path: ['areas', '*']});
|
|
191
|
+
*/
|
|
192
|
+
function toRenderInputsMatching(render, schema, {
|
|
193
|
+
path = []
|
|
194
|
+
} = {}) {
|
|
195
|
+
const subschema = subschemaAt(schema, path);
|
|
196
|
+
if (!subschema) {
|
|
197
|
+
return {
|
|
198
|
+
pass: false,
|
|
199
|
+
message: () => `expected schema to describe configuration at ${path.join('/')}`
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
const inputs = recordInputs(render);
|
|
203
|
+
if (!inputs.length) {
|
|
204
|
+
return {
|
|
205
|
+
pass: false,
|
|
206
|
+
message: () => 'expected configuration editor to render inputs, but it rendered none'
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
const mismatches = inputs.flatMap(input => mismatchesOf(input, subschema));
|
|
210
|
+
return {
|
|
211
|
+
pass: mismatches.length === 0,
|
|
212
|
+
message: () => mismatches.length ? `expected rendered inputs to match schema:\n ${mismatches.join('\n ')}` : 'expected rendered inputs not to match schema'
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
function subschemaAt(schema, path) {
|
|
216
|
+
return path.reduce((current, segment) => dereference(child(current, segment), schema), dereference(schema, schema));
|
|
217
|
+
}
|
|
218
|
+
function child(schema, segment) {
|
|
219
|
+
var _schema$properties;
|
|
220
|
+
if (!schema) {
|
|
221
|
+
return undefined;
|
|
222
|
+
}
|
|
223
|
+
return segment === '*' ? schema.items || schema.additionalProperties : (_schema$properties = schema.properties) === null || _schema$properties === void 0 ? void 0 : _schema$properties[segment];
|
|
224
|
+
}
|
|
225
|
+
function dereference(schema, document) {
|
|
226
|
+
var _schema2;
|
|
227
|
+
const seen = [];
|
|
228
|
+
while (((_schema = schema) === null || _schema === void 0 ? void 0 : _schema.$ref) && !seen.includes(schema.$ref)) {
|
|
229
|
+
var _schema;
|
|
230
|
+
seen.push(schema.$ref);
|
|
231
|
+
schema = localTarget(document, schema.$ref);
|
|
232
|
+
}
|
|
233
|
+
return ((_schema2 = schema) === null || _schema2 === void 0 ? void 0 : _schema2.$ref) ? undefined : schema;
|
|
234
|
+
}
|
|
235
|
+
function localTarget(document, ref) {
|
|
236
|
+
const [otherDocumentId, pointer] = ref.split('#');
|
|
237
|
+
if (otherDocumentId) {
|
|
238
|
+
return undefined;
|
|
239
|
+
}
|
|
240
|
+
return pointer.split('/').filter(Boolean).reduce((value, segment) => value === null || value === void 0 ? void 0 : value[segment], document);
|
|
241
|
+
}
|
|
242
|
+
function recordInputs(render) {
|
|
243
|
+
const inputs = [];
|
|
244
|
+
const input = ConfigurationEditorTabView.prototype.input;
|
|
245
|
+
jest.spyOn(ConfigurationEditorTabView.prototype, 'input').mockImplementation(function (propertyName, view, options = {}) {
|
|
246
|
+
inputs.push({
|
|
247
|
+
propertyName,
|
|
248
|
+
view,
|
|
249
|
+
options
|
|
250
|
+
});
|
|
251
|
+
return input.call(this, propertyName, view, options);
|
|
252
|
+
});
|
|
253
|
+
try {
|
|
254
|
+
render();
|
|
255
|
+
} finally {
|
|
256
|
+
ConfigurationEditorTabView.prototype.input.mockRestore();
|
|
257
|
+
}
|
|
258
|
+
return inputs;
|
|
259
|
+
}
|
|
260
|
+
const checks = [fileCollectionMismatch];
|
|
261
|
+
function mismatchesOf({
|
|
262
|
+
propertyName,
|
|
263
|
+
view,
|
|
264
|
+
options
|
|
265
|
+
}, schema) {
|
|
266
|
+
const property = (schema.properties || {})[propertyName];
|
|
267
|
+
return checks.flatMap(check => check({
|
|
268
|
+
propertyName,
|
|
269
|
+
view,
|
|
270
|
+
options,
|
|
271
|
+
property
|
|
272
|
+
}) || []);
|
|
273
|
+
}
|
|
274
|
+
function fileCollectionMismatch({
|
|
275
|
+
propertyName,
|
|
276
|
+
view,
|
|
277
|
+
options,
|
|
278
|
+
property
|
|
279
|
+
}) {
|
|
280
|
+
if (!isFileInput(view) || !options.collection) {
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
const declared = property && property['x-fileCollection'];
|
|
284
|
+
if (declared !== options.collection) {
|
|
285
|
+
return `${propertyName}: expected x-fileCollection ${JSON.stringify(options.collection)}, ` + `found ${JSON.stringify(declared)}`;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
function isFileInput(view) {
|
|
289
|
+
return view === FileInputView || view.prototype instanceof FileInputView;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Register the public content element matchers for the surrounding
|
|
294
|
+
* `describe` block: {@link toContainContentElementBox} and
|
|
295
|
+
* {@link toContainFitViewport}.
|
|
296
|
+
*
|
|
297
|
+
* Call inside a `describe` block. Content element plugins can use this to
|
|
298
|
+
* assert that their component opts into the framework chrome correctly.
|
|
299
|
+
*
|
|
300
|
+
* @example
|
|
301
|
+
* import {renderInContentElement, useContentElementMatchers} from 'pageflow-scrolled/testHelpers';
|
|
302
|
+
*
|
|
303
|
+
* describe('MyContentElement', () => {
|
|
304
|
+
* useContentElementMatchers();
|
|
305
|
+
*
|
|
306
|
+
* it('renders inside a box', () => {
|
|
307
|
+
* const {container} = renderInContentElement(<MyContentElement />);
|
|
308
|
+
* expect(container).toContainContentElementBox();
|
|
309
|
+
* });
|
|
310
|
+
* });
|
|
311
|
+
*/
|
|
312
|
+
function useContentElementMatchers() {
|
|
313
|
+
beforeEach(() => {
|
|
314
|
+
expect.extend({
|
|
315
|
+
toContainContentElementBox,
|
|
316
|
+
toContainFitViewport
|
|
317
|
+
});
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Register the configuration editor matchers for the surrounding
|
|
323
|
+
* `describe` block: {@link toRenderInputsMatching}.
|
|
324
|
+
*
|
|
325
|
+
* Call inside a `describe` block. Content element plugins can use this to
|
|
326
|
+
* assert that their configuration schema keeps up with their editor
|
|
327
|
+
* integration.
|
|
328
|
+
*
|
|
329
|
+
* @example
|
|
330
|
+
* import {
|
|
331
|
+
* renderContentElementConfigurationEditor, useConfigurationEditorMatchers
|
|
332
|
+
* } from 'pageflow-scrolled/testHelpers';
|
|
333
|
+
*
|
|
334
|
+
* describe('myContentElement/editor', () => {
|
|
335
|
+
* useConfigurationEditorMatchers();
|
|
336
|
+
*
|
|
337
|
+
* it('renders inputs described by schema', () => {
|
|
338
|
+
* expect(() => renderContentElementConfigurationEditor({entry, contentElement}))
|
|
339
|
+
* .toRenderInputsMatching(schema);
|
|
340
|
+
* });
|
|
341
|
+
* });
|
|
342
|
+
*/
|
|
343
|
+
function useConfigurationEditorMatchers() {
|
|
344
|
+
beforeEach(() => {
|
|
345
|
+
expect.extend({
|
|
346
|
+
toRenderInputsMatching
|
|
347
|
+
});
|
|
348
|
+
});
|
|
54
349
|
}
|
|
55
350
|
|
|
56
351
|
/**
|
|
@@ -65,81 +360,110 @@ function _objectSpread2(target) {
|
|
|
65
360
|
* @param {Object} [options.legalInfo] - imprint, copyright and privacy information of entry.
|
|
66
361
|
* @param {Object} [options.themeOptions] - Options set via theme registration.
|
|
67
362
|
* @param {Object} [options.themeAssets] - Paths to theme assets.
|
|
363
|
+
* @param {Object} [options.themeTranslations] - Pre-merged theme translations (e.g., scales).
|
|
68
364
|
* @param {Object} [options.additionalSeedData] - Seed data by name.
|
|
69
365
|
* @param {Array} [options.consentVendors] - Server rendered consent vendor data.
|
|
70
366
|
* @param {Object} [options.contentElementConsentVendors] - Consent vendor name by content element id.
|
|
71
367
|
* @param {Object} [options.entry] - attributes of entry.
|
|
368
|
+
* @param {Object} [options.fileModelTypes] - Mapping of file collection names to model types.
|
|
369
|
+
* Only needed to associate nested files with their parent. Collections of file types
|
|
370
|
+
* registered by plugins get a placeholder model type.
|
|
371
|
+
* @param {Object} [options.fileUrlTemplates] - Mapping of file collection names to mappings of
|
|
372
|
+
* url template names to url templates.
|
|
72
373
|
* @param {Array} [options.imageFiles] - Array of objects with image file attributes of entry.
|
|
73
374
|
* @param {Array} [options.videoFiles] - Array of objects with video file attributes of entry.
|
|
74
375
|
* @param {Array} [options.audioFiles] - Array of objects with audio file attributes of entry.
|
|
75
376
|
* @param {Array} [options.textTrackFiles] - Array of objects with text track file attributes of entry.
|
|
377
|
+
* @param {Array} [options.storylines] - Array of objects with storyline attributes of entry.
|
|
76
378
|
* @param {Array} [options.chapters] - Array of objects with chapter attributes of entry.
|
|
77
379
|
* @param {Array} [options.sections] - Array of objects with section attributes of entry.
|
|
78
380
|
* @param {Array} [options.contentElements] - Array of objects with content element attributes of entry.
|
|
79
381
|
* @param {Array} [options.widgets] - Array of objects with widget attributes of entry.
|
|
80
382
|
* @returns {Object} - Data that resembles seed generated by server side rendering.
|
|
81
383
|
*/
|
|
82
|
-
function normalizeSeed(
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
384
|
+
function normalizeSeed({
|
|
385
|
+
imageFileUrlTemplates,
|
|
386
|
+
fileUrlTemplates,
|
|
387
|
+
fileModelTypes,
|
|
388
|
+
prettyUrl,
|
|
389
|
+
shareUrlTemplates,
|
|
390
|
+
defaultFileRights,
|
|
391
|
+
legalInfo,
|
|
392
|
+
themeOptions,
|
|
393
|
+
themeAssets,
|
|
394
|
+
themeTranslations,
|
|
395
|
+
entry,
|
|
396
|
+
imageFiles,
|
|
397
|
+
videoFiles,
|
|
398
|
+
audioFiles,
|
|
399
|
+
textTrackFiles,
|
|
400
|
+
storylines,
|
|
401
|
+
chapters,
|
|
402
|
+
sections,
|
|
403
|
+
contentElements,
|
|
404
|
+
widgets,
|
|
405
|
+
additionalSeedData,
|
|
406
|
+
consentVendors,
|
|
407
|
+
contentElementConsentVendors,
|
|
408
|
+
cutOff,
|
|
409
|
+
embed,
|
|
410
|
+
originUrl,
|
|
411
|
+
fileLicenses,
|
|
412
|
+
entryTranslations,
|
|
413
|
+
fileReferenceLocations,
|
|
414
|
+
...customFiles
|
|
415
|
+
} = {}) {
|
|
416
|
+
const customFileCollectionNames = [...new Set([...Object.keys(customFiles).filter(name => name.endsWith('Files')), ...Object.keys(fileModelTypes || {})])].filter(name => !builtInFileCollectionNames.includes(name));
|
|
417
|
+
const entries = entry ? [entry] : [{}];
|
|
418
|
+
const normalizedEntries = normalizeCollection(entries, {
|
|
419
|
+
locale: 'en',
|
|
420
|
+
configuration: {}
|
|
421
|
+
});
|
|
422
|
+
const normalizedContentElements = normalizeCollection(contentElements, {
|
|
110
423
|
typeName: 'textBlock',
|
|
111
424
|
configuration: {}
|
|
112
425
|
});
|
|
113
|
-
|
|
114
|
-
|
|
426
|
+
const normalizedSections = normalizeSections(sections, normalizedContentElements);
|
|
427
|
+
const normalizedChapters = normalizeChapters(chapters, normalizedSections);
|
|
428
|
+
const normalizedStorylines = normalizeStorylines(storylines, normalizedChapters);
|
|
115
429
|
return {
|
|
116
430
|
config: {
|
|
117
|
-
fileUrlTemplates:
|
|
118
|
-
imageFiles:
|
|
431
|
+
fileUrlTemplates: {
|
|
432
|
+
imageFiles: {
|
|
433
|
+
...imageFileUrlTemplates
|
|
434
|
+
},
|
|
119
435
|
videoFiles: {},
|
|
120
436
|
audioFiles: {},
|
|
121
|
-
textTrackFiles: {}
|
|
122
|
-
|
|
123
|
-
|
|
437
|
+
textTrackFiles: {},
|
|
438
|
+
...emptyUrlTemplates(customFileCollectionNames),
|
|
439
|
+
...fileUrlTemplates
|
|
440
|
+
},
|
|
441
|
+
fileModelTypes: {
|
|
124
442
|
audioFiles: 'Pageflow::AudioFile',
|
|
125
443
|
imageFiles: 'Pageflow::ImageFile',
|
|
126
444
|
textTrackFiles: 'Pageflow::TextTrackFile',
|
|
127
|
-
videoFiles: 'Pageflow::VideoFile'
|
|
128
|
-
|
|
445
|
+
videoFiles: 'Pageflow::VideoFile',
|
|
446
|
+
...placeholderModelTypes(customFileCollectionNames),
|
|
447
|
+
...fileModelTypes
|
|
448
|
+
},
|
|
129
449
|
prettyUrl: prettyUrl,
|
|
130
450
|
shareUrlTemplates: normalizeShareUrlTemplates(shareUrlTemplates),
|
|
131
451
|
defaultFileRights: defaultFileRights,
|
|
132
452
|
legalInfo: normalizeLegalInfo(legalInfo),
|
|
133
453
|
theme: normalizeTheme({
|
|
134
|
-
themeOptions
|
|
135
|
-
themeAssets
|
|
454
|
+
themeOptions,
|
|
455
|
+
themeAssets,
|
|
456
|
+
themeTranslations
|
|
136
457
|
}),
|
|
137
|
-
additionalSeedData: additionalSeedData || {
|
|
138
|
-
frontendVersion: 1
|
|
139
|
-
},
|
|
458
|
+
additionalSeedData: additionalSeedData || {},
|
|
140
459
|
consentVendors: consentVendors || [],
|
|
141
460
|
contentElementConsentVendors: contentElementConsentVendors || {},
|
|
142
|
-
|
|
461
|
+
cutOff,
|
|
462
|
+
embed,
|
|
463
|
+
originUrl,
|
|
464
|
+
fileLicenses: fileLicenses || {},
|
|
465
|
+
entryTranslations: entryTranslations || [],
|
|
466
|
+
fileReferenceLocations: normalizeFileReferenceLocations(fileReferenceLocations)
|
|
143
467
|
},
|
|
144
468
|
collections: {
|
|
145
469
|
entries: normalizedEntries,
|
|
@@ -166,6 +490,8 @@ function normalizeSeed() {
|
|
|
166
490
|
parentFileType: null,
|
|
167
491
|
configuration: {}
|
|
168
492
|
}),
|
|
493
|
+
...customFileCollections(customFileCollectionNames, customFiles),
|
|
494
|
+
storylines: normalizedStorylines,
|
|
169
495
|
chapters: normalizedChapters,
|
|
170
496
|
sections: normalizedSections,
|
|
171
497
|
contentElements: normalizedContentElements,
|
|
@@ -173,11 +499,25 @@ function normalizeSeed() {
|
|
|
173
499
|
}
|
|
174
500
|
};
|
|
175
501
|
}
|
|
502
|
+
const builtInFileCollectionNames = ['imageFiles', 'videoFiles', 'audioFiles', 'textTrackFiles'];
|
|
176
503
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
504
|
+
// Model types are only compared to associate nested files with their
|
|
505
|
+
// parent. Specs that seed nested files need to pass the real model type
|
|
506
|
+
// via the fileModelTypes option.
|
|
507
|
+
function placeholderModelTypes(collectionNames) {
|
|
508
|
+
return Object.fromEntries(collectionNames.map(name => [name, name.replace(/Files$/, 'File').replace(/^./, letter => letter.toUpperCase())]));
|
|
509
|
+
}
|
|
510
|
+
function emptyUrlTemplates(collectionNames) {
|
|
511
|
+
return Object.fromEntries(collectionNames.map(name => [name, {}]));
|
|
512
|
+
}
|
|
513
|
+
function customFileCollections(collectionNames, customFiles) {
|
|
514
|
+
return Object.fromEntries(collectionNames.map(name => [name, normalizeCollection(customFiles[name], {
|
|
515
|
+
isReady: true,
|
|
516
|
+
configuration: {}
|
|
517
|
+
})]));
|
|
518
|
+
}
|
|
519
|
+
function normalizeSections(sections = [], contentElements) {
|
|
520
|
+
const sectionDefaults = {
|
|
181
521
|
configuration: {
|
|
182
522
|
transition: 'scroll',
|
|
183
523
|
backdrop: {
|
|
@@ -185,62 +525,66 @@ function normalizeSections() {
|
|
|
185
525
|
}
|
|
186
526
|
}
|
|
187
527
|
};
|
|
188
|
-
|
|
189
528
|
if (contentElements.length && !sections.length) {
|
|
190
|
-
contentElements.forEach(
|
|
191
|
-
|
|
192
|
-
});
|
|
193
|
-
return [_objectSpread2({
|
|
529
|
+
contentElements.forEach(contentElement => contentElement.sectionId = 10);
|
|
530
|
+
return [{
|
|
194
531
|
id: 10,
|
|
195
|
-
permaId: 1
|
|
196
|
-
|
|
532
|
+
permaId: 1,
|
|
533
|
+
...sectionDefaults
|
|
534
|
+
}];
|
|
197
535
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
});
|
|
536
|
+
return normalizeCollection(sections, sectionDefaults).map(section => ({
|
|
537
|
+
...section,
|
|
538
|
+
configuration: {
|
|
539
|
+
transition: sectionDefaults.configuration.transition,
|
|
540
|
+
...section.configuration
|
|
541
|
+
}
|
|
542
|
+
}));
|
|
206
543
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
var chapters = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
|
|
210
|
-
var sections = arguments.length > 1 ? arguments[1] : undefined;
|
|
211
|
-
var chapterDefaults = {
|
|
544
|
+
function normalizeChapters(chapters = [], sections) {
|
|
545
|
+
const chapterDefaults = {
|
|
212
546
|
configuration: {}
|
|
213
547
|
};
|
|
214
|
-
|
|
215
548
|
if (sections.length && !chapters.length) {
|
|
216
|
-
sections.forEach(
|
|
217
|
-
|
|
218
|
-
});
|
|
219
|
-
return [_objectSpread2({
|
|
549
|
+
sections.forEach(section => section.chapterId = 100);
|
|
550
|
+
return [{
|
|
220
551
|
id: 100,
|
|
221
|
-
permaId: 10
|
|
222
|
-
|
|
552
|
+
permaId: 10,
|
|
553
|
+
...chapterDefaults
|
|
554
|
+
}];
|
|
223
555
|
}
|
|
224
|
-
|
|
225
556
|
return normalizeCollection(chapters, chapterDefaults);
|
|
226
557
|
}
|
|
227
|
-
|
|
558
|
+
function normalizeStorylines(storylines = [], chapters) {
|
|
559
|
+
if (!storylines.length) {
|
|
560
|
+
chapters.forEach(chapter => chapter.storylineId = 1000);
|
|
561
|
+
return [{
|
|
562
|
+
id: 1000,
|
|
563
|
+
permaId: 100,
|
|
564
|
+
configuration: {
|
|
565
|
+
main: true
|
|
566
|
+
}
|
|
567
|
+
}];
|
|
568
|
+
}
|
|
569
|
+
return normalizeCollection(storylines, {
|
|
570
|
+
configuration: {}
|
|
571
|
+
});
|
|
572
|
+
}
|
|
228
573
|
function normalizeShareUrlTemplates(shareUrlTemplates) {
|
|
229
574
|
if (shareUrlTemplates) {
|
|
230
575
|
return shareUrlTemplates;
|
|
231
576
|
} else {
|
|
232
577
|
return {
|
|
233
|
-
email: 'mailto:?body
|
|
234
|
-
facebook: 'http://www.facebook.com/sharer/sharer.php?u
|
|
235
|
-
google: 'https://plus.google.com/share?url
|
|
236
|
-
linked_in: 'https://www.linkedin.com/shareArticle?mini=true&url
|
|
237
|
-
telegram: 'tg://msg?text
|
|
238
|
-
twitter: 'https://x.com/intent/post?url
|
|
239
|
-
whats_app: 'WhatsApp://send?text
|
|
578
|
+
email: 'mailto:?body=%<url>s',
|
|
579
|
+
facebook: 'http://www.facebook.com/sharer/sharer.php?u=%<url>s',
|
|
580
|
+
google: 'https://plus.google.com/share?url=%<url>s',
|
|
581
|
+
linked_in: 'https://www.linkedin.com/shareArticle?mini=true&url=%<url>s',
|
|
582
|
+
telegram: 'tg://msg?text=%<url>s',
|
|
583
|
+
twitter: 'https://x.com/intent/post?url=%<url>s',
|
|
584
|
+
whats_app: 'WhatsApp://send?text=%<url>s'
|
|
240
585
|
};
|
|
241
586
|
}
|
|
242
587
|
}
|
|
243
|
-
|
|
244
588
|
function normalizeLegalInfo(legalInfo) {
|
|
245
589
|
if (legalInfo) {
|
|
246
590
|
return legalInfo;
|
|
@@ -261,75 +605,76 @@ function normalizeLegalInfo(legalInfo) {
|
|
|
261
605
|
};
|
|
262
606
|
}
|
|
263
607
|
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
608
|
+
function normalizeTheme({
|
|
609
|
+
themeAssets,
|
|
610
|
+
themeOptions,
|
|
611
|
+
themeTranslations
|
|
612
|
+
}) {
|
|
268
613
|
return {
|
|
269
|
-
assets:
|
|
270
|
-
icons: {}
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
614
|
+
assets: {
|
|
615
|
+
icons: {},
|
|
616
|
+
...themeAssets
|
|
617
|
+
},
|
|
618
|
+
options: {
|
|
619
|
+
colors: {},
|
|
620
|
+
...themeOptions
|
|
621
|
+
},
|
|
622
|
+
translations: themeTranslations
|
|
275
623
|
};
|
|
276
624
|
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
configuration: {}
|
|
284
|
-
}, widget);
|
|
285
|
-
});
|
|
625
|
+
function normalizeWidgets(widgets = []) {
|
|
626
|
+
return widgets.map(widget => ({
|
|
627
|
+
permaId: widget.role,
|
|
628
|
+
configuration: {},
|
|
629
|
+
...widget
|
|
630
|
+
}));
|
|
286
631
|
}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
permaId: index + 1
|
|
295
|
-
}, defaults), item);
|
|
296
|
-
});
|
|
632
|
+
function normalizeCollection(collection = [], defaults = {}) {
|
|
633
|
+
return collection.map((item, index) => ({
|
|
634
|
+
id: index + 1,
|
|
635
|
+
permaId: index + 1,
|
|
636
|
+
...defaults,
|
|
637
|
+
...item
|
|
638
|
+
}));
|
|
297
639
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
for (i = 0; i < sourceKeys.length; i++) {
|
|
306
|
-
key = sourceKeys[i];
|
|
307
|
-
if (excluded.indexOf(key) >= 0) continue;
|
|
308
|
-
target[key] = source[key];
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
return target;
|
|
640
|
+
function normalizeFileReferenceLocations(fileReferenceLocations) {
|
|
641
|
+
return {
|
|
642
|
+
contentElements: {},
|
|
643
|
+
sections: [],
|
|
644
|
+
entry: [],
|
|
645
|
+
...fileReferenceLocations
|
|
646
|
+
};
|
|
312
647
|
}
|
|
313
648
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
649
|
+
/**
|
|
650
|
+
* Render the configuration editor of a content element. Content element
|
|
651
|
+
* packs can use this to assert how their editor integration behaves.
|
|
652
|
+
*
|
|
653
|
+
* @param {Object} options
|
|
654
|
+
* @param {Object} options.entry - Entry the content element belongs to.
|
|
655
|
+
* @param {Object} options.contentElement - Content element to configure.
|
|
656
|
+
*
|
|
657
|
+
* @example
|
|
658
|
+
* import {renderContentElementConfigurationEditor} from 'pageflow-scrolled/testHelpers';
|
|
659
|
+
*/
|
|
660
|
+
function renderContentElementConfigurationEditor({
|
|
661
|
+
entry,
|
|
662
|
+
contentElement
|
|
663
|
+
}) {
|
|
664
|
+
// Normally contributed by the text inline file rights widget type
|
|
665
|
+
// once the widgets of the entry have been set up.
|
|
666
|
+
ConfigurationEditorTabView.groups.define('ContentElementInlineFileRightsSettings', () => {});
|
|
667
|
+
const view = new EditContentElementView({
|
|
668
|
+
model: contentElement,
|
|
669
|
+
editor,
|
|
670
|
+
entry
|
|
671
|
+
});
|
|
672
|
+
renderBackboneView(view);
|
|
673
|
+
return ConfigurationEditor.find(view);
|
|
331
674
|
}
|
|
332
675
|
|
|
676
|
+
var _jsxFileName = "/home/tfischbach/code/pageflow/entry_types/scrolled/package/src/testHelpers/rendering.js";
|
|
677
|
+
|
|
333
678
|
/**
|
|
334
679
|
* Render a component that depends on entry state. Accepts all options
|
|
335
680
|
* supported by [`render` of
|
|
@@ -366,20 +711,18 @@ function _objectWithoutProperties(source, excluded) {
|
|
|
366
711
|
* function. The normalized seed constructed from the `seed` option
|
|
367
712
|
* is passed as a second parameter.
|
|
368
713
|
*/
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
}, options);
|
|
382
|
-
|
|
714
|
+
function renderInEntry(ui, {
|
|
715
|
+
seed,
|
|
716
|
+
setup,
|
|
717
|
+
wrapper,
|
|
718
|
+
consent = Consent.create(),
|
|
719
|
+
phonePlatform,
|
|
720
|
+
...options
|
|
721
|
+
} = {}) {
|
|
722
|
+
options = {
|
|
723
|
+
wrapper: createWrapper(seed, setup, wrapper, consent, phonePlatform),
|
|
724
|
+
...options
|
|
725
|
+
};
|
|
383
726
|
if (typeof ui === 'function') {
|
|
384
727
|
// Evaluate `ui` inside a React component to allow using hooks in
|
|
385
728
|
// the test. We also could have used `ui` as a React component
|
|
@@ -394,25 +737,39 @@ function renderInEntry(ui) {
|
|
|
394
737
|
// render call and mount a new one. We therefore define a single
|
|
395
738
|
// component that is reused across rerenders to ensure
|
|
396
739
|
// `MyComponent` stays mounted and just receives new props.
|
|
397
|
-
|
|
398
|
-
|
|
740
|
+
function HooksWrapper({
|
|
741
|
+
ui
|
|
742
|
+
}) {
|
|
399
743
|
return ui();
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
744
|
+
}
|
|
745
|
+
const result = render( /*#__PURE__*/React.createElement(HooksWrapper, {
|
|
746
|
+
ui: ui,
|
|
747
|
+
__self: this,
|
|
748
|
+
__source: {
|
|
749
|
+
fileName: _jsxFileName,
|
|
750
|
+
lineNumber: 71,
|
|
751
|
+
columnNumber: 27
|
|
752
|
+
}
|
|
404
753
|
}), options);
|
|
405
|
-
return
|
|
406
|
-
|
|
754
|
+
return {
|
|
755
|
+
...result,
|
|
756
|
+
rerender(ui) {
|
|
407
757
|
result.rerender( /*#__PURE__*/React.createElement(HooksWrapper, {
|
|
408
|
-
ui: ui
|
|
758
|
+
ui: ui,
|
|
759
|
+
__self: this,
|
|
760
|
+
__source: {
|
|
761
|
+
fileName: _jsxFileName,
|
|
762
|
+
lineNumber: 76,
|
|
763
|
+
columnNumber: 25
|
|
764
|
+
}
|
|
409
765
|
}));
|
|
410
766
|
}
|
|
411
|
-
}
|
|
767
|
+
};
|
|
412
768
|
} else {
|
|
413
769
|
return render(ui, options);
|
|
414
770
|
}
|
|
415
771
|
}
|
|
772
|
+
|
|
416
773
|
/**
|
|
417
774
|
* Render a hook that depends on entry state. Accepts all options
|
|
418
775
|
* supported by [`renderHook` of
|
|
@@ -426,45 +783,75 @@ function renderInEntry(ui) {
|
|
|
426
783
|
* @param {Object} [options.seed] - Seed data for entry state. Passed through {@link normalizeSeed}.
|
|
427
784
|
* @param {Function} [options.setup] - See {@link renderInEntry}.
|
|
428
785
|
*/
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
}
|
|
786
|
+
function renderHookInEntry(callback, {
|
|
787
|
+
seed,
|
|
788
|
+
setup,
|
|
789
|
+
wrapper,
|
|
790
|
+
phonePlatform,
|
|
791
|
+
...options
|
|
792
|
+
} = {}) {
|
|
793
|
+
return renderHook(callback, {
|
|
794
|
+
wrapper: createWrapper(seed, setup, wrapper, undefined, phonePlatform),
|
|
795
|
+
...options
|
|
796
|
+
});
|
|
440
797
|
}
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
var children = _ref4.children;
|
|
798
|
+
function createWrapper(seed, setup, originalWrapper, consent, phonePlatform) {
|
|
799
|
+
const normalizedSeed = normalizeSeed(seed);
|
|
800
|
+
const OriginalWrapper = originalWrapper || function Noop({
|
|
801
|
+
children
|
|
802
|
+
}) {
|
|
447
803
|
return children;
|
|
448
804
|
};
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
805
|
+
return function Wrapper({
|
|
806
|
+
children
|
|
807
|
+
}) {
|
|
808
|
+
let content = /*#__PURE__*/React.createElement(Dispatcher, {
|
|
809
|
+
callback: setup,
|
|
810
|
+
seed: normalizedSeed,
|
|
811
|
+
__self: this,
|
|
812
|
+
__source: {
|
|
813
|
+
fileName: _jsxFileName,
|
|
814
|
+
lineNumber: 112,
|
|
815
|
+
columnNumber: 7
|
|
816
|
+
}
|
|
817
|
+
}, /*#__PURE__*/React.createElement(OriginalWrapper, {
|
|
818
|
+
__self: this,
|
|
819
|
+
__source: {
|
|
820
|
+
fileName: _jsxFileName,
|
|
821
|
+
lineNumber: 113,
|
|
822
|
+
columnNumber: 9
|
|
823
|
+
}
|
|
824
|
+
}, children));
|
|
825
|
+
if (phonePlatform !== undefined) {
|
|
826
|
+
content = /*#__PURE__*/React.createElement(PhonePlatformContext.Provider, {
|
|
827
|
+
value: phonePlatform,
|
|
828
|
+
__self: this,
|
|
829
|
+
__source: {
|
|
830
|
+
fileName: _jsxFileName,
|
|
831
|
+
lineNumber: 121,
|
|
832
|
+
columnNumber: 9
|
|
833
|
+
}
|
|
834
|
+
}, content);
|
|
835
|
+
}
|
|
452
836
|
return /*#__PURE__*/React.createElement(RootProviders, {
|
|
453
837
|
seed: normalizedSeed,
|
|
454
|
-
consent: consent
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
838
|
+
consent: consent,
|
|
839
|
+
__self: this,
|
|
840
|
+
__source: {
|
|
841
|
+
fileName: _jsxFileName,
|
|
842
|
+
lineNumber: 128,
|
|
843
|
+
columnNumber: 7
|
|
844
|
+
}
|
|
845
|
+
}, content);
|
|
459
846
|
};
|
|
460
847
|
}
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
useEffect(
|
|
848
|
+
function Dispatcher({
|
|
849
|
+
children,
|
|
850
|
+
seed,
|
|
851
|
+
callback
|
|
852
|
+
}) {
|
|
853
|
+
const dispatch = useEntryStateDispatch();
|
|
854
|
+
useEffect(() => {
|
|
468
855
|
if (callback) {
|
|
469
856
|
callback(dispatch, seed);
|
|
470
857
|
}
|
|
@@ -472,4 +859,330 @@ function Dispatcher(_ref6) {
|
|
|
472
859
|
return children;
|
|
473
860
|
}
|
|
474
861
|
|
|
475
|
-
|
|
862
|
+
var _jsxFileName$1 = "/home/tfischbach/code/pageflow/entry_types/scrolled/package/src/testHelpers/scrollPositionLifecycle.js";
|
|
863
|
+
|
|
864
|
+
/**
|
|
865
|
+
* Takes the same options as {@link renderInEntry} but returns
|
|
866
|
+
* additional helper function to the return value of the
|
|
867
|
+
* {@link `useContentElementLifecycle`} hook:
|
|
868
|
+
*
|
|
869
|
+
* const {simulateScrollPosition} = renderInEntry(...)
|
|
870
|
+
* simulateScrollPosition('near viewport')
|
|
871
|
+
* // => Turns `shouldLoad` and `shouldPrepare` to true
|
|
872
|
+
*/
|
|
873
|
+
function renderInEntryWithContentElementLifecycle(ui, options) {
|
|
874
|
+
return renderInEntryWithScrollPositionLifecycle(ui, {
|
|
875
|
+
lifecycleContext: ContentElementLifecycleContext,
|
|
876
|
+
...options
|
|
877
|
+
});
|
|
878
|
+
}
|
|
879
|
+
function renderInEntryWithScrollPositionLifecycle(ui, {
|
|
880
|
+
lifecycleContext,
|
|
881
|
+
wrapper,
|
|
882
|
+
...options
|
|
883
|
+
} = {}) {
|
|
884
|
+
const emitter = createEmitter();
|
|
885
|
+
return withSimulateScrollPositionHelper(emitter, renderInEntry(ui, {
|
|
886
|
+
wrapper: createScrollPositionProvider(lifecycleContext, emitter, wrapper),
|
|
887
|
+
...options
|
|
888
|
+
}));
|
|
889
|
+
}
|
|
890
|
+
function createScrollPositionProvider(Context, emitter, originalWrapper) {
|
|
891
|
+
const OriginalWrapper = originalWrapper || function Noop({
|
|
892
|
+
children
|
|
893
|
+
}) {
|
|
894
|
+
return children;
|
|
895
|
+
};
|
|
896
|
+
return function ScrollPositionProvider({
|
|
897
|
+
children
|
|
898
|
+
}) {
|
|
899
|
+
const [value, setValue] = useState({
|
|
900
|
+
shouldLoad: false,
|
|
901
|
+
shouldPrepare: false,
|
|
902
|
+
isVisible: false,
|
|
903
|
+
isActive: false
|
|
904
|
+
});
|
|
905
|
+
useEffect(() => {
|
|
906
|
+
function handle(scrollPosition) {
|
|
907
|
+
switch (scrollPosition) {
|
|
908
|
+
case 'near viewport':
|
|
909
|
+
setValue({
|
|
910
|
+
shouldLoad: true,
|
|
911
|
+
shouldPrepare: true,
|
|
912
|
+
isVisible: false,
|
|
913
|
+
isActive: false
|
|
914
|
+
});
|
|
915
|
+
break;
|
|
916
|
+
case 'in viewport':
|
|
917
|
+
setValue({
|
|
918
|
+
shouldLoad: true,
|
|
919
|
+
shouldPrepare: true,
|
|
920
|
+
isVisible: true,
|
|
921
|
+
isActive: false
|
|
922
|
+
});
|
|
923
|
+
break;
|
|
924
|
+
case 'center of viewport':
|
|
925
|
+
setValue({
|
|
926
|
+
shouldLoad: true,
|
|
927
|
+
shouldPrepare: true,
|
|
928
|
+
isVisible: true,
|
|
929
|
+
isActive: true
|
|
930
|
+
});
|
|
931
|
+
break;
|
|
932
|
+
default:
|
|
933
|
+
setValue({
|
|
934
|
+
isVisible: false,
|
|
935
|
+
isActive: false
|
|
936
|
+
});
|
|
937
|
+
break;
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
emitter.on('scroll', handle);
|
|
941
|
+
return () => emitter.off('scroll', handle);
|
|
942
|
+
});
|
|
943
|
+
return /*#__PURE__*/React.createElement(OriginalWrapper, {
|
|
944
|
+
__self: this,
|
|
945
|
+
__source: {
|
|
946
|
+
fileName: _jsxFileName$1,
|
|
947
|
+
lineNumber: 69,
|
|
948
|
+
columnNumber: 7
|
|
949
|
+
}
|
|
950
|
+
}, /*#__PURE__*/React.createElement(Context.Provider, {
|
|
951
|
+
value: value,
|
|
952
|
+
__self: this,
|
|
953
|
+
__source: {
|
|
954
|
+
fileName: _jsxFileName$1,
|
|
955
|
+
lineNumber: 70,
|
|
956
|
+
columnNumber: 9
|
|
957
|
+
}
|
|
958
|
+
}, children));
|
|
959
|
+
};
|
|
960
|
+
}
|
|
961
|
+
const allowedScrollPositions = ['outside viewport', 'near viewport', 'in viewport', 'center of viewport'];
|
|
962
|
+
function withSimulateScrollPositionHelper(emitter, result) {
|
|
963
|
+
return {
|
|
964
|
+
...result,
|
|
965
|
+
simulateScrollPosition(scrollPosition) {
|
|
966
|
+
if (!allowedScrollPositions.includes(scrollPosition)) {
|
|
967
|
+
throw new Error(`Invalid scrollPosition '${scrollPosition}'. ` + `Allowed values: ${allowedScrollPositions.join(', ')}`);
|
|
968
|
+
}
|
|
969
|
+
act(() => {
|
|
970
|
+
emitter.trigger('scroll', scrollPosition);
|
|
971
|
+
});
|
|
972
|
+
}
|
|
973
|
+
};
|
|
974
|
+
}
|
|
975
|
+
function createEmitter() {
|
|
976
|
+
return {
|
|
977
|
+
...BackboneEvents
|
|
978
|
+
};
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
var _jsxFileName$2 = "/home/tfischbach/code/pageflow/entry_types/scrolled/package/src/testHelpers/renderInContentElement.js";
|
|
982
|
+
|
|
983
|
+
/**
|
|
984
|
+
* Provide context as if component was rendered inside of a content element.
|
|
985
|
+
*
|
|
986
|
+
* Returns additional functions to control content element scroll
|
|
987
|
+
* lifecycle, view timeline progress, editor commands, and storyline
|
|
988
|
+
* mode: `simulateScrollPosition`, `simulateScrollProgress`,
|
|
989
|
+
* `triggerEditorCommand`, and `simulateStorylineMode`.
|
|
990
|
+
*
|
|
991
|
+
* `simulateScrollProgress` passes the given progress to all
|
|
992
|
+
* `useContentElementViewTimelineProgress` callbacks, no matter which
|
|
993
|
+
* range they observe. Pass a `range` option to only invoke callbacks
|
|
994
|
+
* observing that range.
|
|
995
|
+
*
|
|
996
|
+
* @param {Function} callback - React component or function returning a React component.
|
|
997
|
+
* @param {Object} [options] - Supports all options supported by {@link `renderInEntry`}.
|
|
998
|
+
* @param {boolean|Object} [options.inlineEditing] -
|
|
999
|
+
* Opt the content element into an inline-editing context (matching
|
|
1000
|
+
* what's available when inline editing is loaded in production).
|
|
1001
|
+
* Pass `true` for editable defaults, or an object to override:
|
|
1002
|
+
* `{isEditable, isSelected, transientState}`. `transientState` is
|
|
1003
|
+
* installed as the `setTransientState` function on the editor state
|
|
1004
|
+
* context — pass a jest spy to assert on it. Omitting the option
|
|
1005
|
+
* gives the frontend-mode defaults (`isEditable: false, isSelected:
|
|
1006
|
+
* false, setTransientState: noop`) without wrapping any
|
|
1007
|
+
* inline-editing-only providers (DndProvider, editor command
|
|
1008
|
+
* emitter).
|
|
1009
|
+
* @param {Object} [options.phonePlatform] - Fake result of `usePhonePlatform`.
|
|
1010
|
+
* @param {Object} [options.consentState] - Pass 'undecided' to render third party consent opt in.
|
|
1011
|
+
*
|
|
1012
|
+
* @example
|
|
1013
|
+
*
|
|
1014
|
+
* const {getByRole, simulateScrollPosition, triggerEditorCommand, simulateStorylineMode} =
|
|
1015
|
+
* renderInContentElement(<MyContentElement />, {
|
|
1016
|
+
* seed: {...},
|
|
1017
|
+
* inlineEditing: {isSelected: true}
|
|
1018
|
+
* });
|
|
1019
|
+
* simulateScrollPosition('near viewport');
|
|
1020
|
+
* simulateScrollProgress(0.5);
|
|
1021
|
+
* simulateScrollProgress(0.5, {range: 'pinned'});
|
|
1022
|
+
* triggerEditorCommand({type: 'HIGHLIGHT'});
|
|
1023
|
+
* simulateStorylineMode('background');
|
|
1024
|
+
*/
|
|
1025
|
+
function renderInContentElement(ui, {
|
|
1026
|
+
inlineEditing,
|
|
1027
|
+
phonePlatform = false,
|
|
1028
|
+
wrapper: OriginalWrapper,
|
|
1029
|
+
consentState = 'accepted',
|
|
1030
|
+
seed,
|
|
1031
|
+
...options
|
|
1032
|
+
} = {}) {
|
|
1033
|
+
const emitter = Object.assign({}, BackboneEvents);
|
|
1034
|
+
const storylineEmitter = Object.assign({}, BackboneEvents);
|
|
1035
|
+
const viewTimelineEmitter = Object.assign({}, BackboneEvents);
|
|
1036
|
+
const viewTimeline = {
|
|
1037
|
+
subscribe(range, callback) {
|
|
1038
|
+
function handleProgress(progress, options) {
|
|
1039
|
+
if (!options.range || options.range === range) {
|
|
1040
|
+
callback(progress);
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
viewTimelineEmitter.on('progress', handleProgress);
|
|
1044
|
+
return () => viewTimelineEmitter.off('progress', handleProgress);
|
|
1045
|
+
}
|
|
1046
|
+
};
|
|
1047
|
+
const inlineEditingConfig = resolveInlineEditing(inlineEditing);
|
|
1048
|
+
function Wrapper({
|
|
1049
|
+
children
|
|
1050
|
+
}) {
|
|
1051
|
+
const [storylineMode, setStorylineMode] = useState('active');
|
|
1052
|
+
useEffect(() => {
|
|
1053
|
+
storylineEmitter.on('storylineMode', setStorylineMode);
|
|
1054
|
+
return () => storylineEmitter.off('storylineMode', setStorylineMode);
|
|
1055
|
+
}, []);
|
|
1056
|
+
let tree = OriginalWrapper ? /*#__PURE__*/React.createElement(OriginalWrapper, {
|
|
1057
|
+
children: children,
|
|
1058
|
+
__self: this,
|
|
1059
|
+
__source: {
|
|
1060
|
+
fileName: _jsxFileName$2,
|
|
1061
|
+
lineNumber: 95,
|
|
1062
|
+
columnNumber: 34
|
|
1063
|
+
}
|
|
1064
|
+
}) : children;
|
|
1065
|
+
if (inlineEditingConfig) {
|
|
1066
|
+
tree = /*#__PURE__*/React.createElement(DndProvider, {
|
|
1067
|
+
backend: HTML5Backend,
|
|
1068
|
+
__self: this,
|
|
1069
|
+
__source: {
|
|
1070
|
+
fileName: _jsxFileName$2,
|
|
1071
|
+
lineNumber: 99,
|
|
1072
|
+
columnNumber: 9
|
|
1073
|
+
}
|
|
1074
|
+
}, /*#__PURE__*/React.createElement(ContentElementEditorCommandEmitterContext.Provider, {
|
|
1075
|
+
value: emitter,
|
|
1076
|
+
__self: this,
|
|
1077
|
+
__source: {
|
|
1078
|
+
fileName: _jsxFileName$2,
|
|
1079
|
+
lineNumber: 100,
|
|
1080
|
+
columnNumber: 11
|
|
1081
|
+
}
|
|
1082
|
+
}, /*#__PURE__*/React.createElement(ContentElementEditorStateContext.Provider, {
|
|
1083
|
+
value: inlineEditingConfig,
|
|
1084
|
+
__self: this,
|
|
1085
|
+
__source: {
|
|
1086
|
+
fileName: _jsxFileName$2,
|
|
1087
|
+
lineNumber: 101,
|
|
1088
|
+
columnNumber: 13
|
|
1089
|
+
}
|
|
1090
|
+
}, tree)));
|
|
1091
|
+
}
|
|
1092
|
+
return /*#__PURE__*/React.createElement(MainStorylineActivity, {
|
|
1093
|
+
activeExcursion: storylineMode !== 'active' ? {
|
|
1094
|
+
id: 1
|
|
1095
|
+
} : null,
|
|
1096
|
+
__self: this,
|
|
1097
|
+
__source: {
|
|
1098
|
+
fileName: _jsxFileName$2,
|
|
1099
|
+
lineNumber: 110,
|
|
1100
|
+
columnNumber: 7
|
|
1101
|
+
}
|
|
1102
|
+
}, /*#__PURE__*/React.createElement(ContentElementAttributesProvider, {
|
|
1103
|
+
id: 42,
|
|
1104
|
+
__self: this,
|
|
1105
|
+
__source: {
|
|
1106
|
+
fileName: _jsxFileName$2,
|
|
1107
|
+
lineNumber: 111,
|
|
1108
|
+
columnNumber: 9
|
|
1109
|
+
}
|
|
1110
|
+
}, /*#__PURE__*/React.createElement(ContentElementViewTimelineContext.Provider, {
|
|
1111
|
+
value: viewTimeline,
|
|
1112
|
+
__self: this,
|
|
1113
|
+
__source: {
|
|
1114
|
+
fileName: _jsxFileName$2,
|
|
1115
|
+
lineNumber: 112,
|
|
1116
|
+
columnNumber: 11
|
|
1117
|
+
}
|
|
1118
|
+
}, tree)));
|
|
1119
|
+
}
|
|
1120
|
+
return {
|
|
1121
|
+
...renderInEntryWithScrollPositionLifecycle(ui, {
|
|
1122
|
+
lifecycleContext: ContentElementLifecycleContext,
|
|
1123
|
+
wrapper: Wrapper,
|
|
1124
|
+
consent: createConsent(consentState),
|
|
1125
|
+
phonePlatform,
|
|
1126
|
+
seed: {
|
|
1127
|
+
...consentSeed,
|
|
1128
|
+
...seed
|
|
1129
|
+
},
|
|
1130
|
+
...options
|
|
1131
|
+
}),
|
|
1132
|
+
triggerEditorCommand(command) {
|
|
1133
|
+
act(() => {
|
|
1134
|
+
emitter.trigger(`command:42`, command);
|
|
1135
|
+
});
|
|
1136
|
+
},
|
|
1137
|
+
simulateStorylineMode(mode) {
|
|
1138
|
+
act(() => {
|
|
1139
|
+
storylineEmitter.trigger('storylineMode', mode);
|
|
1140
|
+
});
|
|
1141
|
+
},
|
|
1142
|
+
simulateScrollProgress(progress, {
|
|
1143
|
+
range
|
|
1144
|
+
} = {}) {
|
|
1145
|
+
act(() => {
|
|
1146
|
+
viewTimelineEmitter.trigger('progress', progress, {
|
|
1147
|
+
range
|
|
1148
|
+
});
|
|
1149
|
+
});
|
|
1150
|
+
}
|
|
1151
|
+
};
|
|
1152
|
+
}
|
|
1153
|
+
function resolveInlineEditing(option) {
|
|
1154
|
+
var _overrides$isEditable, _overrides$isSelected, _overrides$transientS;
|
|
1155
|
+
if (!option) return null;
|
|
1156
|
+
const overrides = option === true ? {} : option;
|
|
1157
|
+
return {
|
|
1158
|
+
isEditable: (_overrides$isEditable = overrides.isEditable) !== null && _overrides$isEditable !== void 0 ? _overrides$isEditable : true,
|
|
1159
|
+
isSelected: (_overrides$isSelected = overrides.isSelected) !== null && _overrides$isSelected !== void 0 ? _overrides$isSelected : false,
|
|
1160
|
+
setTransientState: (_overrides$transientS = overrides.transientState) !== null && _overrides$transientS !== void 0 ? _overrides$transientS : () => {},
|
|
1161
|
+
select: () => {},
|
|
1162
|
+
selectNewThread: () => {}
|
|
1163
|
+
};
|
|
1164
|
+
}
|
|
1165
|
+
function createConsent(consentState) {
|
|
1166
|
+
const consent = Consent.create();
|
|
1167
|
+
consent.registerVendor('testVendor', {
|
|
1168
|
+
displayName: 'Test Vendor',
|
|
1169
|
+
description: 'Test embeds',
|
|
1170
|
+
paradigm: 'lazy opt-in'
|
|
1171
|
+
});
|
|
1172
|
+
consent.closeVendorRegistration();
|
|
1173
|
+
if (consentState === 'accepted') {
|
|
1174
|
+
consent.accept('testVendor');
|
|
1175
|
+
}
|
|
1176
|
+
return consent;
|
|
1177
|
+
}
|
|
1178
|
+
const consentSeed = {
|
|
1179
|
+
consentVendors: [{
|
|
1180
|
+
name: 'testVendor',
|
|
1181
|
+
paradigm: 'lazy opt-in'
|
|
1182
|
+
}],
|
|
1183
|
+
contentElementConsentVendors: {
|
|
1184
|
+
42: 'testVendor'
|
|
1185
|
+
}
|
|
1186
|
+
};
|
|
1187
|
+
|
|
1188
|
+
export { normalizeSeed, renderContentElementConfigurationEditor, renderHookInEntry, renderInContentElement, renderInEntry, renderInEntryWithContentElementLifecycle, renderInEntryWithScrollPositionLifecycle, useConfigurationEditorMatchers, useContentElementMatchers };
|