wagtail 6.3.2__py3-none-any.whl → 6.4rc1__py3-none-any.whl
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.
- wagtail/__init__.py +1 -1
- wagtail/actions/publish_revision.py +4 -5
- wagtail/admin/auth.py +0 -2
- wagtail/admin/checks.py +1 -1
- wagtail/admin/filters.py +3 -1
- wagtail/admin/forms/account.py +21 -11
- wagtail/admin/forms/collections.py +2 -9
- wagtail/admin/forms/formsets.py +32 -0
- wagtail/admin/forms/pages.py +5 -1
- wagtail/admin/forms/workflows.py +2 -13
- wagtail/admin/locale/ar/LC_MESSAGES/django.mo +0 -0
- wagtail/admin/locale/ar/LC_MESSAGES/django.po +68 -1
- wagtail/admin/locale/ar/LC_MESSAGES/djangojs.mo +0 -0
- wagtail/admin/locale/ar/LC_MESSAGES/djangojs.po +5 -1
- wagtail/admin/locale/en/LC_MESSAGES/django.po +312 -356
- wagtail/admin/locale/en/LC_MESSAGES/djangojs.po +21 -16
- wagtail/admin/menu.py +0 -13
- wagtail/admin/panels/base.py +2 -2
- wagtail/admin/panels/group.py +4 -1
- wagtail/admin/panels/inline_panel.py +5 -2
- wagtail/admin/panels/model_utils.py +36 -0
- wagtail/admin/panels/page_utils.py +2 -40
- wagtail/admin/panels/signal_handlers.py +0 -2
- wagtail/admin/static/wagtailadmin/css/core.css +1 -1
- wagtail/admin/static/wagtailadmin/css/panels/draftail.css +1 -1
- wagtail/admin/static/wagtailadmin/css/panels/streamfield.css +1 -1
- wagtail/admin/static/wagtailadmin/js/comments.js +1 -1
- wagtail/admin/static/wagtailadmin/js/core.js +1 -1
- wagtail/admin/static/wagtailadmin/js/core.js.LICENSE.txt +1 -8
- wagtail/admin/static/wagtailadmin/js/draftail.js +1 -1
- wagtail/admin/static/wagtailadmin/js/modal-workflow.js +1 -1
- wagtail/admin/static/wagtailadmin/js/page-chooser-modal.js +1 -1
- wagtail/admin/static/wagtailadmin/js/privacy-switch.js +1 -1
- wagtail/admin/static/wagtailadmin/js/sidebar.js +1 -1
- wagtail/admin/static/wagtailadmin/js/telepath/blocks.js +1 -1
- wagtail/admin/static/wagtailadmin/js/userbar.js +1 -1
- wagtail/admin/static/wagtailadmin/js/userbar.js.LICENSE.txt +1 -1
- wagtail/admin/static/wagtailadmin/js/vendor.js +1 -1
- wagtail/admin/static/wagtailadmin/js/vendor.js.LICENSE.txt +7 -0
- wagtail/admin/templates/wagtailadmin/404.html +4 -0
- wagtail/admin/templates/wagtailadmin/chooser/browse.html +2 -1
- wagtail/admin/templates/wagtailadmin/chooser/tables/parent_page_cell.html +1 -1
- wagtail/admin/templates/wagtailadmin/collections/_privacy_switch.html +8 -1
- wagtail/admin/templates/wagtailadmin/generic/confirm_delete.html +15 -9
- wagtail/admin/templates/wagtailadmin/generic/confirm_unpublish.html +21 -25
- wagtail/admin/templates/wagtailadmin/generic/form.html +1 -1
- wagtail/admin/templates/wagtailadmin/generic/preview_error.html +3 -0
- wagtail/admin/templates/wagtailadmin/generic/revisions/compare.html +63 -76
- wagtail/admin/templates/wagtailadmin/pages/_editor_js.html +0 -2
- wagtail/admin/templates/wagtailadmin/pages/edit.html +1 -5
- wagtail/admin/templates/wagtailadmin/panels/inline_panel_child.html +1 -0
- wagtail/admin/templates/wagtailadmin/permissions/includes/collection_member_permissions_form.html +1 -1
- wagtail/admin/templates/wagtailadmin/permissions/includes/collection_member_permissions_formset.html +6 -22
- wagtail/admin/templates/wagtailadmin/shared/formatted_field.html +2 -2
- wagtail/admin/templates/wagtailadmin/shared/header.html +2 -2
- wagtail/admin/templates/wagtailadmin/shared/page_status_tag_new.html +32 -39
- wagtail/admin/templates/wagtailadmin/shared/revisions/confirm_unschedule.html +13 -17
- wagtail/admin/templates/wagtailadmin/shared/side_panels/includes/status/privacy.html +15 -3
- wagtail/admin/templates/wagtailadmin/shared/side_panels/preview.html +1 -1
- wagtail/admin/templates/wagtailadmin/skeleton.html +4 -2
- wagtail/admin/templates/wagtailadmin/workflows/create.html +1 -1
- wagtail/admin/templates/wagtailadmin/workflows/edit.html +1 -1
- wagtail/admin/templates/wagtailadmin/workflows/includes/workflow_pages_form.html +1 -1
- wagtail/admin/templates/wagtailadmin/workflows/includes/workflow_pages_formset.html +6 -23
- wagtail/admin/templatetags/wagtailadmin_tags.py +12 -0
- wagtail/admin/templatetags/wagtailuserbar.py +2 -3
- wagtail/admin/tests/pages/test_create_page.py +110 -1
- wagtail/admin/tests/pages/test_edit_page.py +3 -2
- wagtail/admin/tests/pages/test_explorer_view.py +18 -0
- wagtail/admin/tests/pages/test_page_usage.py +24 -20
- wagtail/admin/tests/pages/test_preview.py +69 -1
- wagtail/admin/tests/pages/test_revisions.py +40 -6
- wagtail/admin/tests/test_account_management.py +39 -1
- wagtail/admin/tests/test_audit_log.py +4 -2
- wagtail/admin/tests/test_block_preview.py +224 -0
- wagtail/admin/tests/test_edit_handlers.py +23 -6
- wagtail/admin/tests/test_page_chooser.py +50 -3
- wagtail/admin/tests/test_privacy.py +49 -26
- wagtail/admin/tests/test_site_summary.py +15 -10
- wagtail/admin/tests/test_templatetags.py +19 -0
- wagtail/admin/tests/test_userbar.py +82 -1
- wagtail/admin/tests/test_views_generic.py +27 -12
- wagtail/admin/tests/test_workflows.py +69 -0
- wagtail/admin/tests/tests.py +23 -4
- wagtail/admin/tests/ui/test_sidebar.py +1 -1
- wagtail/admin/tests/viewsets/test_model_viewset.py +15 -13
- wagtail/admin/ui/side_panels.py +7 -4
- wagtail/admin/urls/__init__.py +6 -0
- wagtail/admin/urls/pages.py +1 -1
- wagtail/admin/userbar.py +21 -1
- wagtail/admin/views/account.py +5 -0
- wagtail/admin/views/chooser.py +5 -1
- wagtail/admin/views/collections.py +0 -2
- wagtail/admin/views/generic/base.py +20 -10
- wagtail/admin/views/generic/history.py +0 -1
- wagtail/admin/views/generic/models.py +79 -21
- wagtail/admin/views/generic/preview.py +50 -1
- wagtail/admin/views/mixins.py +4 -2
- wagtail/admin/views/pages/bulk_actions/delete.py +11 -23
- wagtail/admin/views/pages/bulk_actions/page_bulk_action.py +17 -0
- wagtail/admin/views/pages/bulk_actions/publish.py +11 -31
- wagtail/admin/views/pages/bulk_actions/unpublish.py +11 -31
- wagtail/admin/views/pages/create.py +1 -0
- wagtail/admin/views/pages/edit.py +38 -30
- wagtail/admin/views/pages/revisions.py +43 -114
- wagtail/admin/views/pages/utils.py +0 -1
- wagtail/admin/views/tags.py +6 -2
- wagtail/admin/views/workflows.py +8 -6
- wagtail/admin/viewsets/model.py +0 -4
- wagtail/admin/viewsets/pages.py +0 -1
- wagtail/admin/widgets/tags.py +1 -0
- wagtail/api/v2/tests/test_documents.py +4 -2
- wagtail/api/v2/tests/test_images.py +4 -2
- wagtail/api/v2/tests/test_pages.py +8 -4
- wagtail/blocks/base.py +59 -1
- wagtail/blocks/field_block.py +6 -0
- wagtail/blocks/list_block.py +4 -0
- wagtail/blocks/static_block.py +3 -0
- wagtail/blocks/stream_block.py +5 -1
- wagtail/blocks/struct_block.py +6 -0
- wagtail/compat.py +16 -0
- wagtail/contrib/forms/forms.py +27 -7
- wagtail/contrib/forms/locale/en/LC_MESSAGES/django.po +2 -2
- wagtail/contrib/forms/tests/test_models.py +7 -5
- wagtail/contrib/forms/tests/test_views.py +75 -0
- wagtail/contrib/frontend_cache/tasks.py +83 -0
- wagtail/contrib/frontend_cache/tests.py +47 -32
- wagtail/contrib/frontend_cache/utils.py +2 -70
- wagtail/contrib/redirects/base_formats.py +2 -2
- wagtail/contrib/redirects/locale/ar/LC_MESSAGES/django.mo +0 -0
- wagtail/contrib/redirects/locale/ar/LC_MESSAGES/django.po +3 -0
- wagtail/contrib/redirects/locale/en/LC_MESSAGES/django.po +24 -37
- wagtail/contrib/redirects/templates/wagtailredirects/add.html +1 -24
- wagtail/contrib/redirects/templates/wagtailredirects/confirm_delete.html +3 -13
- wagtail/contrib/redirects/tests/test_redirects.py +122 -110
- wagtail/contrib/redirects/tests/test_signal_handlers.py +75 -69
- wagtail/contrib/redirects/urls.py +2 -2
- wagtail/contrib/redirects/views.py +35 -73
- wagtail/contrib/search_promotions/admin_urls.py +10 -3
- wagtail/contrib/search_promotions/forms.py +55 -26
- wagtail/contrib/search_promotions/locale/en/LC_MESSAGES/django.po +44 -54
- wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/add.html +21 -31
- wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/confirm_delete.html +3 -12
- wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/edit.html +11 -34
- wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/includes/searchpromotion_form.html +1 -0
- wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/includes/searchpromotions_formset.js +2 -1
- wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/index.html +0 -1
- wagtail/contrib/search_promotions/tests.py +814 -13
- wagtail/contrib/search_promotions/views/__init__.py +1 -0
- wagtail/contrib/search_promotions/views/reports.py +56 -0
- wagtail/contrib/search_promotions/views/settings.py +258 -0
- wagtail/contrib/search_promotions/wagtail_hooks.py +12 -1
- wagtail/contrib/settings/locale/ar/LC_MESSAGES/django.mo +0 -0
- wagtail/contrib/settings/locale/ar/LC_MESSAGES/django.po +6 -1
- wagtail/contrib/settings/locale/en/LC_MESSAGES/django.po +3 -3
- wagtail/contrib/settings/templates/wagtailsettings/edit.html +1 -5
- wagtail/contrib/settings/tests/generic/test_admin.py +2 -5
- wagtail/contrib/settings/tests/generic/test_register.py +1 -1
- wagtail/contrib/settings/tests/site_specific/test_admin.py +2 -5
- wagtail/contrib/settings/tests/site_specific/test_register.py +1 -1
- wagtail/contrib/settings/views.py +9 -23
- wagtail/contrib/simple_translation/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/contrib/styleguide/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/contrib/table_block/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/contrib/table_block/tests.py +4 -1
- wagtail/contrib/typed_table_block/blocks.py +3 -0
- wagtail/contrib/typed_table_block/locale/en/LC_MESSAGES/django.po +10 -10
- wagtail/contrib/typed_table_block/static/typed_table_block/js/typed_table_block.js +1 -1
- wagtail/contrib/typed_table_block/tests.py +33 -0
- wagtail/documents/locale/en/LC_MESSAGES/django.po +26 -26
- wagtail/documents/migrations/0011_add_choose_permissions.py +1 -0
- wagtail/documents/models.py +1 -0
- wagtail/documents/signal_handlers.py +6 -2
- wagtail/documents/static/wagtaildocs/js/add-multiple.js +1 -1
- wagtail/documents/templates/wagtaildocs/documents/edit.html +1 -3
- wagtail/documents/templates/wagtaildocs/multiple/add.html +7 -1
- wagtail/documents/tests/test_admin_views.py +74 -33
- wagtail/documents/tests/test_views.py +21 -12
- wagtail/documents/views/chooser.py +1 -0
- wagtail/documents/views/documents.py +1 -2
- wagtail/documents/views/multiple.py +0 -1
- wagtail/documents/views/serve.py +9 -2
- wagtail/documents/wagtail_hooks.py +6 -1
- wagtail/embeds/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/embeds/oembed_providers.py +0 -64
- wagtail/fields.py +3 -0
- wagtail/images/apps.py +2 -1
- wagtail/images/blocks.py +6 -2
- wagtail/images/forms.py +40 -3
- wagtail/images/locale/ar/LC_MESSAGES/django.mo +0 -0
- wagtail/images/locale/ar/LC_MESSAGES/django.po +4 -0
- wagtail/images/locale/en/LC_MESSAGES/django.po +49 -49
- wagtail/images/migrations/0023_add_choose_permissions.py +1 -0
- wagtail/images/rich_text/contentstate.py +1 -0
- wagtail/images/rich_text/editor_html.py +1 -0
- wagtail/images/signal_handlers.py +17 -10
- wagtail/images/static/wagtailimages/js/add-multiple.js +1 -1
- wagtail/images/static/wagtailimages/js/image-block.js +1 -1
- wagtail/images/static/wagtailimages/js/image-chooser-telepath.js +1 -1
- wagtail/images/static/wagtailimages/js/image-chooser.js +1 -1
- wagtail/images/static/wagtailimages/js/image-url-generator.js +1 -1
- wagtail/images/static/wagtailimages/js/vendor/jquery.fileupload-image.js +1 -1
- wagtail/images/tasks.py +18 -0
- wagtail/images/templates/wagtailimages/images/edit.html +1 -3
- wagtail/images/templates/wagtailimages/images/url_generator.html +1 -1
- wagtail/images/templates/wagtailimages/multiple/add.html +7 -2
- wagtail/images/templates/wagtailimages/widgets/image_chooser.html +1 -1
- wagtail/images/tests/test_admin_views.py +53 -29
- wagtail/images/tests/test_blocks.py +3 -2
- wagtail/images/tests/test_models.py +12 -10
- wagtail/images/tests/tests.py +10 -0
- wagtail/images/views/chooser.py +1 -0
- wagtail/images/views/images.py +1 -3
- wagtail/images/views/multiple.py +0 -1
- wagtail/images/views/serve.py +18 -2
- wagtail/images/widgets.py +3 -0
- wagtail/locale/en/LC_MESSAGES/django.po +228 -216
- wagtail/locales/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/management/commands/publish_scheduled.py +1 -1
- wagtail/migrations/0087_alter_grouppagepermission_unique_together_and_more.py +16 -8
- wagtail/models/__init__.py +300 -119
- wagtail/models/i18n.py +2 -2
- wagtail/models/panels.py +37 -0
- wagtail/models/sites.py +7 -6
- wagtail/permission_policies/pages.py +2 -2
- wagtail/project_template/project_name/settings/base.py +4 -0
- wagtail/project_template/requirements.txt +1 -1
- wagtail/query.py +145 -0
- wagtail/search/backends/database/mysql/mysql.py +25 -17
- wagtail/search/backends/database/postgres/postgres.py +44 -83
- wagtail/search/backends/database/sqlite/sqlite.py +25 -17
- wagtail/search/backends/elasticsearch7.py +4 -0
- wagtail/search/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/search/query.py +8 -2
- wagtail/search/signal_handlers.py +6 -9
- wagtail/search/tasks.py +10 -0
- wagtail/search/tests/test_elasticsearch7_backend.py +21 -0
- wagtail/search/tests/test_index_functions.py +10 -6
- wagtail/search/tests/test_postgres_backend.py +0 -14
- wagtail/signal_handlers.py +5 -20
- wagtail/sites/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/snippets/locale/en/LC_MESSAGES/django.po +3 -13
- wagtail/snippets/tests/test_preview.py +5 -0
- wagtail/snippets/tests/test_snippets.py +100 -45
- wagtail/snippets/tests/test_usage.py +29 -24
- wagtail/snippets/tests/test_viewset.py +1 -1
- wagtail/snippets/views/snippets.py +0 -12
- wagtail/tasks.py +41 -0
- wagtail/templates/wagtailcore/shared/block_preview.html +29 -0
- wagtail/test/earlypage/__init__.py +0 -0
- wagtail/test/earlypage/migrations/0001_initial.py +37 -0
- wagtail/test/earlypage/migrations/__init__.py +0 -0
- wagtail/test/earlypage/models.py +14 -0
- wagtail/test/settings.py +3 -0
- wagtail/test/testapp/fixtures/test.json +7 -0
- wagtail/test/testapp/fixtures/test_specific.json +6 -3
- wagtail/test/testapp/models.py +58 -44
- wagtail/test/testapp/templates/tests/custom_block_preview.html +16 -0
- wagtail/test/testapp/templates/tests/static_block_preview.html +5 -0
- wagtail/test/testapp/wagtail_hooks.py +9 -0
- wagtail/tests/test_blocks.py +189 -2
- wagtail/tests/test_hooks.py +166 -1
- wagtail/tests/test_management_commands.py +54 -13
- wagtail/tests/test_page_allowed_http_methods.py +32 -0
- wagtail/tests/test_page_model.py +68 -0
- wagtail/tests/test_page_privacy.py +10 -0
- wagtail/tests/test_page_queryset.py +79 -0
- wagtail/tests/test_reference_index.py +84 -75
- wagtail/tests/test_streamfield.py +30 -0
- wagtail/tests/test_utils.py +61 -0
- wagtail/users/forms.py +2 -9
- wagtail/users/locale/en/LC_MESSAGES/django.po +17 -17
- wagtail/users/templates/wagtailusers/groups/create.html +0 -5
- wagtail/users/templates/wagtailusers/groups/includes/page_permissions_form.html +1 -1
- wagtail/users/templates/wagtailusers/groups/includes/page_permissions_formset.html +6 -6
- wagtail/users/tests/test_admin_views.py +96 -4
- wagtail/users/tests/test_utils.py +76 -0
- wagtail/users/utils.py +43 -11
- wagtail/utils/setup.py +2 -2
- wagtail/utils/templates.py +26 -0
- wagtail/utils/widgets.py +1 -0
- wagtail/views.py +9 -1
- wagtail/wagtail_hooks.py +67 -29
- {wagtail-6.3.2.dist-info → wagtail-6.4rc1.dist-info}/METADATA +2 -2
- {wagtail-6.3.2.dist-info → wagtail-6.4rc1.dist-info}/RECORD +289 -276
- wagtail/admin/static/wagtailadmin/js/expanding-formset.js +0 -1
- wagtail/admin/static/wagtailadmin/js/vendor/rangy-core.js +0 -1
- wagtail/admin/static/wagtailadmin/js/vendor/uuidv4.min.js +0 -1
- wagtail/contrib/search_promotions/views.py +0 -323
- wagtail/images/static/wagtailimages/js/vendor/canvas-to-blob.min.js +0 -1
- wagtail/users/static/wagtailusers/js/group-form.js +0 -1
- wagtail/users/templates/wagtailusers/groups/includes/group_form_js.html +0 -3
- {wagtail-6.3.2.dist-info → wagtail-6.4rc1.dist-info}/LICENSE +0 -0
- {wagtail-6.3.2.dist-info → wagtail-6.4rc1.dist-info}/WHEEL +0 -0
- {wagtail-6.3.2.dist-info → wagtail-6.4rc1.dist-info}/entry_points.txt +0 -0
- {wagtail-6.3.2.dist-info → wagtail-6.4rc1.dist-info}/top_level.txt +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{"use strict";var t,e={7595:(t,e,n)=>{var i=n(4327),o=n(9675),s=n(4545);class l{constructor(t,e,n,o,s){this.blockDef=t,this.type=t.name,this.caption="",this.columns=[],this.rows=[],this.columnCountIncludingDeleted=0,this.rowCountIncludingDeleted=0,this.prefix=n,this.childBlockDefsByName={},this.blockDef.childBlockDefs.forEach((t=>{this.childBlockDefsByName[t.name]=t}));const l=this.blockDef.meta.strings,a=`${(0,i.Z)(n)}-caption`,d=$(`\n <div class="typed-table-block ${(0,i.Z)(this.blockDef.meta.classname||"")}">\n <div class="w-field__wrapper" data-field-wrapper>\n <label class="w-field__label" for="${a}">\n ${l.CAPTION}\n </label>\n <div class="w-field w-field--char_field w-field--text_input" data-field>\n <div class="w-field__help" data-field-help>\n <div class="help">\n ${l.CAPTION_HELP_TEXT}\n </div>\n </div>\n <div class="w-field__input" data-field-input>\n <input type="text" id="${a}" name="${a}" value="" />\n <span></span>\n </div>\n </div>\n </div>\n <input type="hidden" name="${(0,i.Z)(n)}-column-count" data-column-count value="0">\n <input type="hidden" name="${(0,i.Z)(n)}-row-count" data-row-count value="0">\n <div data-deleted-fields></div>\n <div class="typed-table-block__wrapper">\n <table>\n <thead>\n <tr>\n <th></th>\n <th class="control-cell">\n <button type="button" class="button button-small button-secondary append-column" data-append-column>\n ${(0,i.Z)(l.ADD_COLUMN)}\n </button>\n </th>\n </tr>\n </thead>\n <tbody>\n </tbody>\n <tfoot>\n <tr>\n <td class="control-cell">\n <button\n type="button"\n class="button button-small button-secondary button--icon text-replace prepend-row"\n data-add-row\n aria-label="${(0,i.Z)(l.ADD_ROW)}"\n title="${(0,i.Z)(l.ADD_ROW)}"\n >\n <svg class="icon icon-plus icon" aria-hidden="true">\n <use href="#icon-plus"></use>\n </svg>\n </button></td>\n </tr>\n </tfoot>\n </table>\n </div>\n </div>\n `);$(e).replaceWith(d),this.container=d,this.captionInput=d.find(`#${a}`).get(0),this.thead=d.find("table > thead").get(0),this.tbody=d.find("table > tbody").get(0),this.columnCountInput=d.find("input[data-column-count]").get(0),this.rowCountInput=d.find("input[data-row-count]").get(0),this.deletedFieldsContainer=d.find("[data-deleted-fields]").get(0),this.appendColumnButton=d.find("button[data-append-column]"),this.addRowButton=d.find("button[data-add-row]"),this.addRowButton.hide(),this.blockDef.meta.helpText&&d.append(`\n <div class="c-sf-help">\n <div class="help">\n ${this.blockDef.meta.helpText}\n </div>\n </div>\n `),this.addColumnCallback=null,this.addColumnMenu=$('<ul class="add-column-menu"></ul>'),this.blockDef.childBlockDefs.forEach((t=>{const e=$('<button type="button" class="button button-small"></button>').text(t.meta.label);e.on("click",(()=>{this.addColumnCallback&&this.addColumnCallback(t),this.hideAddColumnMenu()}));const n=$("<li></li>").append(e);this.addColumnMenu.append(n)})),this.addColumnMenuBaseElement=null,this.appendColumnButton.on("click",(()=>{this.toggleAddColumnMenu(this.appendColumnButton,(t=>{this.insertColumn(this.columns.length,t,{addInitialRow:!0})}))})),this.addRowButton.on("click",(()=>{this.insertRow(this.rows.length)})),this.setState(o),s&&this.setError(s)}showAddColumnMenu(t,e){this.addColumnMenuBaseElement=t,t.after(this.addColumnMenu),this.addColumnMenu.show(),this.addColumnCallback=e}hideAddColumnMenu(){this.addColumnMenu.hide(),this.addColumnMenuBaseElement=null}toggleAddColumnMenu(t,e){this.addColumnMenuBaseElement===t?this.hideAddColumnMenu():this.showAddColumnMenu(t,e)}clear(){this.setCaption(""),this.columns=[],this.rows=[],this.columnCountIncludingDeleted=0,this.columnCountInput.value=0,this.rowCountIncludingDeleted=0,this.rowCountInput.value=0,this.deletedFieldsContainer.replaceChildren();const t=this.thead.children[0];t.replaceChildren(t.firstElementChild,t.lastElementChild),this.appendColumnButton.text(this.blockDef.meta.strings.ADD_COLUMN).removeClass("button--icon text-replace white").removeAttr("aria-label").removeAttr("title"),this.tbody.replaceChildren(),this.addRowButton.hide()}setCaption(t){this.caption=t,this.captionInput.value=t}insertColumn(t,e,n){const s={blockDef:e,position:t,id:this.columnCountIncludingDeleted};this.columnCountIncludingDeleted+=1,(0,o.y)(t,this.columns.length).forEach((t=>{this.columns[t].position+=1,this.columns[t].positionInput.value=this.columns[t].position})),this.columns.splice(t,0,s),this.columnCountInput.value=this.columnCountIncludingDeleted;const l=this.thead.children[0],a=l.children,d=document.createElement("th");l.insertBefore(d,a[t+1]),s.typeInput=document.createElement("input"),s.typeInput.type="hidden",s.typeInput.name=this.prefix+"-column-"+s.id+"-type",s.typeInput.value=e.name,d.appendChild(s.typeInput),s.positionInput=document.createElement("input"),s.positionInput.type="hidden",s.positionInput.name=this.prefix+"-column-"+s.id+"-order",s.positionInput.value=t,d.appendChild(s.positionInput),s.deletedInput=document.createElement("input"),s.deletedInput.type="hidden",s.deletedInput.name=this.prefix+"-column-"+s.id+"-deleted",s.deletedInput.value="",this.deletedFieldsContainer.appendChild(s.deletedInput);const u=$(`<button type="button"\n class="button button-secondary button-small button--icon text-replace prepend-column"\n aria-label="${(0,i.Z)(this.blockDef.meta.strings.INSERT_COLUMN)}"\n title="${(0,i.Z)(this.blockDef.meta.strings.INSERT_COLUMN)}">\n <svg class="icon icon-plus icon" aria-hidden="true"><use href="#icon-plus"></use></svg>\n </button>`);$(d).append(u),u.on("click",(()=>{this.toggleAddColumnMenu(u,(t=>{this.insertColumn(s.position,t,{addInitialRow:!0})}))})),s.headingInput=document.createElement("input"),s.headingInput.type="text",s.headingInput.name=this.prefix+"-column-"+s.id+"-heading",s.headingInput.className="column-heading",s.headingInput.placeholder=this.blockDef.meta.strings.COLUMN_HEADING,d.appendChild(s.headingInput);const c=$(`<button type="button"\n class="button button-secondary button-small button--icon text-replace no delete-column"\n aria-label="${(0,i.Z)(this.blockDef.meta.strings.DELETE_COLUMN)}"\n title="${(0,i.Z)(this.blockDef.meta.strings.DELETE_COLUMN)}">\n <svg class="icon icon-bin icon" aria-hidden="true"><use href="#icon-bin"></use></svg>\n </button>`);$(d).append(c),c.on("click",(()=>{this.deleteColumn(s.position)}));const r=this.blockDef.childBlockDefaultStates[e.name];return Array.from(this.tbody.children).forEach(((e,n)=>{const i=this.rows[n],o=e.children,l=document.createElement("td");e.insertBefore(l,o[t+1]);const a=this.initCell(l,s,i,r);i.blocks.splice(t,0,a)})),this.addRowButton.show(),this.appendColumnButton.html('<svg class="icon icon-plus icon" aria-hidden="true"><use href="#icon-plus"></use></svg>').addClass("button--icon text-replace white").attr("aria-label",this.blockDef.meta.strings.ADD_COLUMN).addClass("button--icon text-replace white").attr("aria-label",this.blockDef.meta.strings.ADD_COLUMN).attr("title",this.blockDef.meta.strings.ADD_COLUMN),n&&n.addInitialRow&&0===this.tbody.children.length&&this.insertRow(0),s}deleteColumn(t){this.columns[t].deletedInput.value="1";const e=this.thead.children[0],n=e.children;e.removeChild(n[t+1]),Array.from(this.tbody.children).forEach(((e,n)=>{const i=e.children;e.removeChild(i[t+1]),this.rows[n].blocks.splice(t,1)})),this.columns.splice(t,1),(0,o.y)(t,this.columns.length).forEach((t=>{this.columns[t].position-=1,this.columns[t].positionInput.value=this.columns[t].position})),0===this.columns.length&&this.clear()}insertRow(t,e){const n=document.createElement("tr"),s={blocks:[],position:t,id:this.rowCountIncludingDeleted};if(t<this.rows.length){const e=this.tbody.children[t];this.tbody.insertBefore(n,e)}else this.tbody.appendChild(n);this.rows.splice(t,0,s),this.rowCountIncludingDeleted+=1,this.rowCountInput.value=this.rowCountIncludingDeleted;const l=document.createElement("td");l.className="control-cell",n.appendChild(l);const a=$(`<button type="button"\n class="button button-secondary button-small button--icon text-replace prepend-row"\n aria-label="${(0,i.Z)(this.blockDef.meta.strings.INSERT_ROW)}"\n title="${(0,i.Z)(this.blockDef.meta.strings.INSERT_ROW)}">\n <svg class="icon icon-plus icon" aria-hidden="true"><use href="#icon-plus"></use></svg>\n </button>`);$(l).append(a),a.on("click",(()=>{this.insertRow(s.position)})),this.columns.forEach(((t,i)=>{let o;o=e?e[i]:this.blockDef.childBlockDefaultStates[t.blockDef.name];const l=document.createElement("td");n.appendChild(l),s.blocks[i]=this.initCell(l,t,s,o)}));const d=document.createElement("td");d.className="control-cell",n.appendChild(d),s.positionInput=document.createElement("input"),s.positionInput.type="hidden",s.positionInput.name=this.prefix+"-row-"+s.id+"-order",s.positionInput.value=s.position,d.appendChild(s.positionInput);const u=$(`<button type="button"\n class="button button-secondary button-small button--icon text-replace no delete-row"\n aria-label="${(0,i.Z)(this.blockDef.meta.strings.DELETE_ROW)}"\n title="${(0,i.Z)(this.blockDef.meta.strings.DELETE_ROW)}">\n <svg class="icon icon-bin icon" aria-hidden="true"><use href="#icon-bin"></use></svg>\n </button>`);return $(d).append(u),u.on("click",(()=>{this.deleteRow(s.position)})),s.deletedInput=document.createElement("input"),s.deletedInput.type="hidden",s.deletedInput.name=this.prefix+"-row-"+s.id+"-deleted",s.deletedInput.value="",this.deletedFieldsContainer.appendChild(s.deletedInput),(0,o.y)(t+1,this.rows.length).forEach((t=>{this.rows[t].position+=1,this.rows[t].positionInput.value=this.rows[t].position})),s}deleteRow(t){this.rows[t].deletedInput.value="1";const e=this.tbody.children[t];this.tbody.removeChild(e),this.rows.splice(t,1),(0,o.y)(t,this.rows.length).forEach((t=>{this.rows[t].position-=1,this.rows[t].positionInput.value=this.rows[t].position}))}initCell(t,e,n,i){const o=document.createElement("div");t.appendChild(o);const s=this.prefix+"-cell-"+n.id+"-"+e.id;return e.blockDef.render(o,s,i,null)}setState(t){this.clear(),t&&(t.columns.forEach(((t,e)=>{const n=this.childBlockDefsByName[t.type];this.insertColumn(e,n).headingInput.value=t.heading})),t.rows.forEach(((t,e)=>{this.insertRow(e,t.values)})),this.setCaption(t.caption))}setError(t){if(!t)return;const e=this.container[0];if((0,s.$)(e),t.messages&&(0,s.U)(e,t.messages),t.blockErrors)for(const[e,n]of Object.entries(t.blockErrors))for(const[t,i]of Object.entries(n))this.rows[e].blocks[t].setError(i)}getState(){return{columns:this.getColumnStates(),rows:this.rows.map((t=>({values:t.blocks.map((t=>t.getState()))}))),caption:this.caption}}getDuplicatedState(){return{columns:this.getColumnStates(),rows:this.rows.map((t=>({values:t.blocks.map((t=>void 0===t.getDuplicatedState?t.getState():t.getDuplicatedState()))})))}}getValue(){return{columns:this.getColumnStates(),rows:this.rows.map((t=>({values:t.blocks.map((t=>t.getValue()))}))),caption:this.caption}}getColumnStates(){return this.columns.map((t=>({type:t.blockDef.name,heading:t.headingInput.value})))}getTextLabel(t){const e=t&&t.maxLength;let n="";for(const t of this.rows)for(const i of t.blocks)if(i.getTextLabel){const t=i.getTextLabel({maxLength:e});if(t)if(n){const i=n+", "+t;if(e&&i.length>e-1)return n.endsWith("…")||(n+="…"),n;n=i}else n=t}return n}focus(t){this.columns.length?this.rows.length?this.rows[0].blocks[0].focus(t):this.addRowButton.focus():this.appendColumnButton.focus()}}window.telepath.register("wagtail.contrib.typed_table_block.blocks.TypedTableBlock",class{constructor(t,e,n,i){this.name=t,this.childBlockDefs=e,this.childBlockDefaultStates=n,this.meta=i}render(t,e,n,i){return new l(this,t,e,n,i)}})}},n={};function i(t){var o=n[t];if(void 0!==o)return o.exports;var s=n[t]={exports:{}};return e[t](s,s.exports,i),s.exports}i.m=e,t=[],i.O=(e,n,o,s)=>{if(!n){var l=1/0;for(c=0;c<t.length;c++){for(var[n,o,s]=t[c],a=!0,d=0;d<n.length;d++)(!1&s||l>=s)&&Object.keys(i.O).every((t=>i.O[t](n[d])))?n.splice(d--,1):(a=!1,s<l&&(l=s));if(a){t.splice(c--,1);var u=o();void 0!==u&&(e=u)}}return e}s=s||0;for(var c=t.length;c>0&&t[c-1][2]>s;c--)t[c]=t[c-1];t[c]=[n,o,s]},i.n=t=>{var e=t&&t.__esModule?()=>t.default:()=>t;return i.d(e,{a:e}),e},i.d=(t,e)=>{for(var n in e)i.o(e,n)&&!i.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:e[n]})},i.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(t){if("object"==typeof window)return window}}(),i.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),i.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},i.j=702,(()=>{var t={702:0};i.O.j=e=>0===t[e];var e=(e,n)=>{var o,s,[l,a,d]=n,u=0;if(l.some((e=>0!==t[e]))){for(o in a)i.o(a,o)&&(i.m[o]=a[o]);if(d)var c=d(i)}for(e&&e(n);u<l.length;u++)s=l[u],i.o(t,s)&&t[s]&&t[s][0](),t[s]=0;return i.O(c)},n=globalThis.webpackChunkwagtail=globalThis.webpackChunkwagtail||[];n.forEach(e.bind(null,0)),n.push=e.bind(null,n.push.bind(n))})();var o=i.O(void 0,[321],(()=>i(7595)));o=i.O(o)})();
|
|
1
|
+
(()=>{"use strict";var t,e={7595:(t,e,n)=>{var i=n(4327),o=n(9675),s=n(4545);class l{constructor(t,e,n,o,s){this.blockDef=t,this.type=t.name,this.caption="",this.columns=[],this.rows=[],this.columnCountIncludingDeleted=0,this.rowCountIncludingDeleted=0,this.prefix=n,this.childBlockDefsByName={},this.blockDef.childBlockDefs.forEach((t=>{this.childBlockDefsByName[t.name]=t}));const l=this.blockDef.meta.strings,a=`${(0,i.Z)(n)}-caption`,d=$(`\n <div class="typed-table-block ${(0,i.Z)(this.blockDef.meta.classname||"")}">\n <div class="w-field__wrapper" data-field-wrapper>\n <label class="w-field__label" for="${a}">\n ${l.CAPTION}\n </label>\n <div class="w-field w-field--char_field w-field--text_input" data-field>\n <div class="w-field__help" data-field-help>\n <div class="help">\n ${l.CAPTION_HELP_TEXT}\n </div>\n </div>\n <div class="w-field__input" data-field-input>\n <input type="text" id="${a}" name="${a}" value="" />\n <span></span>\n </div>\n </div>\n </div>\n <input type="hidden" name="${(0,i.Z)(n)}-column-count" data-column-count value="0">\n <input type="hidden" name="${(0,i.Z)(n)}-row-count" data-row-count value="0">\n <div data-deleted-fields></div>\n <div class="typed-table-block__wrapper">\n <table>\n <thead>\n <tr>\n <th aria-hidden="true"></th>\n <th class="control-cell">\n <button type="button" class="button button-small button-secondary append-column" aria-expanded="false" data-append-column>\n ${(0,i.Z)(l.ADD_COLUMN)}\n </button>\n </th>\n </tr>\n </thead>\n <tbody>\n </tbody>\n <tfoot>\n <tr>\n <td class="control-cell">\n <button\n type="button"\n class="button button-small button-secondary button--icon text-replace prepend-row"\n data-add-row\n aria-label="${(0,i.Z)(l.ADD_ROW)}"\n title="${(0,i.Z)(l.ADD_ROW)}"\n >\n <svg class="icon icon-plus icon" aria-hidden="true">\n <use href="#icon-plus"></use>\n </svg>\n </button></td>\n </tr>\n </tfoot>\n </table>\n </div>\n </div>\n `);$(e).replaceWith(d),this.container=d,this.captionInput=d.find(`#${a}`).get(0),this.thead=d.find("table > thead").get(0),this.tbody=d.find("table > tbody").get(0),this.columnCountInput=d.find("input[data-column-count]").get(0),this.rowCountInput=d.find("input[data-row-count]").get(0),this.deletedFieldsContainer=d.find("[data-deleted-fields]").get(0),this.appendColumnButton=d.find("button[data-append-column]"),this.addRowButton=d.find("button[data-add-row]"),this.addRowButton.hide(),this.blockDef.meta.helpText&&d.append(`\n <div class="c-sf-help">\n <div class="help">\n ${this.blockDef.meta.helpText}\n </div>\n </div>\n `),this.addColumnCallback=null,this.addColumnMenu=$('<ul class="add-column-menu"></ul>'),this.blockDef.childBlockDefs.forEach((t=>{const e=$('<button type="button" class="button button-small"></button>').text(t.meta.label);e.on("click",(()=>{this.addColumnCallback&&this.addColumnCallback(t),this.hideAddColumnMenu(this.addColumnMenuTrigger)}));const n=$("<li></li>").append(e);this.addColumnMenu.append(n)})),this.addColumnMenuTrigger=null,this.appendColumnButton.on("click",(()=>{this.toggleAddColumnMenu(this.appendColumnButton,(t=>{this.insertColumn(this.columns.length,t,{addInitialRow:!0})}))})),this.addRowButton.on("click",(()=>{this.insertRow(this.rows.length)})),this.setState(o),s&&this.setError(s)}showAddColumnMenu(t,e){this.addColumnMenuTrigger?.attr("aria-expanded","false"),this.addColumnMenuTrigger=t,t.after(this.addColumnMenu),t.attr("aria-expanded","true"),this.addColumnMenu.show(),this.addColumnCallback=e}hideAddColumnMenu(t){t.attr("aria-expanded","false"),this.addColumnMenu.hide(),this.addColumnMenuTrigger=null}toggleAddColumnMenu(t,e){this.addColumnMenuTrigger===t?this.hideAddColumnMenu(t):this.showAddColumnMenu(t,e)}clear(){this.setCaption(""),this.columns=[],this.rows=[],this.columnCountIncludingDeleted=0,this.columnCountInput.value=0,this.rowCountIncludingDeleted=0,this.rowCountInput.value=0,this.deletedFieldsContainer.replaceChildren();const t=this.thead.children[0];t.replaceChildren(t.firstElementChild,t.lastElementChild),this.appendColumnButton.text(this.blockDef.meta.strings.ADD_COLUMN).removeClass("button--icon text-replace white").removeAttr("aria-label").removeAttr("title"),this.tbody.replaceChildren(),this.addRowButton.hide()}setCaption(t){this.caption=t,this.captionInput.value=t}insertColumn(t,e,n){const s={blockDef:e,position:t,id:this.columnCountIncludingDeleted};this.columnCountIncludingDeleted+=1,(0,o.y)(t,this.columns.length).forEach((t=>{this.columns[t].position+=1,this.columns[t].positionInput.value=this.columns[t].position})),this.columns.splice(t,0,s),this.columnCountInput.value=this.columnCountIncludingDeleted;const l=this.thead.children[0],a=l.children,d=document.createElement("th");l.insertBefore(d,a[t+1]),s.typeInput=document.createElement("input"),s.typeInput.type="hidden",s.typeInput.name=this.prefix+"-column-"+s.id+"-type",s.typeInput.value=e.name,d.appendChild(s.typeInput),s.positionInput=document.createElement("input"),s.positionInput.type="hidden",s.positionInput.name=this.prefix+"-column-"+s.id+"-order",s.positionInput.value=t,d.appendChild(s.positionInput),s.deletedInput=document.createElement("input"),s.deletedInput.type="hidden",s.deletedInput.name=this.prefix+"-column-"+s.id+"-deleted",s.deletedInput.value="",this.deletedFieldsContainer.appendChild(s.deletedInput);const u=$(`<button type="button"\n class="button button-secondary button-small button--icon text-replace prepend-column"\n aria-label="${(0,i.Z)(this.blockDef.meta.strings.INSERT_COLUMN)}"\n aria-expanded="false"\n title="${(0,i.Z)(this.blockDef.meta.strings.INSERT_COLUMN)}">\n <svg class="icon icon-plus icon" aria-hidden="true"><use href="#icon-plus"></use></svg>\n </button>`);$(d).append(u),u.on("click",(()=>{this.toggleAddColumnMenu(u,(t=>{this.insertColumn(s.position,t,{addInitialRow:!0})}))})),s.headingInput=document.createElement("input"),s.headingInput.type="text",s.headingInput.name=this.prefix+"-column-"+s.id+"-heading",s.headingInput.className="column-heading",s.headingInput.placeholder=this.blockDef.meta.strings.COLUMN_HEADING,d.appendChild(s.headingInput);const c=$(`<button type="button"\n class="button button-secondary button-small button--icon text-replace no delete-column"\n aria-label="${(0,i.Z)(this.blockDef.meta.strings.DELETE_COLUMN)}"\n title="${(0,i.Z)(this.blockDef.meta.strings.DELETE_COLUMN)}">\n <svg class="icon icon-bin icon" aria-hidden="true"><use href="#icon-bin"></use></svg>\n </button>`);$(d).append(c),c.on("click",(()=>{this.deleteColumn(s.position)}));const r=this.blockDef.childBlockDefaultStates[e.name];return Array.from(this.tbody.children).forEach(((e,n)=>{const i=this.rows[n],o=e.children,l=document.createElement("td");e.insertBefore(l,o[t+1]);const a=this.initCell(l,s,i,r);i.blocks.splice(t,0,a)})),this.addRowButton.show(),this.appendColumnButton.html('<svg class="icon icon-plus icon" aria-hidden="true"><use href="#icon-plus"></use></svg>').addClass("button--icon text-replace white").attr("aria-label",this.blockDef.meta.strings.ADD_COLUMN).attr("aria-expanded","false").attr("title",this.blockDef.meta.strings.ADD_COLUMN),n&&n.addInitialRow&&0===this.tbody.children.length&&this.insertRow(0),s}deleteColumn(t){this.columns[t].deletedInput.value="1";const e=this.thead.children[0],n=e.children;e.removeChild(n[t+1]),Array.from(this.tbody.children).forEach(((e,n)=>{const i=e.children;e.removeChild(i[t+1]),this.rows[n].blocks.splice(t,1)})),this.columns.splice(t,1),(0,o.y)(t,this.columns.length).forEach((t=>{this.columns[t].position-=1,this.columns[t].positionInput.value=this.columns[t].position})),0===this.columns.length&&this.clear()}insertRow(t,e){const n=document.createElement("tr"),s={blocks:[],position:t,id:this.rowCountIncludingDeleted};if(t<this.rows.length){const e=this.tbody.children[t];this.tbody.insertBefore(n,e)}else this.tbody.appendChild(n);this.rows.splice(t,0,s),this.rowCountIncludingDeleted+=1,this.rowCountInput.value=this.rowCountIncludingDeleted;const l=document.createElement("td");l.className="control-cell",n.appendChild(l);const a=$(`<button type="button"\n class="button button-secondary button-small button--icon text-replace prepend-row"\n aria-label="${(0,i.Z)(this.blockDef.meta.strings.INSERT_ROW)}"\n title="${(0,i.Z)(this.blockDef.meta.strings.INSERT_ROW)}">\n <svg class="icon icon-plus icon" aria-hidden="true"><use href="#icon-plus"></use></svg>\n </button>`);$(l).append(a),a.on("click",(()=>{this.insertRow(s.position)})),this.columns.forEach(((t,i)=>{let o;o=e?e[i]:this.blockDef.childBlockDefaultStates[t.blockDef.name];const l=document.createElement("td");n.appendChild(l),s.blocks[i]=this.initCell(l,t,s,o)}));const d=document.createElement("td");d.className="control-cell",n.appendChild(d),s.positionInput=document.createElement("input"),s.positionInput.type="hidden",s.positionInput.name=this.prefix+"-row-"+s.id+"-order",s.positionInput.value=s.position,d.appendChild(s.positionInput);const u=$(`<button type="button"\n class="button button-secondary button-small button--icon text-replace no delete-row"\n aria-label="${(0,i.Z)(this.blockDef.meta.strings.DELETE_ROW)}"\n title="${(0,i.Z)(this.blockDef.meta.strings.DELETE_ROW)}">\n <svg class="icon icon-bin icon" aria-hidden="true"><use href="#icon-bin"></use></svg>\n </button>`);return $(d).append(u),u.on("click",(()=>{this.deleteRow(s.position)})),s.deletedInput=document.createElement("input"),s.deletedInput.type="hidden",s.deletedInput.name=this.prefix+"-row-"+s.id+"-deleted",s.deletedInput.value="",this.deletedFieldsContainer.appendChild(s.deletedInput),(0,o.y)(t+1,this.rows.length).forEach((t=>{this.rows[t].position+=1,this.rows[t].positionInput.value=this.rows[t].position})),s}deleteRow(t){this.rows[t].deletedInput.value="1";const e=this.tbody.children[t];this.tbody.removeChild(e),this.rows.splice(t,1),(0,o.y)(t,this.rows.length).forEach((t=>{this.rows[t].position-=1,this.rows[t].positionInput.value=this.rows[t].position}))}initCell(t,e,n,i){const o=document.createElement("div");t.appendChild(o);const s=this.prefix+"-cell-"+n.id+"-"+e.id;return e.blockDef.render(o,s,i,null)}setState(t){this.clear(),t&&(t.columns.forEach(((t,e)=>{const n=this.childBlockDefsByName[t.type];this.insertColumn(e,n).headingInput.value=t.heading})),t.rows.forEach(((t,e)=>{this.insertRow(e,t.values)})),this.setCaption(t.caption))}setError(t){if(!t)return;const e=this.container[0];if((0,s.$)(e),t.messages&&(0,s.U)(e,t.messages),t.blockErrors)for(const[e,n]of Object.entries(t.blockErrors))for(const[t,i]of Object.entries(n))this.rows[e].blocks[t].setError(i)}getState(){return{columns:this.getColumnStates(),rows:this.rows.map((t=>({values:t.blocks.map((t=>t.getState()))}))),caption:this.caption}}getDuplicatedState(){return{columns:this.getColumnStates(),rows:this.rows.map((t=>({values:t.blocks.map((t=>void 0===t.getDuplicatedState?t.getState():t.getDuplicatedState()))})))}}getValue(){return{columns:this.getColumnStates(),rows:this.rows.map((t=>({values:t.blocks.map((t=>t.getValue()))}))),caption:this.caption}}getColumnStates(){return this.columns.map((t=>({type:t.blockDef.name,heading:t.headingInput.value})))}getTextLabel(t){const e=t&&t.maxLength;let n="";for(const t of this.rows)for(const i of t.blocks)if(i.getTextLabel){const t=i.getTextLabel({maxLength:e});if(t)if(n){const i=n+", "+t;if(e&&i.length>e-1)return n.endsWith("…")||(n+="…"),n;n=i}else n=t}return n}focus(t){this.columns.length?this.rows.length?this.rows[0].blocks[0].focus(t):this.addRowButton.focus():this.appendColumnButton.focus()}}window.telepath.register("wagtail.contrib.typed_table_block.blocks.TypedTableBlock",class{constructor(t,e,n,i){this.name=t,this.childBlockDefs=e,this.childBlockDefaultStates=n,this.meta=i}render(t,e,n,i){return new l(this,t,e,n,i)}})}},n={};function i(t){var o=n[t];if(void 0!==o)return o.exports;var s=n[t]={exports:{}};return e[t](s,s.exports,i),s.exports}i.m=e,t=[],i.O=(e,n,o,s)=>{if(!n){var l=1/0;for(c=0;c<t.length;c++){for(var[n,o,s]=t[c],a=!0,d=0;d<n.length;d++)(!1&s||l>=s)&&Object.keys(i.O).every((t=>i.O[t](n[d])))?n.splice(d--,1):(a=!1,s<l&&(l=s));if(a){t.splice(c--,1);var u=o();void 0!==u&&(e=u)}}return e}s=s||0;for(var c=t.length;c>0&&t[c-1][2]>s;c--)t[c]=t[c-1];t[c]=[n,o,s]},i.n=t=>{var e=t&&t.__esModule?()=>t.default:()=>t;return i.d(e,{a:e}),e},i.d=(t,e)=>{for(var n in e)i.o(e,n)&&!i.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:e[n]})},i.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(t){if("object"==typeof window)return window}}(),i.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),i.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},i.j=702,(()=>{var t={702:0};i.O.j=e=>0===t[e];var e=(e,n)=>{var o,s,[l,a,d]=n,u=0;if(l.some((e=>0!==t[e]))){for(o in a)i.o(a,o)&&(i.m[o]=a[o]);if(d)var c=d(i)}for(e&&e(n);u<l.length;u++)s=l[u],i.o(t,s)&&t[s]&&t[s][0](),t[s]=0;return i.O(c)},n=globalThis.webpackChunkwagtail=globalThis.webpackChunkwagtail||[];n.forEach(e.bind(null,0)),n.push=e.bind(null,n.push.bind(n))})();var o=i.O(void 0,[321],(()=>i(7595)));o=i.O(o)})();
|
|
@@ -9,6 +9,7 @@ from wagtail.blocks.struct_block import StructBlockValidationError
|
|
|
9
9
|
from wagtail.contrib.typed_table_block.blocks import (
|
|
10
10
|
TypedTable,
|
|
11
11
|
TypedTableBlock,
|
|
12
|
+
TypedTableBlockAdapter,
|
|
12
13
|
TypedTableBlockValidationError,
|
|
13
14
|
)
|
|
14
15
|
|
|
@@ -223,6 +224,38 @@ class TestTableBlock(TestCase):
|
|
|
223
224
|
# rendering should use the block renderings of the child blocks ('FR' not 'fr')
|
|
224
225
|
self.assertIn("<td>FR</td>", html)
|
|
225
226
|
|
|
227
|
+
def test_adapt(self):
|
|
228
|
+
block = TypedTableBlock(description="A table of countries and their food")
|
|
229
|
+
|
|
230
|
+
block.set_name("test_typedtableblock")
|
|
231
|
+
js_args = TypedTableBlockAdapter().js_args(block)
|
|
232
|
+
|
|
233
|
+
self.assertEqual(js_args[0], "test_typedtableblock")
|
|
234
|
+
self.assertEqual(
|
|
235
|
+
js_args[-1],
|
|
236
|
+
{
|
|
237
|
+
"label": "Test typedtableblock",
|
|
238
|
+
"description": "A table of countries and their food",
|
|
239
|
+
"required": False,
|
|
240
|
+
"icon": "table",
|
|
241
|
+
"blockDefId": block.definition_prefix,
|
|
242
|
+
"isPreviewable": block.is_previewable,
|
|
243
|
+
"strings": {
|
|
244
|
+
"CAPTION": "Caption",
|
|
245
|
+
"CAPTION_HELP_TEXT": (
|
|
246
|
+
"A heading that identifies the overall topic of the table, and is useful for screen reader users."
|
|
247
|
+
),
|
|
248
|
+
"ADD_COLUMN": "Add column",
|
|
249
|
+
"ADD_ROW": "Add row",
|
|
250
|
+
"COLUMN_HEADING": "Column heading",
|
|
251
|
+
"INSERT_COLUMN": "Insert column",
|
|
252
|
+
"DELETE_COLUMN": "Delete column",
|
|
253
|
+
"INSERT_ROW": "Insert row",
|
|
254
|
+
"DELETE_ROW": "Delete row",
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
)
|
|
258
|
+
|
|
226
259
|
def test_validation_error_as_json(self):
|
|
227
260
|
error = TypedTableBlockValidationError(
|
|
228
261
|
cell_errors={
|
|
@@ -8,7 +8,7 @@ msgid ""
|
|
|
8
8
|
msgstr ""
|
|
9
9
|
"Project-Id-Version: PACKAGE VERSION\n"
|
|
10
10
|
"Report-Msgid-Bugs-To: \n"
|
|
11
|
-
"POT-Creation-Date:
|
|
11
|
+
"POT-Creation-Date: 2025-01-20 17:59+0000\n"
|
|
12
12
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
|
13
13
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
|
14
14
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
|
@@ -71,11 +71,11 @@ msgstr ""
|
|
|
71
71
|
msgid "tags"
|
|
72
72
|
msgstr ""
|
|
73
73
|
|
|
74
|
-
#: models.py:
|
|
74
|
+
#: models.py:209
|
|
75
75
|
msgid "document"
|
|
76
76
|
msgstr ""
|
|
77
77
|
|
|
78
|
-
#: models.py:
|
|
78
|
+
#: models.py:210
|
|
79
79
|
msgid "documents"
|
|
80
80
|
msgstr ""
|
|
81
81
|
|
|
@@ -151,14 +151,14 @@ msgid "Delete documents"
|
|
|
151
151
|
msgstr ""
|
|
152
152
|
|
|
153
153
|
#: templates/wagtaildocs/bulk_actions/confirm_bulk_delete.html:17
|
|
154
|
-
#: views/documents.py:
|
|
154
|
+
#: views/documents.py:281
|
|
155
155
|
msgid "Are you sure you want to delete this document?"
|
|
156
156
|
msgid_plural "Are you sure you want to delete these documents?"
|
|
157
157
|
msgstr[0] ""
|
|
158
158
|
msgstr[1] ""
|
|
159
159
|
|
|
160
160
|
#: templates/wagtaildocs/bulk_actions/confirm_bulk_delete.html:28
|
|
161
|
-
#: templates/wagtaildocs/documents/edit.html:
|
|
161
|
+
#: templates/wagtaildocs/documents/edit.html:27
|
|
162
162
|
#, python-format
|
|
163
163
|
msgid "Used %(usage_count)s time"
|
|
164
164
|
msgid_plural "Used %(usage_count)s times"
|
|
@@ -210,11 +210,11 @@ msgstr ""
|
|
|
210
210
|
msgid "Add a document"
|
|
211
211
|
msgstr ""
|
|
212
212
|
|
|
213
|
-
#: templates/wagtaildocs/documents/add.html:45 views/chooser.py:
|
|
213
|
+
#: templates/wagtaildocs/documents/add.html:45 views/chooser.py:187
|
|
214
214
|
msgid "Uploading…"
|
|
215
215
|
msgstr ""
|
|
216
216
|
|
|
217
|
-
#: templates/wagtaildocs/documents/add.html:48 views/chooser.py:
|
|
217
|
+
#: templates/wagtaildocs/documents/add.html:48 views/chooser.py:186
|
|
218
218
|
msgid "Upload"
|
|
219
219
|
msgstr ""
|
|
220
220
|
|
|
@@ -266,30 +266,30 @@ msgstr[1] ""
|
|
|
266
266
|
msgid "Add multiple documents"
|
|
267
267
|
msgstr ""
|
|
268
268
|
|
|
269
|
-
#: templates/wagtaildocs/multiple/add.html:
|
|
269
|
+
#: templates/wagtaildocs/multiple/add.html:20
|
|
270
270
|
msgid "Drag and drop documents into this area to upload immediately."
|
|
271
271
|
msgstr ""
|
|
272
272
|
|
|
273
|
-
#: templates/wagtaildocs/multiple/add.html:
|
|
273
|
+
#: templates/wagtaildocs/multiple/add.html:25
|
|
274
274
|
msgid "Or choose from your computer"
|
|
275
275
|
msgstr ""
|
|
276
276
|
|
|
277
|
-
#: templates/wagtaildocs/multiple/add.html:
|
|
277
|
+
#: templates/wagtaildocs/multiple/add.html:37
|
|
278
278
|
msgid "Add to collection:"
|
|
279
279
|
msgstr ""
|
|
280
280
|
|
|
281
|
-
#: templates/wagtaildocs/multiple/add.html:
|
|
281
|
+
#: templates/wagtaildocs/multiple/add.html:67
|
|
282
282
|
msgid ""
|
|
283
283
|
"Upload successful. Please update this document with a more appropriate "
|
|
284
284
|
"title, if necessary. You may also delete the document completely if the "
|
|
285
285
|
"upload wasn't required."
|
|
286
286
|
msgstr ""
|
|
287
287
|
|
|
288
|
-
#: templates/wagtaildocs/multiple/add.html:
|
|
288
|
+
#: templates/wagtaildocs/multiple/add.html:68
|
|
289
289
|
msgid "Sorry, upload failed."
|
|
290
290
|
msgstr ""
|
|
291
291
|
|
|
292
|
-
#: templates/wagtaildocs/multiple/add.html:
|
|
292
|
+
#: templates/wagtaildocs/multiple/add.html:69
|
|
293
293
|
msgid "Document updated."
|
|
294
294
|
msgstr ""
|
|
295
295
|
|
|
@@ -340,7 +340,7 @@ msgid_plural ""
|
|
|
340
340
|
msgstr[0] ""
|
|
341
341
|
msgstr[1] ""
|
|
342
342
|
|
|
343
|
-
#: views/bulk_actions/delete.py:8 views/documents.py:
|
|
343
|
+
#: views/bulk_actions/delete.py:8 views/documents.py:247
|
|
344
344
|
msgid "Delete"
|
|
345
345
|
msgstr ""
|
|
346
346
|
|
|
@@ -363,19 +363,19 @@ msgstr ""
|
|
|
363
363
|
msgid "Created"
|
|
364
364
|
msgstr ""
|
|
365
365
|
|
|
366
|
-
#: views/chooser.py:
|
|
366
|
+
#: views/chooser.py:185
|
|
367
367
|
msgid "Choose a document"
|
|
368
368
|
msgstr ""
|
|
369
369
|
|
|
370
|
-
#: views/chooser.py:
|
|
370
|
+
#: views/chooser.py:188
|
|
371
371
|
msgid "Choose another document"
|
|
372
372
|
msgstr ""
|
|
373
373
|
|
|
374
|
-
#: views/chooser.py:
|
|
374
|
+
#: views/chooser.py:189
|
|
375
375
|
msgid "Edit this document"
|
|
376
376
|
msgstr ""
|
|
377
377
|
|
|
378
|
-
#: views/documents.py:63 wagtail_hooks.py:
|
|
378
|
+
#: views/documents.py:63 wagtail_hooks.py:62 wagtail_hooks.py:135
|
|
379
379
|
msgid "Documents"
|
|
380
380
|
msgstr ""
|
|
381
381
|
|
|
@@ -387,30 +387,30 @@ msgstr ""
|
|
|
387
387
|
msgid "The document could not be created due to errors."
|
|
388
388
|
msgstr ""
|
|
389
389
|
|
|
390
|
-
#: views/documents.py:
|
|
390
|
+
#: views/documents.py:184
|
|
391
391
|
#, python-format
|
|
392
392
|
msgid "Document '%(document_title)s' added."
|
|
393
393
|
msgstr ""
|
|
394
394
|
|
|
395
|
-
#: views/documents.py:
|
|
395
|
+
#: views/documents.py:192
|
|
396
396
|
msgid "The document could not be saved due to errors."
|
|
397
397
|
msgstr ""
|
|
398
398
|
|
|
399
|
-
#: views/documents.py:
|
|
399
|
+
#: views/documents.py:221
|
|
400
400
|
#, python-format
|
|
401
401
|
msgid "Document '%(document_title)s' updated"
|
|
402
402
|
msgstr ""
|
|
403
403
|
|
|
404
|
-
#: views/documents.py:
|
|
404
|
+
#: views/documents.py:245
|
|
405
405
|
msgid ""
|
|
406
406
|
"The file could not be found. Please change the source or delete the document"
|
|
407
407
|
msgstr ""
|
|
408
408
|
|
|
409
|
-
#: views/documents.py:
|
|
409
|
+
#: views/documents.py:269
|
|
410
410
|
msgid "Delete document"
|
|
411
411
|
msgstr ""
|
|
412
412
|
|
|
413
|
-
#: views/documents.py:
|
|
413
|
+
#: views/documents.py:287
|
|
414
414
|
#, python-format
|
|
415
415
|
msgid "Document '%(document_title)s' deleted."
|
|
416
416
|
msgstr ""
|
|
@@ -419,11 +419,11 @@ msgstr ""
|
|
|
419
419
|
msgid "Add documents"
|
|
420
420
|
msgstr ""
|
|
421
421
|
|
|
422
|
-
#: wagtail_hooks.py:
|
|
422
|
+
#: wagtail_hooks.py:81
|
|
423
423
|
msgid "Document"
|
|
424
424
|
msgstr ""
|
|
425
425
|
|
|
426
|
-
#: wagtail_hooks.py:
|
|
426
|
+
#: wagtail_hooks.py:156
|
|
427
427
|
#, python-format
|
|
428
428
|
msgid "%(count)s document"
|
|
429
429
|
msgid_plural "%(count)s documents"
|
wagtail/documents/models.py
CHANGED
|
@@ -2,11 +2,15 @@ from django.db import transaction
|
|
|
2
2
|
from django.db.models.signals import post_delete
|
|
3
3
|
|
|
4
4
|
from wagtail.documents import get_document_model
|
|
5
|
+
from wagtail.tasks import delete_file_from_storage_task
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
def post_delete_file_cleanup(instance, **kwargs):
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
transaction.on_commit(
|
|
10
|
+
lambda: delete_file_from_storage_task.enqueue(
|
|
11
|
+
instance.file.storage.deconstruct(), instance.file.name
|
|
12
|
+
)
|
|
13
|
+
)
|
|
10
14
|
|
|
11
15
|
|
|
12
16
|
def register_signal_handlers():
|
|
@@ -1 +1 @@
|
|
|
1
|
-
$((function(){$(
|
|
1
|
+
$((function(){$("#fileupload").fileupload({dataType:"html",sequentialUploads:!0,dropZone:$(".drop-zone"),add:function(e,a){var t=$(this),s=t.data("blueimp-fileupload")||t.data("fileupload"),o=$($("#upload-list-item").html()).addClass("upload-uploading"),l=s.options;$("#upload-list").append(o),a.context=o,a.process((function(){return t.fileupload("process",a)})).always((function(){a.context.removeClass("processing"),a.context.find(".left").each((function(e,t){$(t).append(escapeHtml(a.files[e].name))}))})).done((function(){a.context.find(".start").prop("disabled",!1),!1!==s._trigger("added",e,a)&&(l.autoUpload||a.autoUpload)&&!1!==a.autoUpload&&a.submit()})).fail((function(){a.files.error&&a.context.each((function(e){var t=a.files[e].error;t&&$(this).find(".error_messages").text(t)}))}))},processfail:function(e,a){$(a.context).removeClass("upload-uploading").addClass("upload-failure")},progress:function(e,a){if(e.isDefaultPrevented())return!1;var t=Math.floor(a.loaded/a.total*100);a.context.each((function(){$(this).find(".progress").addClass("active").attr("aria-valuenow",t).find(".bar").css("width",t+"%").html(t+"%")}))},progressall:function(e,a){var t=parseInt(a.loaded/a.total*100,10);$("#overall-progress").addClass("active").attr("aria-valuenow",t).find(".bar").css("width",t+"%").html(t+"%"),t>=100&&$("#overall-progress").removeClass("active").find(".bar").css("width","0%")},formData:function(e){var a=this.files[0].name,t={title:a.replace(/\.[^.]+$/,"")};return e.get(0).dispatchEvent(new CustomEvent("wagtail:documents-upload",{bubbles:!0,cancelable:!0,detail:{data:t,filename:a,maxTitleLength:this.maxTitleLength}}))?e.serializeArray().concat({name:"title",value:t.title}):e.serializeArray()},done:function(e,a){var t=$(a.context),s=JSON.parse(a.result);s.success?(t.addClass("upload-success"),$(".right",t).append(s.form)):(t.addClass("upload-failure"),$(".right .error_messages",t).append(s.error_message))},fail:function(e,a){$(a.context).addClass("upload-failure")},always:function(e,a){$(a.context).removeClass("upload-uploading").addClass("upload-complete")}}),$("#upload-list").on("submit","form",(function(e){var a=$(this),t=new FormData(this),s=a.closest("#upload-list > li");e.preventDefault(),$.ajax({contentType:!1,data:t,processData:!1,type:"POST",url:this.action}).done((function(e){if(e.success){var t=$(".status-msg.update-success").first().text();document.dispatchEvent(new CustomEvent("w-messages:add",{detail:{clear:!0,text:t,type:"success"}})),s.slideUp((function(){$(this).remove()}))}else a.replaceWith(e.form)}))})),$("#upload-list").on("click",".delete",(function(e){var a=$(this).closest("form"),t=a.closest("#upload-list > li");e.preventDefault();var s=$('input[name="csrfmiddlewaretoken"]',a).val();$.post(this.href,{csrfmiddlewaretoken:s},(function(e){e.success&&t.slideUp((function(){$(this).remove()}))}))}))}));
|
|
@@ -24,9 +24,7 @@
|
|
|
24
24
|
|
|
25
25
|
<dt>{% trans "Usage" %}</dt>
|
|
26
26
|
<dd>
|
|
27
|
-
{% with usage_count_val
|
|
28
|
-
<a href="{{ document.usage_url }}">{% blocktrans trimmed with usage_count=usage_count_val|intcomma count usage_count_val=usage_count_val %}Used {{ usage_count }} time{% plural %}Used {{ usage_count }} times{% endblocktrans %}</a>
|
|
29
|
-
{% endwith %}
|
|
27
|
+
<a href="{{ document.usage_url }}">{% blocktrans trimmed with usage_count=usage_count_val|intcomma count usage_count_val=usage_count_val %}Used {{ usage_count }} time{% plural %}Used {{ usage_count }} times{% endblocktrans %}</a>
|
|
30
28
|
</dd>
|
|
31
29
|
</dl>
|
|
32
30
|
</div>
|
|
@@ -10,7 +10,13 @@
|
|
|
10
10
|
{% endblock %}
|
|
11
11
|
|
|
12
12
|
{% block main_content %}
|
|
13
|
-
<div
|
|
13
|
+
<div
|
|
14
|
+
class="drop-zone w-mt-8"
|
|
15
|
+
data-controller="w-zone"
|
|
16
|
+
data-action="dragover@document->w-zone#noop:prevent drop@document->w-zone#noop:prevent dragover->w-zone#activate drop->w-zone#deactivate dragleave->w-zone#deactivate dragend->w-zone#deactivate"
|
|
17
|
+
data-w-zone-active-class="hovered"
|
|
18
|
+
data-w-zone-delay-value="10"
|
|
19
|
+
>
|
|
14
20
|
<p>{% trans "Drag and drop documents into this area to upload immediately." %}</p>
|
|
15
21
|
<p>{{ help_text }}</p>
|
|
16
22
|
|
|
@@ -30,6 +30,7 @@ from wagtail.test.testapp.models import (
|
|
|
30
30
|
)
|
|
31
31
|
from wagtail.test.utils import WagtailTestUtils
|
|
32
32
|
from wagtail.test.utils.template_tests import AdminTemplateTestUtils
|
|
33
|
+
from wagtail.test.utils.timestamps import local_datetime
|
|
33
34
|
|
|
34
35
|
|
|
35
36
|
class TestDocumentIndexView(WagtailTestUtils, TestCase):
|
|
@@ -95,7 +96,7 @@ class TestDocumentIndexView(WagtailTestUtils, TestCase):
|
|
|
95
96
|
)
|
|
96
97
|
|
|
97
98
|
def test_ordering(self):
|
|
98
|
-
orderings = ["title", "-created_at"]
|
|
99
|
+
orderings = ["title", "created_at", "-created_at"]
|
|
99
100
|
for ordering in orderings:
|
|
100
101
|
response = self.get({"ordering": ordering})
|
|
101
102
|
self.assertEqual(response.status_code, 200)
|
|
@@ -371,6 +372,39 @@ class TestDocumentIndexViewSearch(WagtailTestUtils, TransactionTestCase):
|
|
|
371
372
|
response = self.get({"tag": "one", "q": "test"})
|
|
372
373
|
self.assertEqual(response.context["page_obj"].paginator.count, 2)
|
|
373
374
|
|
|
375
|
+
def test_search_and_order_by_created_at(self):
|
|
376
|
+
# Create Documents, change their created_at dates after creation as
|
|
377
|
+
# the field has auto_now_add=True
|
|
378
|
+
doc1 = models.Document.objects.create(title="recent good Document")
|
|
379
|
+
doc1.created_at = local_datetime(2024, 1, 1)
|
|
380
|
+
doc1.save()
|
|
381
|
+
|
|
382
|
+
doc2 = models.Document.objects.create(title="latest ok Document")
|
|
383
|
+
doc2.created_at = local_datetime(2025, 1, 1)
|
|
384
|
+
doc2.save()
|
|
385
|
+
|
|
386
|
+
doc3 = models.Document.objects.create(title="oldest good document")
|
|
387
|
+
doc3.created_at = local_datetime(2023, 1, 1)
|
|
388
|
+
doc3.save()
|
|
389
|
+
|
|
390
|
+
cases = [
|
|
391
|
+
("created_at", [doc3, doc1]),
|
|
392
|
+
("-created_at", [doc1, doc3]),
|
|
393
|
+
]
|
|
394
|
+
|
|
395
|
+
for ordering, expected_docs in cases:
|
|
396
|
+
with self.subTest(ordering=ordering):
|
|
397
|
+
response = self.get({"q": "good", "ordering": ordering})
|
|
398
|
+
self.assertEqual(response.status_code, 200)
|
|
399
|
+
self.assertEqual(response.context["query_string"], "good")
|
|
400
|
+
|
|
401
|
+
# Check that the documents are filtered by the search query
|
|
402
|
+
# and are in the correct order
|
|
403
|
+
documents = list(response.context["page_obj"].object_list)
|
|
404
|
+
self.assertEqual(documents, expected_docs)
|
|
405
|
+
self.assertIn("ordering", response.context)
|
|
406
|
+
self.assertEqual(response.context["ordering"], ordering)
|
|
407
|
+
|
|
374
408
|
|
|
375
409
|
class TestDocumentIndexResultsView(WagtailTestUtils, TransactionTestCase):
|
|
376
410
|
def setUp(self):
|
|
@@ -969,7 +1003,8 @@ class TestDocumentDeleteView(WagtailTestUtils, TestCase):
|
|
|
969
1003
|
)
|
|
970
1004
|
|
|
971
1005
|
def test_delete_get_with_protected_reference(self):
|
|
972
|
-
|
|
1006
|
+
with self.captureOnCommitCallbacks(execute=True):
|
|
1007
|
+
VariousOnDeleteModel.objects.create(protected_document=self.document)
|
|
973
1008
|
response = self.client.get(self.delete_url)
|
|
974
1009
|
self.assertEqual(response.status_code, 200)
|
|
975
1010
|
self.assertTemplateUsed(response, "wagtailadmin/generic/confirm_delete.html")
|
|
@@ -991,7 +1026,8 @@ class TestDocumentDeleteView(WagtailTestUtils, TestCase):
|
|
|
991
1026
|
)
|
|
992
1027
|
|
|
993
1028
|
def test_delete_post_with_protected_reference(self):
|
|
994
|
-
|
|
1029
|
+
with self.captureOnCommitCallbacks(execute=True):
|
|
1030
|
+
VariousOnDeleteModel.objects.create(protected_document=self.document)
|
|
995
1031
|
response = self.client.post(self.delete_url)
|
|
996
1032
|
self.assertRedirects(response, reverse("wagtailadmin_home"))
|
|
997
1033
|
self.assertTrue(
|
|
@@ -2058,21 +2094,23 @@ class TestUsageCount(WagtailTestUtils, TestCase):
|
|
|
2058
2094
|
self.assertEqual(doc.get_usage().count(), 0)
|
|
2059
2095
|
|
|
2060
2096
|
def test_used_document_usage_count(self):
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2097
|
+
with self.captureOnCommitCallbacks(execute=True):
|
|
2098
|
+
doc = models.Document.objects.get(id=1)
|
|
2099
|
+
page = EventPage.objects.get(id=4)
|
|
2100
|
+
event_page_related_link = EventPageRelatedLink()
|
|
2101
|
+
event_page_related_link.page = page
|
|
2102
|
+
event_page_related_link.link_document = doc
|
|
2103
|
+
event_page_related_link.save()
|
|
2067
2104
|
self.assertEqual(doc.get_usage().count(), 1)
|
|
2068
2105
|
|
|
2069
2106
|
def test_usage_count_appears(self):
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2107
|
+
with self.captureOnCommitCallbacks(execute=True):
|
|
2108
|
+
doc = models.Document.objects.get(id=1)
|
|
2109
|
+
page = EventPage.objects.get(id=4)
|
|
2110
|
+
event_page_related_link = EventPageRelatedLink()
|
|
2111
|
+
event_page_related_link.page = page
|
|
2112
|
+
event_page_related_link.link_document = doc
|
|
2113
|
+
event_page_related_link.save()
|
|
2076
2114
|
response = self.client.get(reverse("wagtaildocs:edit", args=(1,)))
|
|
2077
2115
|
self.assertContains(response, "Used 1 time")
|
|
2078
2116
|
|
|
@@ -2092,12 +2130,13 @@ class TestGetUsage(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
|
|
|
2092
2130
|
self.assertEqual(list(doc.get_usage()), [])
|
|
2093
2131
|
|
|
2094
2132
|
def test_used_document_get_usage(self):
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2133
|
+
with self.captureOnCommitCallbacks(execute=True):
|
|
2134
|
+
doc = models.Document.objects.get(id=1)
|
|
2135
|
+
page = EventPage.objects.get(id=4)
|
|
2136
|
+
event_page_related_link = EventPageRelatedLink()
|
|
2137
|
+
event_page_related_link.page = page
|
|
2138
|
+
event_page_related_link.link_document = doc
|
|
2139
|
+
event_page_related_link.save()
|
|
2101
2140
|
|
|
2102
2141
|
self.assertIsInstance(doc.get_usage()[0], tuple)
|
|
2103
2142
|
self.assertIsInstance(doc.get_usage()[0][0], Page)
|
|
@@ -2105,12 +2144,13 @@ class TestGetUsage(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
|
|
|
2105
2144
|
self.assertIsInstance(doc.get_usage()[0][1][0], ReferenceIndex)
|
|
2106
2145
|
|
|
2107
2146
|
def test_usage_page(self):
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2147
|
+
with self.captureOnCommitCallbacks(execute=True):
|
|
2148
|
+
doc = models.Document.objects.get(id=1)
|
|
2149
|
+
page = EventPage.objects.get(id=4)
|
|
2150
|
+
event_page_related_link = EventPageRelatedLink()
|
|
2151
|
+
event_page_related_link.page = page
|
|
2152
|
+
event_page_related_link.link_document = doc
|
|
2153
|
+
event_page_related_link.save()
|
|
2114
2154
|
response = self.client.get(reverse("wagtaildocs:document_usage", args=(1,)))
|
|
2115
2155
|
self.assertContains(response, "Christmas")
|
|
2116
2156
|
self.assertContains(response, '<table class="listing">')
|
|
@@ -2140,12 +2180,13 @@ class TestGetUsage(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
|
|
|
2140
2180
|
self.assertNotContains(response, '<table class="listing">')
|
|
2141
2181
|
|
|
2142
2182
|
def test_usage_page_with_only_change_permission(self):
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2183
|
+
with self.captureOnCommitCallbacks(execute=True):
|
|
2184
|
+
doc = models.Document.objects.get(id=1)
|
|
2185
|
+
page = EventPage.objects.get(id=4)
|
|
2186
|
+
event_page_related_link = EventPageRelatedLink()
|
|
2187
|
+
event_page_related_link.page = page
|
|
2188
|
+
event_page_related_link.link_document = doc
|
|
2189
|
+
event_page_related_link.save()
|
|
2149
2190
|
|
|
2150
2191
|
# Create a user with change_document permission but not add_document
|
|
2151
2192
|
user = self.create_user(
|
|
@@ -58,15 +58,18 @@ class TestServeView(TestCase):
|
|
|
58
58
|
f'inline; filename="{self.pdf_document.filename}"',
|
|
59
59
|
)
|
|
60
60
|
|
|
61
|
+
def test_content_security_policy(self):
|
|
62
|
+
self.assertEqual(self.get()["Content-Security-Policy"], "default-src 'none'")
|
|
63
|
+
|
|
64
|
+
with self.settings(WAGTAILDOCS_BLOCK_EMBEDDED_CONTENT=False):
|
|
65
|
+
self.assertNotIn("Content-Security-Policy", self.get().headers)
|
|
66
|
+
|
|
67
|
+
def test_no_sniff_content_type(self):
|
|
68
|
+
self.assertEqual(self.get()["X-Content-Type-Options"], "nosniff")
|
|
69
|
+
|
|
61
70
|
@mock.patch("wagtail.documents.views.serve.hooks")
|
|
62
71
|
@mock.patch("wagtail.documents.views.serve.get_object_or_404")
|
|
63
|
-
def
|
|
64
|
-
self, mock_get_object_or_404, mock_hooks
|
|
65
|
-
):
|
|
66
|
-
"""
|
|
67
|
-
Tests the 'Content-Disposition' header in a response when using a
|
|
68
|
-
storage backend that doesn't expose filesystem paths.
|
|
69
|
-
"""
|
|
72
|
+
def test_non_local_filesystem_headers(self, mock_get_object_or_404, mock_hooks):
|
|
70
73
|
# Create a mock document with no local file to hit the correct code path
|
|
71
74
|
mock_doc = mock.Mock()
|
|
72
75
|
mock_doc.filename = self.document.filename
|
|
@@ -90,16 +93,14 @@ class TestServeView(TestCase):
|
|
|
90
93
|
urllib.parse.quote(self.document.filename)
|
|
91
94
|
),
|
|
92
95
|
)
|
|
96
|
+
self.assertEqual(response["Content-Security-Policy"], "default-src 'none'")
|
|
97
|
+
self.assertEqual(response["X-Content-Type-Options"], "nosniff")
|
|
93
98
|
|
|
94
99
|
@mock.patch("wagtail.documents.views.serve.hooks")
|
|
95
100
|
@mock.patch("wagtail.documents.views.serve.get_object_or_404")
|
|
96
|
-
def
|
|
101
|
+
def test_non_local_filesystem_inline_headers(
|
|
97
102
|
self, mock_get_object_or_404, mock_hooks
|
|
98
103
|
):
|
|
99
|
-
"""
|
|
100
|
-
Tests the 'Content-Disposition' header in a response when using a
|
|
101
|
-
storage backend that doesn't expose filesystem paths.
|
|
102
|
-
"""
|
|
103
104
|
# Create a mock document with no local file to hit the correct code path
|
|
104
105
|
mock_doc = mock.Mock()
|
|
105
106
|
mock_doc.filename = self.pdf_document.filename
|
|
@@ -118,6 +119,8 @@ class TestServeView(TestCase):
|
|
|
118
119
|
self.assertEqual(response.status_code, 200)
|
|
119
120
|
|
|
120
121
|
self.assertEqual(response["Content-Disposition"], "inline")
|
|
122
|
+
self.assertEqual(response["Content-Security-Policy"], "default-src 'none'")
|
|
123
|
+
self.assertEqual(response["X-Content-Type-Options"], "nosniff")
|
|
121
124
|
|
|
122
125
|
def test_content_length_header(self):
|
|
123
126
|
self.assertEqual(self.get()["Content-Length"], "25")
|
|
@@ -346,6 +349,12 @@ class TestServeViewWithSendfile(TestCase):
|
|
|
346
349
|
os.path.join(settings.MEDIA_URL, self.document.file.name),
|
|
347
350
|
)
|
|
348
351
|
|
|
352
|
+
def test_content_security_policy(self):
|
|
353
|
+
self.assertEqual(self.get()["Content-Security-Policy"], "default-src 'none'")
|
|
354
|
+
|
|
355
|
+
def test_no_sniff_content_type(self):
|
|
356
|
+
self.assertEqual(self.get()["X-Content-Type-Options"], "nosniff")
|
|
357
|
+
|
|
349
358
|
|
|
350
359
|
@override_settings(WAGTAILDOCS_SERVE_METHOD=None)
|
|
351
360
|
class TestServeWithUnicodeFilename(TestCase):
|
|
@@ -145,6 +145,7 @@ class BaseAdminDocumentChooser(BaseChooser):
|
|
|
145
145
|
js=[
|
|
146
146
|
versioned_static("wagtaildocs/js/document-chooser-modal.js"),
|
|
147
147
|
versioned_static("wagtaildocs/js/document-chooser.js"),
|
|
148
|
+
versioned_static("wagtaildocs/js/document-chooser-telepath.js"),
|
|
148
149
|
]
|
|
149
150
|
)
|
|
150
151
|
|