From cc9a6a0f50f575d2b20e6588617fc0856c519be0 Mon Sep 17 00:00:00 2001 From: Brian Weaver <weaver.299@osu.edu> Date: Tue, 25 Feb 2020 11:25:56 -0500 Subject: [PATCH] Update paragraphs module to 1.11 --- composer.json | 7 +- composer.lock | 34 ++- vendor/composer/installed.json | 31 ++- web/modules/paragraphs/PATCHES.txt | 7 + web/modules/paragraphs/README.txt | 16 +- web/modules/paragraphs/composer.json | 6 +- .../config/schema/paragraphs_type.schema.yml | 15 +- web/modules/paragraphs/css/_summary.scss | 77 ++++-- web/modules/paragraphs/css/_variables.scss | 4 + .../paragraphs/css/paragraphs.dragdrop.css | 8 - .../paragraphs/css/paragraphs.dragdrop.scss | 7 +- .../paragraphs/css/paragraphs.formatter.css | 58 +++-- .../paragraphs/css/paragraphs.modal.css | 3 + .../paragraphs/css/paragraphs.modal.scss | 3 + .../paragraphs/css/paragraphs.widget.css | 163 ++++++++---- .../paragraphs/css/paragraphs.widget.scss | 103 ++++++-- web/modules/paragraphs/icons/icon-view.svg | 6 +- .../paragraphs/js/paragraphs.actions.js | 9 +- .../js/paragraphs.add_above_button.js | 39 +-- web/modules/paragraphs/js/paragraphs.admin.js | 111 ++++++-- .../paragraphs/js/paragraphs.dragdrop.js | 24 +- web/modules/paragraphs/js/paragraphs.modal.js | 87 ++++--- .../paragraphs.paragraphs_type.text_image.yml | 2 +- .../paragraphs_demo/paragraphs_demo.info.yml | 9 +- .../paragraphs_demo/paragraphs_demo.install | 6 +- .../src/Functional}/ParagraphsDemoTest.php | 17 +- .../views.view.paragraphs_library_browser.yml | 1 + .../paragraphs_library.info.yml | 9 +- .../paragraphs_library.install | 39 ++- .../paragraphs_library.module | 17 +- .../src/Controller/LibraryItemController.php | 3 +- .../src/Entity/LibraryItem.php | 28 +- .../src/Form/LibraryItemForm.php | 42 +-- .../Form/LibraryItemRevisionDeleteForm.php | 6 +- .../Form/LibraryItemRevisionRevertForm.php | 6 +- .../src/LibraryItemAccessControlHandler.php | 7 - ...lowedParagraphsTypeConstraintValidator.php | 32 +-- .../Functional}/MultilingualBehaviorTest.php | 32 +-- .../Functional/ParagraphsLibraryItemTest.php | 57 +++- .../ParagraphsLibraryItemTranslationTest.php | 39 ++- .../src/Functional/ParagraphsLibraryTest.php} | 78 +++--- .../ParagraphsContentModerationTest.php | 25 +- ...ParagraphsLibraryItemEntityBrowserTest.php | 96 ++++++- .../paragraphs_type_permissions.info.yml | 9 +- .../src/ParagraphsTypePermissions.php | 2 - .../ParagraphsTypePermissionsTest.php | 38 ++- web/modules/paragraphs/paragraphs.info.yml | 11 +- web/modules/paragraphs/paragraphs.install | 210 ++++++++++++++- .../paragraphs/paragraphs.libraries.yml | 23 +- web/modules/paragraphs/paragraphs.module | 68 ++++- .../paragraphs/paragraphs.post_update.php | 153 ++++++++++- .../paragraphs/paragraphs.services.yml | 5 + .../paragraphs/src/Entity/Paragraph.php | 246 ++++++++++-------- .../paragraphs/src/Entity/ParagraphsType.php | 148 +++++++++-- .../src/Feeds/Target/Paragraphs.php | 2 +- .../src/Form/ParagraphsTypeDeleteConfirm.php | 2 +- .../src/Form/ParagraphsTypeForm.php | 23 +- .../paragraphs/src/ParagraphInterface.php | 20 +- .../paragraphs/src/ParagraphStorageSchema.php | 5 +- .../paragraphs/src/ParagraphsBehaviorBase.php | 8 +- .../src/ParagraphsBehaviorInterface.php | 5 +- .../src/ParagraphsServiceProvider.php | 2 +- .../ParagraphsTypeAccessControlHandler.php | 34 +++ .../src/ParagraphsTypeIconUuidLookup.php | 55 ++++ .../src/ParagraphsTypeInterface.php | 7 + .../ParagraphSelection.php | 57 +--- .../ParagraphsSummaryFormatter.php | 7 +- .../FieldWidget/InlineParagraphsWidget.php | 70 ++--- .../Field/FieldWidget/ParagraphsWidget.php | 137 +++++++--- .../Plugin/migrate/field/FieldCollection.php | 40 --- .../src/Plugin/migrate/field/Paragraphs.php | 52 ---- .../migrate/process/ProcessPluginBase.php | 11 +- .../Plugin/migrate/source/DrupalSqlBase.php | 10 +- .../migrate/source/d7/FieldCollectionItem.php | 4 +- .../migrate/source/d7/FieldableEntity.php | 10 +- .../migrate/source/d7/ParagraphsItem.php | 2 +- .../src/Tests/Classic/ParagraphsTestBase.php | 7 +- .../ParagraphsExperimentalTestBase.php | 5 +- .../templates/paragraphs-summary.html.twig | 45 ++++ .../paragraphs_test/paragraphs_test.info.yml | 11 +- .../Behavior/TestBoldTextBehavior.php | 7 +- .../Behavior/TestTextColorBehavior.php | 7 +- .../Classic/ParagraphsAccessTest.php | 27 +- .../Classic/ParagraphsAddModesTest.php | 9 +- .../Classic/ParagraphsAdministrationTest.php | 104 +++----- ...assicContentModerationTranslationsTest.php | 13 +- .../Classic/ParagraphsConfigTest.php | 6 +- .../Classic/ParagraphsContactTest.php | 6 +- .../Classic/ParagraphsEditModesTest.php | 36 ++- ...anslationWithNonTranslatableParagraphs.php | 2 +- .../Classic/ParagraphsFieldGroupTest.php | 5 +- .../ParagraphsInlineEntityFormTest.php | 11 +- .../Classic/ParagraphsPreviewTest.php | 16 +- .../ParagraphsSummaryFormatterTest.php | 10 +- .../Functional/Classic/ParagraphsTestBase.php | 208 +++++++++++++++ .../Classic/ParagraphsTranslationTest.php | 44 ++-- .../Classic/ParagraphsTypesTest.php | 50 +++- .../Functional}/Classic/ParagraphsUiTest.php | 9 +- .../Classic/ParagraphsWidgetButtonsTest.php | 32 +-- .../ParagraphsExperimentalAccessTest.php | 65 ++++- .../ParagraphsExperimentalAddModesTest.php | 11 +- ...ragraphsExperimentalAdministrationTest.php | 99 +++---- .../ParagraphsExperimentalAlterByTypeTest.php | 2 +- .../ParagraphsExperimentalBehaviorsTest.php | 47 ++-- .../ParagraphsExperimentalConfigTest.php | 4 +- .../ParagraphsExperimentalContactTest.php | 6 +- ...entalContentModerationTranslationsTest.php | 13 +- ...agraphsExperimentalDragAndDropModeTest.php | 28 +- ...graphsExperimentalDuplicateFeatureTest.php | 24 +- .../ParagraphsExperimentalEditModesTest.php | 105 +++++--- ...anslationWithNonTranslatableParagraphs.php | 2 +- .../ParagraphsExperimentalFieldGroupTest.php | 5 +- ...aragraphsExperimentalHeaderActionsTest.php | 46 ++-- ...graphsExperimentalInlineEntityFormTest.php | 11 +- .../ParagraphsExperimentalPreviewTest.php | 17 +- ...agraphsExperimentalReplicateEnableTest.php | 2 +- ...graphsExperimentalSummaryFormatterTest.php | 10 +- .../ParagraphsExperimentalTestBase.php | 47 ++++ .../ParagraphsExperimentalTranslationTest.php | 56 ++-- ...ParagraphsExperimentalTranslationsTest.php | 39 ++- .../ParagraphsExperimentalTypesTest.php | 9 +- .../ParagraphsExperimentalUiTest.php | 15 +- ...aragraphsExperimentalWidgetButtonsTest.php | 32 ++- .../ParagraphsExperimentalBehaviorsTest.php | 9 +- .../ParagraphsExperimentalUiTest.php | 31 ++- ...aragraphsExperimentalWidgetButtonsTest.php | 47 +++- .../Functional}/ParagraphsUninstallTest.php | 19 +- .../ParagraphsExperimentalAddWidgetTest.php | 89 +++++-- ...raphsExperimentalClientsideButtonsTest.php | 38 ++- ...aphsExperimentalEditPerspectivesUiTest.php | 136 ++++++---- ...ragraphsExperimentalWidgetElementsTest.php | 13 +- .../ParagraphsTestBaseTrait.php | 4 +- .../tests/src/Kernel/ParagraphsAccessTest.php | 2 +- .../Kernel/ParagraphsBehaviorPluginsTest.php | 37 ++- .../Kernel/ParagraphsCollapsedSummaryTest.php | 45 +++- .../ParagraphsCompositeRelationshipTest.php | 1 - .../Kernel/ParagraphsEntityMethodsTest.php | 117 +++++++++ .../src/Kernel/ParagraphsIsChangedTest.php | 5 - .../src/Kernel/ParagraphsReplicateTest.php | 2 - .../ParagraphsCoreVersionUiTestTrait.php | 58 +++++ 140 files changed, 3309 insertions(+), 1554 deletions(-) create mode 100644 web/modules/paragraphs/PATCHES.txt rename web/modules/paragraphs/modules/paragraphs_demo/{src/Tests => tests/src/Functional}/ParagraphsDemoTest.php (94%) rename web/modules/paragraphs/modules/paragraphs_library/{src/Tests => tests/src/Functional}/MultilingualBehaviorTest.php (88%) rename web/modules/paragraphs/modules/paragraphs_library/{src/Tests/ParagraphsLibraryItemTest.php => tests/src/Functional/ParagraphsLibraryTest.php} (88%) rename web/modules/paragraphs/modules/paragraphs_type_permissions/{src/Tests => tests/src/Functional}/ParagraphsTypePermissionsTest.php (86%) create mode 100644 web/modules/paragraphs/src/ParagraphsTypeAccessControlHandler.php create mode 100644 web/modules/paragraphs/src/ParagraphsTypeIconUuidLookup.php create mode 100644 web/modules/paragraphs/templates/paragraphs-summary.html.twig rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Classic/ParagraphsAccessTest.php (90%) rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Classic/ParagraphsAddModesTest.php (97%) rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Classic/ParagraphsAdministrationTest.php (84%) rename web/modules/paragraphs/tests/src/Functional/{ => Classic}/ParagraphsClassicContentModerationTranslationsTest.php (98%) rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Classic/ParagraphsConfigTest.php (97%) rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Classic/ParagraphsContactTest.php (85%) rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Classic/ParagraphsEditModesTest.php (67%) rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Classic/ParagraphsEntityTranslationWithNonTranslatableParagraphs.php (98%) rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Classic/ParagraphsFieldGroupTest.php (90%) rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Classic/ParagraphsInlineEntityFormTest.php (92%) rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Classic/ParagraphsPreviewTest.php (87%) rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Classic/ParagraphsSummaryFormatterTest.php (88%) create mode 100644 web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsTestBase.php rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Classic/ParagraphsTranslationTest.php (96%) rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Classic/ParagraphsTypesTest.php (72%) rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Classic/ParagraphsUiTest.php (94%) rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Classic/ParagraphsWidgetButtonsTest.php (78%) rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalAccessTest.php (80%) rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalAddModesTest.php (97%) rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalAdministrationTest.php (84%) rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalAlterByTypeTest.php (95%) rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalBehaviorsTest.php (86%) rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalConfigTest.php (98%) rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalContactTest.php (87%) rename web/modules/paragraphs/tests/src/Functional/{ => Experimental}/ParagraphsExperimentalContentModerationTranslationsTest.php (98%) rename web/modules/paragraphs/tests/src/Functional/{ => Experimental}/ParagraphsExperimentalDragAndDropModeTest.php (98%) rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalDuplicateFeatureTest.php (88%) rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalEditModesTest.php (62%) rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalEntityTranslationWithNonTranslatableParagraphs.php (98%) rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalFieldGroupTest.php (90%) rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalHeaderActionsTest.php (87%) rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalInlineEntityFormTest.php (92%) rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalPreviewTest.php (86%) rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalReplicateEnableTest.php (79%) rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalSummaryFormatterTest.php (88%) create mode 100644 web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalTestBase.php rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalTranslationTest.php (95%) rename web/modules/paragraphs/tests/src/Functional/{ => Experimental}/ParagraphsExperimentalTranslationsTest.php (77%) rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalTypesTest.php (92%) rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalUiTest.php (90%) rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalWidgetButtonsTest.php (89%) rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/ParagraphsUninstallTest.php (76%) create mode 100644 web/modules/paragraphs/tests/src/Kernel/ParagraphsEntityMethodsTest.php create mode 100644 web/modules/paragraphs/tests/src/Traits/ParagraphsCoreVersionUiTestTrait.php diff --git a/composer.json b/composer.json index d1ef7f2961..8de26d8ad5 100644 --- a/composer.json +++ b/composer.json @@ -149,7 +149,7 @@ "drupal/mobile_device_detection": "^3.2", "drupal/module_filter": "^3.1", "drupal/pantheon_advanced_page_cache": "^1.0", - "drupal/paragraphs": "1.6", + "drupal/paragraphs": "^1.6", "drupal/pathauto": "^1.0", "drupal/realname": "^1.0@RC", "drupal/rebuild_cache_access": "^1.4", @@ -302,6 +302,9 @@ }, "drupal/entity_clone": { "3060223": "https://www.drupal.org/files/issues/2019-10-17/%20entity_clone-corrupted-paragraph-cloning-3060223-5.patch" + }, + "drupal/paragraphs": { + "3114512": "https://www.drupal.org/files/issues/2020-02-20/3114512-1.patch" } } }, @@ -313,4 +316,4 @@ "php": "7.0.8" } } -} +} \ No newline at end of file diff --git a/composer.lock b/composer.lock index 90dc22db4e..e304ef53bb 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "926e92273c27be3e90bbd5a0458f014a", + "content-hash": "9cebdfa2dca9a89bb18005ed1f9db499", "packages": [ { "name": "alchemy/zippy", @@ -3590,7 +3590,8 @@ }, "patches_applied": { "2799049": "patches/role_based_email_access-2799049-d87.patch", - "2949017": "https://www.drupal.org/files/issues/2018-09-19/allow-uid-1-to-delete-2949017-36-3.patch" + "2862291": "https://www.drupal.org/files/issues/2019-07-02/2862291-21.patch", + "2949017": "https://www.drupal.org/files/issues/2019-12-12/2949017-59.patch" } }, "autoload": { @@ -6273,29 +6274,29 @@ }, { "name": "drupal/paragraphs", - "version": "1.6.0", + "version": "1.11.0", "source": { "type": "git", "url": "https://git.drupalcode.org/project/paragraphs.git", - "reference": "8.x-1.6" + "reference": "8.x-1.11" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/paragraphs-8.x-1.6.zip", - "reference": "8.x-1.6", - "shasum": "cd93e244f3a78dabdcf362adc31e59aad25b3fae" + "url": "https://ftp.drupal.org/files/projects/paragraphs-8.x-1.11.zip", + "reference": "8.x-1.11", + "shasum": "4fa849a249fbc689ca0c83523a967c08767e91af" }, "require": { - "drupal/core": "~8", + "drupal/core": "^8.7.7 || ^9", "drupal/entity_reference_revisions": "~1.3" }, "require-dev": { "drupal/block_field": "~1.0", "drupal/ctools": "3.x-dev", "drupal/diff": "~1.0", - "drupal/entity_browser": "1.x-dev", + "drupal/entity_browser": "2.x-dev", "drupal/entity_usage": "2.x-dev", - "drupal/field_group": "~1.0", + "drupal/field_group": "3.x-dev", "drupal/inline_entity_form": "~1.0", "drupal/paragraphs-paragraphs_library": "*", "drupal/replicate": "~1.0", @@ -6311,12 +6312,15 @@ "dev-1.x": "1.x-dev" }, "drupal": { - "version": "8.x-1.6", - "datestamp": "1550692525", + "version": "8.x-1.11", + "datestamp": "1581850829", "security-coverage": { "status": "covered", "message": "Covered by Drupal's security advisory policy" } + }, + "patches_applied": { + "3114512": "https://www.drupal.org/files/issues/2020-02-20/3114512-1.patch" } }, "notification-url": "https://packages.drupal.org/8/downloads", @@ -6340,6 +6344,10 @@ "name": "jeroen.b", "homepage": "https://www.drupal.org/user/1853532" }, + { + "name": "jstoller", + "homepage": "https://www.drupal.org/user/99012" + }, { "name": "miro_dietiker", "homepage": "https://www.drupal.org/user/227761" @@ -6348,7 +6356,7 @@ "description": "Enables the creation of Paragraphs entities.", "homepage": "https://www.drupal.org/project/paragraphs", "support": { - "source": "http://cgit.drupalcode.org/paragraphs" + "source": "https://git.drupalcode.org/project/paragraphs" } }, { diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 037d9c35b1..899a4506a1 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -6470,30 +6470,30 @@ }, { "name": "drupal/paragraphs", - "version": "1.6.0", - "version_normalized": "1.6.0.0", + "version": "1.11.0", + "version_normalized": "1.11.0.0", "source": { "type": "git", "url": "https://git.drupalcode.org/project/paragraphs.git", - "reference": "8.x-1.6" + "reference": "8.x-1.11" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/paragraphs-8.x-1.6.zip", - "reference": "8.x-1.6", - "shasum": "cd93e244f3a78dabdcf362adc31e59aad25b3fae" + "url": "https://ftp.drupal.org/files/projects/paragraphs-8.x-1.11.zip", + "reference": "8.x-1.11", + "shasum": "4fa849a249fbc689ca0c83523a967c08767e91af" }, "require": { - "drupal/core": "~8", + "drupal/core": "^8.7.7 || ^9", "drupal/entity_reference_revisions": "~1.3" }, "require-dev": { "drupal/block_field": "~1.0", "drupal/ctools": "3.x-dev", "drupal/diff": "~1.0", - "drupal/entity_browser": "1.x-dev", + "drupal/entity_browser": "2.x-dev", "drupal/entity_usage": "2.x-dev", - "drupal/field_group": "~1.0", + "drupal/field_group": "3.x-dev", "drupal/inline_entity_form": "~1.0", "drupal/paragraphs-paragraphs_library": "*", "drupal/replicate": "~1.0", @@ -6509,12 +6509,15 @@ "dev-1.x": "1.x-dev" }, "drupal": { - "version": "8.x-1.6", - "datestamp": "1550692525", + "version": "8.x-1.11", + "datestamp": "1581850829", "security-coverage": { "status": "covered", "message": "Covered by Drupal's security advisory policy" } + }, + "patches_applied": { + "3114512": "https://www.drupal.org/files/issues/2020-02-20/3114512-1.patch" } }, "installation-source": "dist", @@ -6539,6 +6542,10 @@ "name": "jeroen.b", "homepage": "https://www.drupal.org/user/1853532" }, + { + "name": "jstoller", + "homepage": "https://www.drupal.org/user/99012" + }, { "name": "miro_dietiker", "homepage": "https://www.drupal.org/user/227761" @@ -6547,7 +6554,7 @@ "description": "Enables the creation of Paragraphs entities.", "homepage": "https://www.drupal.org/project/paragraphs", "support": { - "source": "http://cgit.drupalcode.org/paragraphs" + "source": "https://git.drupalcode.org/project/paragraphs" } }, { diff --git a/web/modules/paragraphs/PATCHES.txt b/web/modules/paragraphs/PATCHES.txt new file mode 100644 index 0000000000..3dda710f53 --- /dev/null +++ b/web/modules/paragraphs/PATCHES.txt @@ -0,0 +1,7 @@ +This file was automatically generated by Composer Patches (https://github.com/cweagans/composer-patches) +Patches applied to this directory: + +3114512 +Source: https://www.drupal.org/files/issues/2020-02-20/3114512-1.patch + + diff --git a/web/modules/paragraphs/README.txt b/web/modules/paragraphs/README.txt index ecc17371ec..f1c652a6b9 100644 --- a/web/modules/paragraphs/README.txt +++ b/web/modules/paragraphs/README.txt @@ -36,13 +36,17 @@ and move paragraphs including their children around and into other paragraphs. During drag & drop mode, paragraphs are also displayed as a summary only, which results in a very compact display that makes it easier to move them around. -To use this, an additional library is necessary, which needs to be put in the -/libraries folder. Download from https://github.com/RubaXa/Sortable/releases, -make sure that the folder name is Sortable (with uppercase S) so that the path -to the javascript file is /libraries/Sortable/Sortable.min.js. +Starting with Drupal 8.8.0, the necessary library is part of Drupal core and +this feature is always available. -Due to a known issue (https://github.com/RubaXa/Sortable/pull/1154), version -1.6.0 should be used with the patch from that pull request. +In Drupal 8.7 and earlier, an additional library is necessary, which needs to be +put in the libraries folder. Download from +https://github.com/RubaXa/Sortable/releases, make sure that the folder name is +Sortable (with uppercase S) so that the path to the javascript file is +/libraries/Sortable/Sortable.min.js. + +Use the version 1.10+ as it's tested and approved. Older versions may introduce +bugs with nested drag & drop functionality. If the file exists, the feature will automatically be available. diff --git a/web/modules/paragraphs/composer.json b/web/modules/paragraphs/composer.json index 158e9f5183..7d4960b265 100644 --- a/web/modules/paragraphs/composer.json +++ b/web/modules/paragraphs/composer.json @@ -4,7 +4,7 @@ "type": "drupal-module", "license": "GPL-2.0", "require": { - "drupal/core": "~8", + "drupal/core": "^8.7.7 || ^9", "drupal/entity_reference_revisions": "~1.3" }, "suggest": { @@ -14,10 +14,10 @@ "drupal/diff": "~1.0", "drupal/replicate": "~1.0", "drupal/inline_entity_form": "~1.0", - "drupal/field_group": "~1.0", + "drupal/field_group": "3.x-dev", "drupal/block_field": "~1.0", "drupal/ctools": "3.x-dev", - "drupal/entity_browser": "1.x-dev", + "drupal/entity_browser": "2.x-dev", "drupal/entity_usage": "2.x-dev", "drupal/search_api": "~1.0" } diff --git a/web/modules/paragraphs/config/schema/paragraphs_type.schema.yml b/web/modules/paragraphs/config/schema/paragraphs_type.schema.yml index a04120dd99..15fc2f1dab 100644 --- a/web/modules/paragraphs/config/schema/paragraphs_type.schema.yml +++ b/web/modules/paragraphs/config/schema/paragraphs_type.schema.yml @@ -11,6 +11,9 @@ paragraphs.paragraphs_type.*: icon_uuid: type: string label: 'Icon uuid' + icon_default: + type: string + label: 'Default icon' description: type: text label: 'Description' @@ -53,9 +56,9 @@ entity_reference_selection.default:paragraph: edit_mode: type: string title: - type: string + type: label title_plural: - type: string + type: label default_paragraph_type: type: string @@ -63,9 +66,9 @@ field.widget.settings.entity_reference_paragraphs: type: mapping mapping: title: - type: string + type: label title_plural: - type: string + type: label edit_mode: type: string add_mode: @@ -79,9 +82,9 @@ field.widget.settings.paragraphs: type: mapping mapping: title: - type: string + type: label title_plural: - type: string + type: label edit_mode: type: string closed_mode: diff --git a/web/modules/paragraphs/css/_summary.scss b/web/modules/paragraphs/css/_summary.scss index b08472f07f..5c646f4cad 100644 --- a/web/modules/paragraphs/css/_summary.scss +++ b/web/modules/paragraphs/css/_summary.scss @@ -18,6 +18,7 @@ text-align: center; white-space: nowrap; vertical-align: baseline; + margin: 3px 0; // Empty badges collapse automatically &:empty { @@ -26,33 +27,63 @@ } } -.paragraph-info { - display: flex; - // Needed not just because of centering but also to prevent span child to - // stretch vertically. - align-items: center; -} - // We are using .js prefix here mainly because we want to apply this style rules // only for JS version of the element. .js { - .paragraphs-collapsed-description { - position: relative; - height: 1.538em; - overflow: hidden; - color: #777; - word-break: break-all; - line-height: 1.538em; - - // Fade out text element. - &::after { + .paragraphs-description { + .paragraphs-content-wrapper, + .paragraphs-plugin-wrapper { + position: relative; + height: 1.538em; + overflow: hidden; + word-break: break-all; + line-height: 1.538em; + text-overflow: ellipsis; + } + + .summary-plugin-label::after { + content: ": "; + } + + .summary-content { + color: $content-summary-color; + } + + .summary-plugin { + display: inline-block; + padding-right: 5px; + font-size: 0.7rem; + color: $behavior-summary-color; + + &:not(:last-child) { + border-right: 2px solid $light-grey; + } + + &:not(:first-child) { + padding: 0 5px; + } + } + } + + // Behavior tab is active. + .behavior-active { + // Hide plugin summary. + .paragraphs-expanded-description .paragraphs-plugin-wrapper, + .paragraphs-content { + display: none; + } + + // Display paragraphs behavior. + .paragraphs-behavior { display: block; - position: absolute; - top: 0; - right: 0; - width: 3em; - background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, #fff 100%); - content: "\00a0"; + } + } + + // Content tab is active. + .content-active { + // Hide content summary. + .paragraphs-expanded-description .paragraphs-content-wrapper { + display: none; } } } diff --git a/web/modules/paragraphs/css/_variables.scss b/web/modules/paragraphs/css/_variables.scss index 47660ad360..3ed4ce6265 100644 --- a/web/modules/paragraphs/css/_variables.scss +++ b/web/modules/paragraphs/css/_variables.scss @@ -1,6 +1,7 @@ // Colours. $grey-dark: #999999 !default; +$light-grey: #e5e3de !default; // Layout. @@ -35,3 +36,6 @@ $info-icon-size: 16px !default; $badge-padding-y: .15em !default; $badge-padding-x: .3em !default; $badge-color: #787878 !default; +$content-summary-color: #666666 !default; +$behavior-summary-color: #888888 !default; +$paragraph-hover-bg: #f7fcff !default; diff --git a/web/modules/paragraphs/css/paragraphs.dragdrop.css b/web/modules/paragraphs/css/paragraphs.dragdrop.css index e743f211e5..a8abdc811d 100644 --- a/web/modules/paragraphs/css/paragraphs.dragdrop.css +++ b/web/modules/paragraphs/css/paragraphs.dragdrop.css @@ -176,14 +176,6 @@ line-height: 1.538em; } -.paragraphs-dragdrop__item .paragraphs-summary-wrapper > .paragraphs-collapsed-description { - -webkit-box-flex: 1; - -webkit-flex-grow: 1; - -ms-flex-positive: 1; - flex-grow: 1; - font-style: italic; -} - .paragraphs-dragdrop__handle { display: -webkit-box; display: -webkit-flex; diff --git a/web/modules/paragraphs/css/paragraphs.dragdrop.scss b/web/modules/paragraphs/css/paragraphs.dragdrop.scss index 09cd3f7bec..a451bbd69c 100644 --- a/web/modules/paragraphs/css/paragraphs.dragdrop.scss +++ b/web/modules/paragraphs/css/paragraphs.dragdrop.scss @@ -171,18 +171,13 @@ width: calc(100% - var(--dnd-icon-size)); } - // Collapsed summary container. + // Closed summary container. .paragraphs-summary-wrapper { display: flex; align-items: center; height: 1.538em; margin: 5px 0; line-height: 1.538em; - - > .paragraphs-collapsed-description { - flex-grow: 1; - font-style: italic; - } } } diff --git a/web/modules/paragraphs/css/paragraphs.formatter.css b/web/modules/paragraphs/css/paragraphs.formatter.css index af9d1a8366..47f6580171 100644 --- a/web/modules/paragraphs/css/paragraphs.formatter.css +++ b/web/modules/paragraphs/css/paragraphs.formatter.css @@ -10,41 +10,57 @@ text-align: center; white-space: nowrap; vertical-align: baseline; + margin: 3px 0; } .paragraphs-badge:empty { display: none; } -.paragraph-info { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-box-align: center; - -webkit-align-items: center; - -ms-flex-align: center; - align-items: center; -} - -.js .paragraphs-collapsed-description { +.js .paragraphs-description .paragraphs-content-wrapper, +.js .paragraphs-description .paragraphs-plugin-wrapper { position: relative; height: 1.538em; overflow: hidden; - color: #777; word-break: break-all; line-height: 1.538em; + text-overflow: ellipsis; } -.js .paragraphs-collapsed-description::after { +.js .paragraphs-description .summary-plugin-label::after { + content: ": "; +} + +.js .paragraphs-description .summary-content { + color: #666666; +} + +.js .paragraphs-description .summary-plugin { + display: inline-block; + padding-right: 5px; + font-size: 0.7rem; + color: #888888; +} + +.js .paragraphs-description .summary-plugin:not(:last-child) { + border-right: 2px solid #e5e3de; +} + +.js .paragraphs-description .summary-plugin:not(:first-child) { + padding: 0 5px; +} + +.js .behavior-active .paragraphs-expanded-description .paragraphs-plugin-wrapper, +.js .behavior-active .paragraphs-content { + display: none; +} + +.js .behavior-active .paragraphs-behavior { display: block; - position: absolute; - top: 0; - right: 0; - width: 3em; - background: -webkit-gradient(linear, left top, right top, from(rgba(255, 255, 255, 0)), to(#fff)); - background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, #fff 100%); - content: "\00a0"; +} + +.js .content-active .paragraphs-expanded-description .paragraphs-content-wrapper { + display: none; } .paragraph-formatter { diff --git a/web/modules/paragraphs/css/paragraphs.modal.css b/web/modules/paragraphs/css/paragraphs.modal.css index 22a368d661..299c77aa76 100644 --- a/web/modules/paragraphs/css/paragraphs.modal.css +++ b/web/modules/paragraphs/css/paragraphs.modal.css @@ -8,7 +8,10 @@ ul.paragraphs-add-dialog-list input.field-add-more-submit { background-repeat: no-repeat; background-position: 10px; background-size: auto calc(100% - 10px); + margin: 0; padding-left: 40px; + padding-top: calc(.5rem - 1px); + padding-bottom: calc(.5rem - 1px); text-align: left; border-radius: 3px; } diff --git a/web/modules/paragraphs/css/paragraphs.modal.scss b/web/modules/paragraphs/css/paragraphs.modal.scss index 0da0fe1ada..96631e5ea6 100644 --- a/web/modules/paragraphs/css/paragraphs.modal.scss +++ b/web/modules/paragraphs/css/paragraphs.modal.scss @@ -7,7 +7,10 @@ ul.paragraphs-add-dialog-list { background-repeat: no-repeat; background-position: 10px; background-size: auto calc(100% - 10px); + margin: 0; padding-left: 40px; + padding-top: calc(.5rem - 1px); + padding-bottom: calc(.5rem - 1px); text-align: left; border-radius: 3px; } diff --git a/web/modules/paragraphs/css/paragraphs.widget.css b/web/modules/paragraphs/css/paragraphs.widget.css index dd6b59b597..a2616b936c 100644 --- a/web/modules/paragraphs/css/paragraphs.widget.css +++ b/web/modules/paragraphs/css/paragraphs.widget.css @@ -10,41 +10,57 @@ text-align: center; white-space: nowrap; vertical-align: baseline; + margin: 3px 0; } .paragraphs-badge:empty { display: none; } -.paragraph-info { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-box-align: center; - -webkit-align-items: center; - -ms-flex-align: center; - align-items: center; -} - -.js .paragraphs-collapsed-description { +.js .paragraphs-description .paragraphs-content-wrapper, +.js .paragraphs-description .paragraphs-plugin-wrapper { position: relative; height: 1.538em; overflow: hidden; - color: #777; word-break: break-all; line-height: 1.538em; + text-overflow: ellipsis; +} + +.js .paragraphs-description .summary-plugin-label::after { + content: ": "; +} + +.js .paragraphs-description .summary-content { + color: #666666; +} + +.js .paragraphs-description .summary-plugin { + display: inline-block; + padding-right: 5px; + font-size: 0.7rem; + color: #888888; +} + +.js .paragraphs-description .summary-plugin:not(:last-child) { + border-right: 2px solid #e5e3de; } -.js .paragraphs-collapsed-description::after { +.js .paragraphs-description .summary-plugin:not(:first-child) { + padding: 0 5px; +} + +.js .behavior-active .paragraphs-expanded-description .paragraphs-plugin-wrapper, +.js .behavior-active .paragraphs-content { + display: none; +} + +.js .behavior-active .paragraphs-behavior { display: block; - position: absolute; - top: 0; - right: 0; - width: 3em; - background: -webkit-gradient(linear, left top, right top, from(rgba(255, 255, 255, 0)), to(#fff)); - background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, #fff 100%); - content: "\00a0"; +} + +.js .content-active .paragraphs-expanded-description .paragraphs-content-wrapper { + display: none; } .paragraphs-icon { @@ -53,6 +69,7 @@ width: 20px; background: no-repeat center; background-size: 16px 16px; + vertical-align: middle; } .paragraphs-icon-view { @@ -142,16 +159,41 @@ } } +.js .field--widget-paragraphs .paragraphs-nested .tabledrag-toggle-weight-wrapper { + display: none; +} + .js .field--widget-paragraphs th .paragraphs-actions { float: right; margin-right: -11px; } +.js .field--widget-paragraphs .form-actions { + -webkit-box-align: center; + -webkit-align-items: center; + -ms-flex-align: center; + align-items: center; +} + +.js .field--widget-paragraphs .form-actions .dropbutton-multiple { + margin-right: .5rem; +} + +.js .field--widget-paragraphs .form-actions .placeholder { + margin-left: .25em; +} + .js .field--widget-paragraphs .paragraphs-dropbutton-wrapper { display: -webkit-inline-box; display: -webkit-inline-flex; display: -ms-inline-flexbox; display: inline-flex; + margin: 0; + padding: 0; +} + +.js .field--widget-paragraphs .paragraphs-dropbutton-wrapper .dropbutton-multiple { + margin: 0; } .js .field--widget-paragraphs .dropbutton-wrapper { @@ -160,10 +202,6 @@ padding-right: 0; } -.js .field--widget-paragraphs .dropbutton-widget { - position: static; -} - .js .field--widget-paragraphs .field-multiple-table { margin-bottom: 10px; } @@ -177,9 +215,15 @@ } .js .field--widget-paragraphs .draggable .tabledrag-handle { + min-width: 50px; margin-left: 0; } +.js .field--widget-paragraphs .draggable .tabledrag-handle:focus::before { + margin-left: .1em; + margin-right: .1em; +} + .js .field--widget-paragraphs .tabledrag-handle .handle { height: 22px; } @@ -194,13 +238,13 @@ display: grid; -ms-grid-columns: 100px auto 1fr auto; grid-template-columns: 100px auto 1fr auto; - -ms-grid-rows: auto; - grid-template-rows: auto; - grid-gap: 5px 5px; - -webkit-box-align: center; - -webkit-align-items: center; - -ms-flex-align: center; - align-items: center; + -ms-grid-rows: auto auto; + grid-template-rows: auto auto; + grid-gap: 0 5px; + -webkit-box-align: baseline; + -webkit-align-items: baseline; + -ms-flex-align: baseline; + align-items: baseline; } @media (min-width: 992px) { @@ -233,6 +277,8 @@ -ms-grid-row: 2; -ms-grid-row-span: 1; grid-row: 2 / span 1; + overflow: hidden; + white-space: nowrap; } @media (min-width: 600px) { @@ -241,8 +287,8 @@ -ms-grid-column: 3; -ms-grid-column-span: 1; -ms-grid-row: 1; - -ms-grid-row-span: 1; - grid-row: 1 / span 1; + -ms-grid-row-span: 2; + grid-row: 1 / span 2; } } @@ -269,17 +315,17 @@ margin-top: 5px; } -.draggable:hover .paragraphs-collapsed-description::after { +.draggable:hover .paragraphs-description::after { background: -webkit-gradient(linear, left top, right top, from(rgba(247, 252, 255, 0)), to(#f7fcff)); background: linear-gradient(to right, rgba(247, 252, 255, 0) 0%, #f7fcff 100%); } -.drag-previous .paragraphs-collapsed-description::after { +.drag-previous .paragraphs-description::after { background: -webkit-gradient(linear, left top, right top, from(rgba(255, 255, 221, 0)), to(#ffd)); background: linear-gradient(to right, rgba(255, 255, 221, 0) 0%, #ffd 100%); } -tr:hover .paragraphs-collapsed-description::after { +tr:hover .paragraphs-description::after { background: -webkit-gradient(linear, left top, right top, from(rgba(255, 255, 221, 0)), to(#f7fcff)); background: linear-gradient(to right, rgba(255, 255, 221, 0) 0%, #f7fcff 100%); } @@ -305,6 +351,7 @@ tr:hover .paragraphs-collapsed-description::after { padding-right: 5px; height: 16px; width: 16px; + vertical-align: middle; } .js .paragraph-type-label { @@ -315,18 +362,12 @@ tr:hover .paragraphs-collapsed-description::after { @media (min-width: 600px) { .js .paragraph-type-add-modal { - width: 100%; - padding: 10px 0; - height: 30px; - margin-top: -1.8em; - margin-bottom: -0.2em; - display: inline; + display: inline-block; } } .js .paragraph-type-add-modal-button { display: inline-block; - margin: 0 auto; } .js .paragraph-type-add-modal-button:hover { @@ -341,3 +382,37 @@ tr:hover .paragraphs-collapsed-description::after { .is-horizontal .paragraphs-tabs .tabs__tab { border-bottom: 0; } + +.paragraphs-behavior { + display: none; +} + +.first-paragraph { + -webkit-transition: background-color .3s linear; + transition: background-color .3s linear; +} + +.paragraph-hover { + background-color: #f7fcff; +} + +@media (min-width: 768px) { + /* Basic node form sticky paragraph tabs implementation. */ + .is-horizontal .paragraphs-tabs:first-of-type { + position: -webkit-sticky; + position: sticky; + top: 0; + margin-top: 0; + padding-top: 5px !important; + /* Toolbar bar minimum z-index is 501 so we need to be lower, other way + our sticky tabs will be on top of toolbar menu. */ + z-index: 500; + background-color: rgba(255, 255, 255, 0.9); + } + .toolbar-fixed .is-horizontal .paragraphs-tabs:first-of-type { + top: 39px; + } + .toolbar-fixed.toolbar-horizontal.toolbar-tray-open .is-horizontal .paragraphs-tabs:first-of-type { + top: 79px; + } +} diff --git a/web/modules/paragraphs/css/paragraphs.widget.scss b/web/modules/paragraphs/css/paragraphs.widget.scss index d38a9611b1..3dedd0b966 100644 --- a/web/modules/paragraphs/css/paragraphs.widget.scss +++ b/web/modules/paragraphs/css/paragraphs.widget.scss @@ -14,6 +14,7 @@ width: $info-size; background: no-repeat center; background-size: $info-icon-size $info-icon-size; + vertical-align: middle; $icons: view edit-info edit-disabled delete delete-disabled lock changed collapse warning error; @each $icon in $icons { @@ -55,6 +56,7 @@ } } + .paragraphs-tabs-wrapper { .paragraphs-tabs { display: none; @@ -84,6 +86,9 @@ // only for JS version of a widget. .js { .field--widget-paragraphs { + .paragraphs-nested .tabledrag-toggle-weight-wrapper { + display: none; + } th .paragraphs-actions { float: right; // Table th padding is 12px but for some weird reason here we need to do @@ -91,10 +96,32 @@ margin-right: -11px; } + // Fix alignment of form-actions. + .form-actions { + align-items: center; + + // Fix alignment to content. + .dropbutton-multiple { + margin-right: .5rem; + } + + // Add spacing to "to" keyword + .placeholder { + margin-left: .25em; + } + } + .paragraphs-dropbutton-wrapper { // We are using inline-flex here so 'Add type' dropdown button is inline // and aligned 'to type' text. display: inline-flex; + // Remove margins and paddings that come from Claro theme. + margin: 0; + padding: 0; + + .dropbutton-multiple { + margin: 0; + } } .dropbutton-wrapper { @@ -107,11 +134,6 @@ padding-right: 0; } - // Reset some CSS that are coming from core. - .dropbutton-widget { - position: static; - } - .field-multiple-table { margin-bottom: 10px; } @@ -125,7 +147,16 @@ } .draggable .tabledrag-handle { + min-width: 50px; margin-left: 0; + + // Fix active focus. + &:focus { + &::before { + margin-left: .1em; + margin-right: .1em; + } + } } .tabledrag-handle .handle { @@ -141,9 +172,9 @@ .paragraph-top { display: grid; grid-template-columns: 100px auto 1fr auto; - grid-template-rows: auto; - grid-gap: $gutter-top $gutter-top; - align-items: center; + grid-template-rows: auto auto; + grid-gap: 0 $gutter-top; + align-items: baseline; @media (min-width: map-get($grid-breakpoints, 'lg')) { grid-template-columns: 150px auto 1fr auto; @@ -169,12 +200,14 @@ -ms-grid-column: 1; -ms-grid-column-span: 5; grid-row: 2 / span 1; + overflow: hidden; + white-space: nowrap; @media (min-width: map-get($grid-breakpoints, 'sm')) { grid-column: 3 / 4; -ms-grid-column: 3; -ms-grid-column-span: 1; - grid-row: 1 / span 1; + grid-row: 1 / span 2; } } @@ -198,20 +231,20 @@ margin-top: 5px; } - .paragraphs-collapsed-description { - @at-root .draggable:hover .paragraphs-collapsed-description { + .paragraphs-description { + @at-root .draggable:hover .paragraphs-description { &::after { background: linear-gradient(to right, rgba(247, 252, 255, 0) 0%, #f7fcff 100%); } } - @at-root .drag-previous .paragraphs-collapsed-description { + @at-root .drag-previous .paragraphs-description { &::after { background: linear-gradient(to right, rgba(255, 255, 221, 0) 0%, #ffd 100%); } } - @at-root tr:hover .paragraphs-collapsed-description { + @at-root tr:hover .paragraphs-description { &::after { background: linear-gradient(to right, rgba(255, 255, 221, 0) 0%, #f7fcff 100%); } @@ -232,6 +265,7 @@ padding-right: $gutter-top; height: $info-icon-size; width: $info-icon-size; + vertical-align: middle; } &-label { @@ -243,18 +277,12 @@ @media (min-width: map-get($grid-breakpoints, 'sm')) { .paragraph-type-add-modal { - width: 100%; - padding: 10px 0; - height: 30px; - margin-top: -1.8em; - margin-bottom: -0.2em; - display: inline; + display: inline-block; } } .paragraph-type-add-modal-button { display: inline-block; - margin: 0 auto; } .paragraph-type-add-modal-button:hover { @@ -270,3 +298,38 @@ .is-horizontal .paragraphs-tabs .tabs__tab { border-bottom: 0; } + +// Requires JavaScript to avoid flickering on pageload. +.paragraphs-behavior { + display: none; +} + +.first-paragraph { + transition: background-color .3s linear; +} + +.paragraph-hover { + background-color: $paragraph-hover-bg; +} + +@media (min-width: map-get($grid-breakpoints, 'md')) { + /* Basic node form sticky paragraph tabs implementation. */ + .is-horizontal .paragraphs-tabs:first-of-type { + position: sticky; + top: 0; + margin-top: 0; + padding-top: 5px !important; + /* Toolbar bar minimum z-index is 501 so we need to be lower, other way + our sticky tabs will be on top of toolbar menu. */ + z-index: 500; + background-color: rgba(255, 255, 255, 0.9); + } + + .toolbar-fixed .is-horizontal .paragraphs-tabs:first-of-type { + top: 39px; + } + + .toolbar-fixed.toolbar-horizontal.toolbar-tray-open .is-horizontal .paragraphs-tabs:first-of-type { + top: 79px; + } +} diff --git a/web/modules/paragraphs/icons/icon-view.svg b/web/modules/paragraphs/icons/icon-view.svg index d88023f4c5..e9ef7fcd0f 100644 --- a/web/modules/paragraphs/icons/icon-view.svg +++ b/web/modules/paragraphs/icons/icon-view.svg @@ -1,4 +1,4 @@ -<svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"> - <path class="bg" d="M0 0h24v24H0z" fill="none"/> - <path class="icon" d="M11.5 9C10.12 9 9 10.12 9 11.5s1.12 2.5 2.5 2.5 2.5-1.12 2.5-2.5S12.88 9 11.5 9zM20 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm-3.21 14.21l-2.91-2.91c-.69.44-1.51.7-2.39.7C9.01 16 7 13.99 7 11.5S9.01 7 11.5 7 16 9.01 16 11.5c0 .88-.26 1.69-.7 2.39l2.91 2.9-1.42 1.42z" fill="#1d84c3"/> +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg id="svg2" xmlns="http://www.w3.org/2000/svg" height="24" width="24" version="1.1" viewBox="0 0 24 24"> + <path id="path4" fill="#0074bd" d="m11.83 9l3.17 3.16v-0.16a3 3 0 0 0 -3 -3h-0.17m-4.3 0.8l1.55 1.55c-0.05 0.21-0.08 0.42-0.08 0.65a3 3 0 0 0 3 3c0.22 0 0.44-0.03 0.65-0.08l1.55 1.55c-0.67 0.33-1.41 0.53-2.2 0.53a5 5 0 0 1 -5 -5c0-0.79 0.2-1.53 0.53-2.2m-5.53-5.53l2.28 2.28 0.45 0.45c-1.65 1.3-2.95 3-3.73 5 1.73 4.39 6 7.5 11 7.5 1.55 0 3.03-0.3 4.38-0.84l0.43 0.42 2.92 2.92 1.27-1.27-17.73-17.73m8.73 4a5 5 0 0 1 5 5c0 0.64-0.13 1.26-0.36 1.82l2.93 2.93c1.5-1.25 2.7-2.89 3.43-4.75-1.73-4.39-6-7.5-11-7.5-1.4 0-2.74 0.25-4 0.7l2.17 2.15c0.57-0.22 1.18-0.35 1.83-0.35z"/> </svg> diff --git a/web/modules/paragraphs/js/paragraphs.actions.js b/web/modules/paragraphs/js/paragraphs.actions.js index 3fe7a6cbac..27e2d48f0d 100644 --- a/web/modules/paragraphs/js/paragraphs.actions.js +++ b/web/modules/paragraphs/js/paragraphs.actions.js @@ -28,8 +28,13 @@ $this.toggleClass('open'); }); - $toggle.on('focusout', function (e) { - $this.removeClass('open'); + $this.on('focusout', function (e) { + setTimeout(function () { + if ($this.has(document.activeElement).length == 0) { + // The focus left the action button group, hide actions. + $this.removeClass('open'); + } + }, 1); }); }); } diff --git a/web/modules/paragraphs/js/paragraphs.add_above_button.js b/web/modules/paragraphs/js/paragraphs.add_above_button.js index 14ed1bd816..cc49ca15f8 100644 --- a/web/modules/paragraphs/js/paragraphs.add_above_button.js +++ b/web/modules/paragraphs/js/paragraphs.add_above_button.js @@ -8,41 +8,44 @@ 'use strict'; /** - * Handle event when "Add above" button is clicked + * Handle event when "Add above" button is clicked. + * * @param event - * clickevent + * Click event. */ var clickHandler = function(event) { event.preventDefault(); var $button = $(this); - var $add_more_wrapper = $button.closest('table') - .siblings('.clearfix') - .find('.paragraphs-add-dialog'); - var delta = $button.closest('tr').index(); + var $add_more_wrapper = $button.closest('table').siblings('.clearfix').find('.paragraphs-add-dialog'); + + // Find delta for row without interference of unrelated table rows. + var $anchorRow = $button.closest('tr'); + var delta = $anchorRow.parent().find('> .draggable').index($anchorRow); // Set delta before opening of dialog. - var $delta = $add_more_wrapper.closest('.clearfix') - .find('.paragraph-type-add-modal-delta'); - $delta.val(delta); + $add_more_wrapper.parent().find('.paragraph-type-add-modal-delta').val(delta); + Drupal.paragraphsAddModal.openDialog($add_more_wrapper, Drupal.t('Add above')); }; /** * Process paragraph_AddAboveButton elements. + * + * @type {Drupal~behavior} */ Drupal.behaviors.paragraphsAddAboveButton = { attach: function (context, settings) { - var button = '<input class="paragraphs-dropdown-action paragraphs-dropdown-action--add-above button js-form-submit form-submit" type="submit" value="' + Drupal.t('Add above') + '">'; - var $actions = $(context).once().find('.paragraphs-dropdown-actions'); - $actions.each(function() { - if ($(this).closest('.paragraph-top').hasClass('add-above-on')) { - $(this).once().prepend(button); + $('.paragraphs-dropdown-actions', context).once('paragraphs-add-above-button').each(function () { + var $actions = $(this); + if ($actions.closest('.paragraph-top').hasClass('add-above-on')) { + var $button = $('<input class="paragraphs-dropdown-action paragraphs-dropdown-action--add-above button js-form-submit form-submit" type="submit" value="' + Drupal.t('Add above') + '">'); + // "Mousedown" is used since the original actions created by paragraphs + // use the event "focusout" to hide the actions dropdown. + $button.on('mousedown', clickHandler); + + $actions.prepend($button); } }); - var $addButtons = $actions.find('.paragraphs-dropdown-action--add-above'); - // "Mousedown" is used since the original actions created by paragraphs - // use the event "focusout" to hide the actions dropdown. - $addButtons.on('mousedown', clickHandler); } }; diff --git a/web/modules/paragraphs/js/paragraphs.admin.js b/web/modules/paragraphs/js/paragraphs.admin.js index 968d334e34..9b1ae6663a 100644 --- a/web/modules/paragraphs/js/paragraphs.admin.js +++ b/web/modules/paragraphs/js/paragraphs.admin.js @@ -24,8 +24,6 @@ $parWidget.removeClass('content-active').addClass('behavior-active'); $tabContent.removeClass('is-active'); $tabBehavior.addClass('is-active'); - $parContent.hide(); - $parBehavior.show(); } else { // Activate content tab visually if there is no previously @@ -33,12 +31,9 @@ if (!($mainRegion.hasClass('content-active')) && !($mainRegion.hasClass('behavior-active'))) { $tabContent.addClass('is-active'); - $mainRegion.addClass('content-active'); + $parWidget.addClass('content-active'); } - $parContent.show(); - $parBehavior.hide(); - $parTabs.show(); if ($parBehavior.length === 0) { $parTabs.hide(); @@ -58,27 +53,76 @@ var switchActiveClass = function ($parTabs, $clickedTab, $parWidget) { $parTabs.find('li').removeClass('is-active'); $clickedTab.parent('li').addClass('is-active'); - $parWidget.removeClass('behavior-active content-active is-active'); + $parWidget.removeClass('behavior-active content-active'); $($parWidget).find($clickedTab.attr('href')).addClass('is-active'); if ($parWidget.find('#content').hasClass('is-active')) { - $parWidget.find('.layout-region-node-main').addClass('content-active'); - $parWidget.find('.paragraphs-content').show(); - $parWidget.find('.paragraphs-behavior').hide(); + $parWidget.addClass('content-active'); + $parWidget.find('.paragraphs-add-wrapper').parent().removeClass('hidden'); + } + else if ($parWidget.find('#behavior').hasClass('is-active')) { + $parWidget.addClass('behavior-active'); + $parWidget.find('.paragraphs-add-wrapper').parent().addClass('hidden'); } + }; + + /** + * Add class to first paragraph in the viewport. + * + * In order to have a persistent position when switching tabs, + * we add a class to the first paragraph visible in the viewport. + */ + var markFirstVisibleParagraph = function (totalTopOffset) { + var $window = $(window); + var bottomOfScreen = $window.scrollTop() + $window.height(); + var topOfScreen = $window.scrollTop() + totalTopOffset; + var $firstParagraph = false; + // @todo Make sure to skip non-Paragraph draggable field widget items here. + var $allParagraphs = $('.node-form .draggable'); - if ($parWidget.find('#behavior').hasClass('is-active')) { - $parWidget.find('.layout-region-node-main').addClass('behavior-active'); - $parWidget.find('.paragraphs-content').hide(); - $parWidget.find('.paragraphs-behavior').show(); + $allParagraphs.each(function () { + var $this = $(this); + var topOfElement = $this.offset().top; + var bottomOfElement = $this.offset().top + $this.height(); + + // Search for paragraphs inside the viewport. + if ((bottomOfScreen > topOfElement) && (topOfScreen < bottomOfElement)) { + if ($firstParagraph) { + // Find next best Paragraph in Viewport. + if (topOfElement > topOfScreen ) { + // Second top in screen or first nested in screen. + $firstParagraph = $this; + return false; + } + else if(topOfElement > bottomOfScreen) { + // Choose previous element. + return false; + } + } + + $firstParagraph = $this; + if (topOfScreen < topOfElement) { + // Choose this element as it starts in viewport. + return false; + } } + }); + + if ($firstParagraph) { + // Remove potential previous marker. + $('.first-paragraph').removeClass('first-paragraph'); + // Add the class to the first paragraph in the viewport. + $firstParagraph.addClass('first-paragraph paragraph-hover'); + } + + return $firstParagraph; }; /** - * For body tag, adds tabs for selecting how the content will be displayed. - * - * @type {Drupal~behavior} - */ + * For body tag, adds tabs for selecting how the content will be displayed. + * + * @type {Drupal~behavior} + */ Drupal.behaviors.bodyTabs = { attach: function (context) { var $topLevelParWidgets = $('.paragraphs-tabs-wrapper', context).filter(function() { @@ -92,8 +136,39 @@ // Create click event. $parTabs.find('a').click(function(e) { + var toolbarHeight = $('.toolbar-tray-horizontal').outerHeight() || 0; + var adminToolbarsOffset = $('#toolbar-bar').outerHeight() + toolbarHeight; + var totalTopOffset = adminToolbarsOffset + $('.paragraphs-tabs').outerHeight(); + var $firstParagraph; + var currentParagraphOffset = 0; + var $window = $(window); + + $firstParagraph = markFirstVisibleParagraph(totalTopOffset); + + // Set the proper window position for each tab. + if ($firstParagraph) { + // Maintain vertical offset in addition to the toolbar heights. + currentParagraphOffset = $firstParagraph.offset().top - ($window.scrollTop() + totalTopOffset); + // Ignore a negative offset. + if (currentParagraphOffset < 0) { + currentParagraphOffset = 0; + } + } + e.preventDefault(); switchActiveClass($parTabs, $(this), $parWidget); + + // We need to check to which position to scroll to, whenever we need to scroll. + // If the first paragraph is the same, we maintain the scroll position, otherwise scroll to top of the paragraph. + if ($firstParagraph) { + $('html, body').scrollTop($firstParagraph.offset().top - totalTopOffset - currentParagraphOffset); + + // Reset the first paragraph class with a delay, in order for the background change to be visible. + setTimeout(function() { + $('.first-paragraph').removeClass('paragraph-hover'); + }, 1000); + } + }); }); diff --git a/web/modules/paragraphs/js/paragraphs.dragdrop.js b/web/modules/paragraphs/js/paragraphs.dragdrop.js index 3a8c33fba8..5373f6f863 100644 --- a/web/modules/paragraphs/js/paragraphs.dragdrop.js +++ b/web/modules/paragraphs/js/paragraphs.dragdrop.js @@ -80,19 +80,17 @@ * The Sortable event. */ function handleReorder(evt) { - var $item = $(evt.item); - var $parent = $item.closest('.paragraphs-dragdrop__list'); - var $children = $parent.children('li'); - var $srcParent = $(evt.to); - var $srcChildren = $srcParent.children('li'); - // Update both the source and target children. - updateWeightsAndPath($srcChildren); - updateWeightsAndPath($children); + if (evt.from === evt.to) { + updateWeightsAndPath($(evt.to).children('li')); + } + else { + updateWeightsAndPath($(evt.from).children('li')); + updateWeightsAndPath($(evt.to).children('li')); + } endDragClasses(); } - /** * Update weight and recursively update path of the provided paragraphs. * @@ -236,6 +234,12 @@ */ function startDragClasses() { $('html').addClass('is-dragging-paragraphs'); + // Fix race condition when the drag event start results in a scrollbar + // position change triggered by a collapsing item with children. Add a + // min-height for the current height as a workaround. + $('.paragraphs-dragdrop__list').eq(0).css('min-height', function() { + return $(this).height(); + }); } /** @@ -260,6 +264,8 @@ function endDragClasses() { $('html').removeClass('is-dragging-paragraphs'); $('.is-droppable-target').removeClass('is-droppable-target'); + // Remove the custom min-height definition added in startDragClasses(). + $('.paragraphs-dragdrop__list').eq(0).removeAttr('style'); } // Fix for an iOS 10 bug. Binding empty event handler on the touchmove diff --git a/web/modules/paragraphs/js/paragraphs.modal.js b/web/modules/paragraphs/js/paragraphs.modal.js index 55a12a2324..16128f17aa 100644 --- a/web/modules/paragraphs/js/paragraphs.modal.js +++ b/web/modules/paragraphs/js/paragraphs.modal.js @@ -3,28 +3,25 @@ * */ -(function ($, Drupal, drupalSettings) { +(function ($, Drupal) { 'use strict'; /** * Click handler for click "Add" button between paragraphs. * - * @type {Object} + * @type {Drupal~behavior} */ Drupal.behaviors.paragraphsModalAdd = { attach: function (context) { - $('.paragraph-type-add-modal-button', context) - .once('add-click-handler') - .on('click', function (event) { - var $button = $(this); - var $add_more_wrapper = $button.parent().siblings('.paragraphs-add-dialog'); - Drupal.paragraphsAddModal.openDialog($add_more_wrapper, $button.val()); + $('.paragraph-type-add-modal-button', context).once('add-click-handler').on('click', function (event) { + var $button = $(this); + Drupal.paragraphsAddModal.openDialog($button.parent().siblings('.paragraphs-add-dialog'), $button.val()); - // Stop default execution of click event. - event.preventDefault(); - event.stopPropagation(); - }); + // Stop default execution of click event. + event.preventDefault(); + event.stopPropagation(); + }); } }; @@ -38,41 +35,55 @@ /** * Open modal dialog for adding new paragraph in list. * - * @param {Object} $context - * jQuery element of form wrapper used to submit request for adding new - * paragraph to list. Wrapper also contains dialog template. + * @param {Object} element + * The element that holds the dialog. * @param {string} title - * The title of the modal form window. + * The title of the dialog. + * + * @return {Object} + * Dialog object. */ - Drupal.paragraphsAddModal.openDialog = function ($context, title) { + Drupal.paragraphsAddModal.openDialog = function (element, title) { + var $element = $(element); - $context.dialog({ - modal: true, + // Get the delta element before moving $element to dialog element. + var $modalDelta = $element.parent().find('.paragraph-type-add-modal-delta'); + + // Deep clone with all attached events. We need to work on cloned element + // and not directly on origin because Drupal dialog.ajax.js + // Drupal.behaviors.dialog will do remove of origin element on dialog close. + $element = $element.clone(true); + + var dialog = Drupal.dialog($element, { + // Turn off autoResize from dialog.position so draggable is not disabled. + autoResize: false, resizable: false, title: title, width: 'auto', - close: function () { - var $dialog = $(this); - - // Destroy dialog object. - $dialog.dialog('destroy'); - // Reset delta after destroying the dialog object. - var $delta = $dialog.closest('.clearfix') - .find('.paragraph-type-add-modal-delta'); - $delta.val(''); - } + paragraphsModalDelta: $modalDelta, }); + dialog.showModal(); // Close the dialog after a button was clicked. - $('.field-add-more-submit', $context) - .each(function () { - // Use mousedown event, because we are using ajax in the modal add mode - // which explicitly suppresses the click event. - $(this).on('mousedown', function () { - var $this = $(this); - $this.closest('div.ui-dialog-content').dialog('close'); - }); + // Use mousedown event, because we are using ajax in the modal add mode + // which explicitly suppresses the click event. + $element.once().find('.field-add-more-submit').on('mousedown', function () { + dialog.close(); }); + + return dialog; }; -}(jQuery, Drupal, drupalSettings)); + $(window).on({ + 'dialog:afterclose': function (event, dialog, $element) { + // Check first if dialog instance exist because dialog:afterclose will + // be triggered two times, first from once from dialog.ajax.js + // Drupal.behaviors.dialog and second time from dialog.js. + if ($element.dialog('instance') && $element.dialog('option', 'paragraphsModalDelta')) { + // Reset modal delta value. + $element.dialog('option', 'paragraphsModalDelta').val(''); + } + } + }); + +})(jQuery, Drupal); diff --git a/web/modules/paragraphs/modules/paragraphs_demo/config/install/paragraphs.paragraphs_type.text_image.yml b/web/modules/paragraphs/modules/paragraphs_demo/config/install/paragraphs.paragraphs_type.text_image.yml index 260d688c26..5ec43b62b3 100644 --- a/web/modules/paragraphs/modules/paragraphs_demo/config/install/paragraphs.paragraphs_type.text_image.yml +++ b/web/modules/paragraphs/modules/paragraphs_demo/config/install/paragraphs.paragraphs_type.text_image.yml @@ -3,4 +3,4 @@ status: true dependencies: { } id: text_image label: 'Text + Image' -description: 'Use <em>Test + Image</em> for adding a text on the left and an image on the right.' \ No newline at end of file +description: 'Use <em>Text + Image</em> for adding a text on the left and an image on the right.' \ No newline at end of file diff --git a/web/modules/paragraphs/modules/paragraphs_demo/paragraphs_demo.info.yml b/web/modules/paragraphs/modules/paragraphs_demo/paragraphs_demo.info.yml index de41a4d88d..6fc2685385 100644 --- a/web/modules/paragraphs/modules/paragraphs_demo/paragraphs_demo.info.yml +++ b/web/modules/paragraphs/modules/paragraphs_demo/paragraphs_demo.info.yml @@ -1,5 +1,5 @@ description: 'Provides multilingual demo Paragraphs types.' -# core: 8.x +core_version_requirement: ^8.7.7 || ^9 dependencies: - paragraphs:paragraphs - drupal:field @@ -21,8 +21,7 @@ name: Paragraphs Demo package: Paragraphs type: module -# Information added by Drupal.org packaging script on 2019-02-20 -version: '8.x-1.6' -core: '8.x' +# Information added by Drupal.org packaging script on 2020-02-16 +version: '8.x-1.11' project: 'paragraphs' -datestamp: 1550669588 +datestamp: 1581850832 diff --git a/web/modules/paragraphs/modules/paragraphs_demo/paragraphs_demo.install b/web/modules/paragraphs/modules/paragraphs_demo/paragraphs_demo.install index 8373cb80db..5c04a4db22 100644 --- a/web/modules/paragraphs/modules/paragraphs_demo/paragraphs_demo.install +++ b/web/modules/paragraphs/modules/paragraphs_demo/paragraphs_demo.install @@ -13,8 +13,10 @@ * Implements hook_install(). */ function paragraphs_demo_install() { - // Ensure the translation fields are created in the database. - \Drupal::service('entity.definition_update_manager')->applyUpdates(); + if (version_compare(\Drupal::VERSION, '8.6.99', '<=')) { + // Ensure the translation fields are created in the database. + \Drupal::service('entity.definition_update_manager')->applyUpdates(); + } // Create three paragraphs to structure the content. $paragraph = Paragraph::create([ diff --git a/web/modules/paragraphs/modules/paragraphs_demo/src/Tests/ParagraphsDemoTest.php b/web/modules/paragraphs/modules/paragraphs_demo/tests/src/Functional/ParagraphsDemoTest.php similarity index 94% rename from web/modules/paragraphs/modules/paragraphs_demo/src/Tests/ParagraphsDemoTest.php rename to web/modules/paragraphs/modules/paragraphs_demo/tests/src/Functional/ParagraphsDemoTest.php index d62cbb4f02..a4cb734666 100644 --- a/web/modules/paragraphs/modules/paragraphs_demo/src/Tests/ParagraphsDemoTest.php +++ b/web/modules/paragraphs/modules/paragraphs_demo/tests/src/Functional/ParagraphsDemoTest.php @@ -1,16 +1,16 @@ <?php -namespace Drupal\paragraphs_demo\Tests; +namespace Drupal\Tests\paragraphs_demo\Functional; -use Drupal\paragraphs\Tests\Classic\ParagraphsCoreVersionUiTestTrait; -use Drupal\simpletest\WebTestBase; +use Drupal\Tests\BrowserTestBase; +use Drupal\Tests\paragraphs\Traits\ParagraphsCoreVersionUiTestTrait; /** * Tests the demo module for Paragraphs. * * @group paragraphs */ -class ParagraphsDemoTest extends WebTestBase { +class ParagraphsDemoTest extends BrowserTestBase { use ParagraphsCoreVersionUiTestTrait; @@ -24,6 +24,11 @@ class ParagraphsDemoTest extends WebTestBase { 'block', ); + /** + * {@inheritdoc} + */ + protected $defaultTheme = 'stark'; + /** * {@inheritdoc} */ @@ -37,7 +42,7 @@ protected function setUp() { /** * Asserts demo paragraphs have been created. */ - protected function testConfigurationsAndCreation() { + public function testConfigurationsAndCreation() { // Assert that the demo page is displayed to anymous users. $this->drupalGet(''); @@ -76,7 +81,7 @@ protected function testConfigurationsAndCreation() { // Set edit mode to open. $this->drupalGet('admin/structure/types/manage/paragraphed_content_demo/form-display'); - $this->drupalPostAjaxForm(NULL, [], "field_paragraphs_demo_settings_edit"); + $this->drupalPostForm(NULL, [], "field_paragraphs_demo_settings_edit"); $edit = ['fields[field_paragraphs_demo][settings_edit_form][settings][edit_mode]' => 'open']; $this->drupalPostForm(NULL, $edit, t('Save')); diff --git a/web/modules/paragraphs/modules/paragraphs_library/config/optional/views.view.paragraphs_library_browser.yml b/web/modules/paragraphs/modules/paragraphs_library/config/optional/views.view.paragraphs_library_browser.yml index b1f79712e3..372e5d0629 100644 --- a/web/modules/paragraphs/modules/paragraphs_library/config/optional/views.view.paragraphs_library_browser.yml +++ b/web/modules/paragraphs/modules/paragraphs_library/config/optional/views.view.paragraphs_library_browser.yml @@ -166,6 +166,7 @@ display: hide_empty: false empty_zero: false hide_alter_empty: true + use_field_cardinality: true entity_type: paragraphs_library_item plugin_id: entity_browser_select label: diff --git a/web/modules/paragraphs/modules/paragraphs_library/paragraphs_library.info.yml b/web/modules/paragraphs/modules/paragraphs_library/paragraphs_library.info.yml index d1442c8b8b..6186fe0e98 100644 --- a/web/modules/paragraphs/modules/paragraphs_library/paragraphs_library.info.yml +++ b/web/modules/paragraphs/modules/paragraphs_library/paragraphs_library.info.yml @@ -1,7 +1,7 @@ name: Paragraphs Library type: module description: 'Provides a library for reusing paragraphs.' -# core: 8.x +core_version_requirement: ^8.7.7 || ^9 package: Paragraphs configure: paragraphs_library_item.settings dependencies: @@ -11,8 +11,7 @@ dependencies: test_dependencies: - entity_browser:entity_browser -# Information added by Drupal.org packaging script on 2019-02-20 -version: '8.x-1.6' -core: '8.x' +# Information added by Drupal.org packaging script on 2020-02-16 +version: '8.x-1.11' project: 'paragraphs' -datestamp: 1550669588 +datestamp: 1581850832 diff --git a/web/modules/paragraphs/modules/paragraphs_library/paragraphs_library.install b/web/modules/paragraphs/modules/paragraphs_library/paragraphs_library.install index 1e66860898..1751ed9f35 100644 --- a/web/modules/paragraphs/modules/paragraphs_library/paragraphs_library.install +++ b/web/modules/paragraphs/modules/paragraphs_library/paragraphs_library.install @@ -6,7 +6,6 @@ */ use Drupal\Core\Entity\Entity\EntityFormDisplay; -use Drupal\Core\Entity\Entity\EntityViewDisplay; use Drupal\Core\Field\BaseFieldDefinition; use Drupal\field\Entity\FieldConfig; use Drupal\paragraphs_library\Entity\LibraryItem; @@ -45,6 +44,20 @@ function paragraphs_library_install() { $entity_usage_config->set('local_task_enabled_entity_types', $tabs_enabled) ->save(); } + + // Enable the usage warning message on edit and delete forms. + $edit_warning_enabled = $entity_usage_config->get('edit_warning_message_entity_types') ?: []; + if (!in_array('paragraphs_library_item', $edit_warning_enabled)) { + $edit_warning_enabled[] = 'paragraphs_library_item'; + $entity_usage_config->set('edit_warning_message_entity_types', $edit_warning_enabled) + ->save(); + } + $delete_warning_enabled = $entity_usage_config->get('delete_warning_message_entity_types') ?: []; + if (!in_array('paragraphs_library_item', $delete_warning_enabled)) { + $delete_warning_enabled[] = 'paragraphs_library_item'; + $entity_usage_config->set('delete_warning_message_entity_types', $delete_warning_enabled) + ->save(); + } } /** @@ -52,7 +65,7 @@ function paragraphs_library_install() { */ function paragraphs_library_update_8001() { - \Drupal::service('entity.manager')->clearCachedDefinitions(); + \Drupal::service('entity_type.manager')->clearCachedDefinitions(); // Load all library items and store their values in memory. $library_values = \Drupal::database()->query('SELECT * FROM {paragraphs_library_item}')->fetchAll(PDO::FETCH_ASSOC); @@ -87,7 +100,6 @@ function paragraphs_library_update_8001() { ->setRevisionable(TRUE) ->setTranslatable(TRUE); - $default_langcode_field = BaseFieldDefinition::create('boolean') ->setLabel(t('Default translation')) ->setDescription(t('A flag indicating whether this is the default translation.')) @@ -98,7 +110,7 @@ function paragraphs_library_update_8001() { $entity_definition_update_manager->installFieldStorageDefinition('langcode', $entity_type->id(), 'paragraphs_library', $langcode_field); $entity_definition_update_manager->installFieldStorageDefinition('default_langcode', $entity_type->id(), 'paragraphs_library', $default_langcode_field); - \Drupal::entityManager()->clearCachedDefinitions(); + \Drupal::entityTypeManager()->clearCachedDefinitions(); foreach ($library_values as $library_value) { $library_value['paragraphs'] = [ 'target_id' => $library_value['paragraphs__target_id'], @@ -339,3 +351,22 @@ function paragraphs_library_update_8101() { ->save(); } } + +/** + * Enable the usage warning message on edit and delete forms. + */ +function paragraphs_library_update_8102() { + $entity_usage_config = \Drupal::configFactory()->getEditable('entity_usage.settings'); + $edit_warning_enabled = $entity_usage_config->get('edit_warning_message_entity_types') ?: []; + if (!in_array('paragraphs_library_item', $edit_warning_enabled)) { + $edit_warning_enabled[] = 'paragraphs_library_item'; + $entity_usage_config->set('edit_warning_message_entity_types', $edit_warning_enabled) + ->save(); + } + $delete_warning_enabled = $entity_usage_config->get('delete_warning_message_entity_types') ?: []; + if (!in_array('paragraphs_library_item', $delete_warning_enabled)) { + $delete_warning_enabled[] = 'paragraphs_library_item'; + $entity_usage_config->set('delete_warning_message_entity_types', $delete_warning_enabled) + ->save(); + } +} diff --git a/web/modules/paragraphs/modules/paragraphs_library/paragraphs_library.module b/web/modules/paragraphs/modules/paragraphs_library/paragraphs_library.module index 43436e4a23..8c55ac14a6 100644 --- a/web/modules/paragraphs/modules/paragraphs_library/paragraphs_library.module +++ b/web/modules/paragraphs/modules/paragraphs_library/paragraphs_library.module @@ -155,21 +155,6 @@ function paragraphs_library_views_pre_render(ViewExecutable $view) { } } -/** - * Implements hook_form_FORM_ID_alter(). - */ -function paragraphs_library_form_paragraphs_library_item_edit_form_alter(&$form, FormStateInterface $form_state, $form_id) { - $library_item = $form_state->getFormObject()->getEntity(); - $usage_data = \Drupal::service('entity_usage.usage')->listSources($library_item); - - if ($usage_data) { - $usage_count = _paragraphs_library_count_usage($usage_data); - \Drupal::messenger()->addWarning(\Drupal::translation()->formatPlural($usage_count, 'Library item is used 1 time.', 'Library item is used @count times.', [ - '@count' => $usage_count, - ])); - } -} - /** * Counts the usage across all entities. * @@ -256,7 +241,7 @@ function paragraphs_library_library_item_unlink_submit(array $form, FormStateInt // Make a copy of the paragraph. Use the Replicate module, if it is enabled. /** @var \Drupal\Core\Entity\EntityInterface $original_paragraph */ if (\Drupal::hasService('replicate.replicator')) { - $duplicate_paragraph = \Drupal::getContainer()->get('replicate.replicator')->replicateEntity($original_paragraph); + $duplicate_paragraph = \Drupal::getContainer()->get('replicate.replicator')->cloneEntity($original_paragraph); } else { $duplicate_paragraph = $original_paragraph->createDuplicate(); diff --git a/web/modules/paragraphs/modules/paragraphs_library/src/Controller/LibraryItemController.php b/web/modules/paragraphs/modules/paragraphs_library/src/Controller/LibraryItemController.php index 366e23effe..302f06063f 100644 --- a/web/modules/paragraphs/modules/paragraphs_library/src/Controller/LibraryItemController.php +++ b/web/modules/paragraphs/modules/paragraphs_library/src/Controller/LibraryItemController.php @@ -6,9 +6,7 @@ use Drupal\Core\Controller\ControllerBase; use Drupal\Core\Datetime\DateFormatterInterface; use Drupal\Core\DependencyInjection\ContainerInjectionInterface; -use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; -use Drupal\Core\Url; use Drupal\paragraphs_library\Entity\LibraryItem; use Drupal\paragraphs_library\LibraryItemInterface; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -191,4 +189,5 @@ protected function getRevisionIds(LibraryItemInterface $library_item) { ->execute(); return array_keys($result); } + } diff --git a/web/modules/paragraphs/modules/paragraphs_library/src/Entity/LibraryItem.php b/web/modules/paragraphs/modules/paragraphs_library/src/Entity/LibraryItem.php index f0641630cc..3dfe46a230 100644 --- a/web/modules/paragraphs/modules/paragraphs_library/src/Entity/LibraryItem.php +++ b/web/modules/paragraphs/modules/paragraphs_library/src/Entity/LibraryItem.php @@ -17,6 +17,13 @@ * @ContentEntityType( * id = "paragraphs_library_item", * label = @Translation("Paragraphs library item"), + * label_collection = @Translation("Paragraphs library items"), + * label_singular = @Translation("Paragraphs library item"), + * label_plural = @Translation("Paragraphs library items"), + * label_count = @PluralTranslation( + * singular = "@count Paragraphs library item", + * plural = "@count Paragraphs library items", + * ), * handlers = { * "view_builder" = "Drupal\Core\Entity\EntityViewBuilder", * "list_builder" = "Drupal\Core\Entity\EntityListBuilder", @@ -255,19 +262,18 @@ public static function createFromParagraph(ParagraphInterface $paragraph) { } $duplicate_paragraph->save(); - $label = static::buildLabel($paragraph); $library_item = static::create([ - 'label' => $label, 'paragraphs' => $duplicate_paragraph, + 'langcode' => $paragraph->language()->getId(), ]); - // Add a translation for each translation the paragraph has, the only - // translatable element is the label. The referenced paragraph keeps the - // existing translations. - foreach ($duplicate_paragraph->getTranslationLanguages(FALSE) as $langcode => $language) { - $library_item->addTranslation($langcode, [ - 'label' => static::buildLabel($duplicate_paragraph->getTranslation($langcode)) - ] + $library_item->toArray()); + // Build the label in each available translation and ensure the translations + // exist. + foreach ($duplicate_paragraph->getTranslationLanguages() as $langcode => $language) { + if (!$library_item->hasTranslation($langcode)) { + $library_item->addTranslation($langcode, $library_item->toArray()); + } + $library_item->getTranslation($langcode)->set('label', static::buildLabel($duplicate_paragraph->getTranslation($langcode))); } return $library_item; @@ -282,8 +288,8 @@ public static function createFromParagraph(ParagraphInterface $paragraph) { * @return string */ protected static function buildLabel(ParagraphInterface $paragraph) { - $summary = $paragraph->getSummary(['show_behavior_summary' => FALSE]); - $summary = Unicode::truncate($summary, 50); + $summary = $paragraph->getSummaryItems(['show_behavior_summary' => FALSE]); + $summary = Unicode::truncate(implode(', ', $summary['content']), 50); return $paragraph->getParagraphType()->label() . ': ' . $summary; } diff --git a/web/modules/paragraphs/modules/paragraphs_library/src/Form/LibraryItemForm.php b/web/modules/paragraphs/modules/paragraphs_library/src/Form/LibraryItemForm.php index 93a392dd67..a2ed4c6124 100644 --- a/web/modules/paragraphs/modules/paragraphs_library/src/Form/LibraryItemForm.php +++ b/web/modules/paragraphs/modules/paragraphs_library/src/Form/LibraryItemForm.php @@ -3,10 +3,10 @@ namespace Drupal\paragraphs_library\Form; use Drupal\Core\Entity\ContentEntityForm; +use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Form\FormStateInterface; -use Drupal\Core\Messenger\Messenger; +use Drupal\Core\Messenger\MessengerInterface; use Symfony\Component\DependencyInjection\ContainerInterface; -use Drupal\Core\Entity\EntityManagerInterface; use Drupal\Core\Entity\EntityTypeBundleInfoInterface; use Drupal\Component\Datetime\TimeInterface; @@ -21,39 +21,25 @@ class LibraryItemForm extends ContentEntityForm { protected $entity; /** - * Provides messenger service. - * - * @var \Drupal\Core\Messenger\Messenger - */ - protected $messenger; - - /** - * Constructs a LibraryItemForm object. - * - * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager - * The entity manager. - * @param \Drupal\Core\Messenger\Messenger $messenger - * The messenger service. - * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info - * The entity type bundle service. - * @param \Drupal\Component\Datetime\TimeInterface $time - * The time service. + * {@inheritdoc} */ - public function __construct(EntityManagerInterface $entity_manager, Messenger $messenger, EntityTypeBundleInfoInterface $entity_type_bundle_info = NULL, TimeInterface $time = NULL) { - parent::__construct($entity_manager, $entity_type_bundle_info, $time); - $this->messenger = $messenger; + public function getFormId() { + // If the entity is not new, add the entity id. This will allow having more + // than one form open when editing a library item within another. + // To alter this form use hook_form_BASE_FORM_ID_alter. + if ($this->entity->id()) { + return 'paragraphs_library_item_edit_form_' . $this->entity->id(); + } + return 'paragraphs_library_item_edit_form'; } /** * {@inheritdoc} */ public static function create(ContainerInterface $container) { - return new static( - $container->get('entity.manager'), - $container->get('messenger'), - $container->get('entity_type.bundle.info'), - $container->get('datetime.time') - ); + $form = parent::create($container); + $form->setMessenger($container->get('messenger')); + return $form; } /** diff --git a/web/modules/paragraphs/modules/paragraphs_library/src/Form/LibraryItemRevisionDeleteForm.php b/web/modules/paragraphs/modules/paragraphs_library/src/Form/LibraryItemRevisionDeleteForm.php index 1d733468b0..33dc748246 100644 --- a/web/modules/paragraphs/modules/paragraphs_library/src/Form/LibraryItemRevisionDeleteForm.php +++ b/web/modules/paragraphs/modules/paragraphs_library/src/Form/LibraryItemRevisionDeleteForm.php @@ -6,7 +6,7 @@ use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Form\ConfirmFormBase; use Drupal\Core\Form\FormStateInterface; -use Drupal\Core\Messenger\Messenger; +use Drupal\Core\Messenger\MessengerInterface; use Drupal\Core\Url; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -47,10 +47,10 @@ class LibraryItemRevisionDeleteForm extends ConfirmFormBase { * The entity type manager service. * @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter * The date formatter service. - * @param \Drupal\Core\Messenger\Messenger $messenger + * @param \Drupal\Core\Messenger\MessengerInterface $messenger * The messenger service. */ - public function __construct(EntityTypeManagerInterface $entity_type_manager, DateFormatterInterface $date_formatter, Messenger $messenger) { + public function __construct(EntityTypeManagerInterface $entity_type_manager, DateFormatterInterface $date_formatter, MessengerInterface $messenger) { $this->entityTypeManager = $entity_type_manager; $this->dateFormatter = $date_formatter; $this->messenger = $messenger; diff --git a/web/modules/paragraphs/modules/paragraphs_library/src/Form/LibraryItemRevisionRevertForm.php b/web/modules/paragraphs/modules/paragraphs_library/src/Form/LibraryItemRevisionRevertForm.php index 2eb88f9d66..3d2f3fb61e 100644 --- a/web/modules/paragraphs/modules/paragraphs_library/src/Form/LibraryItemRevisionRevertForm.php +++ b/web/modules/paragraphs/modules/paragraphs_library/src/Form/LibraryItemRevisionRevertForm.php @@ -7,7 +7,7 @@ use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Form\ConfirmFormBase; use Drupal\Core\Form\FormStateInterface; -use Drupal\Core\Messenger\Messenger; +use Drupal\Core\Messenger\MessengerInterface; use Drupal\Core\Url; use Drupal\paragraphs_library\LibraryItemInterface; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -58,10 +58,10 @@ class LibraryItemRevisionRevertForm extends ConfirmFormBase { * The date formatter service. * @param \Drupal\Component\Datetime\TimeInterface $time * The time service. - * @param \Drupal\Core\Messenger\Messenger $messenger + * @param \Drupal\Core\Messenger\MessengerInterface $messenger * The messenger service. */ - public function __construct(EntityTypeManagerInterface $entity_type_manager, DateFormatterInterface $date_formatter, TimeInterface $time, Messenger $messenger) { + public function __construct(EntityTypeManagerInterface $entity_type_manager, DateFormatterInterface $date_formatter, TimeInterface $time, MessengerInterface $messenger) { $this->entityTypeManager = $entity_type_manager; $this->dateFormatter = $date_formatter; $this->time = $time; diff --git a/web/modules/paragraphs/modules/paragraphs_library/src/LibraryItemAccessControlHandler.php b/web/modules/paragraphs/modules/paragraphs_library/src/LibraryItemAccessControlHandler.php index 7c2e5b0e3e..2260ed16e5 100644 --- a/web/modules/paragraphs/modules/paragraphs_library/src/LibraryItemAccessControlHandler.php +++ b/web/modules/paragraphs/modules/paragraphs_library/src/LibraryItemAccessControlHandler.php @@ -19,13 +19,6 @@ class LibraryItemAccessControlHandler extends EntityAccessControlHandler { * {@inheritdoc} */ protected function checkAccess(EntityInterface $library_item, $operation, AccountInterface $account) { - if ($operation == 'delete') { - $usage_data = \Drupal::service('entity_usage.usage')->listSources($library_item); - if ($usage_data) { - return AccessResult::forbidden(); - } - } - // In case a library item is unpublished, only allow access if a user has // administrative permission. Ensure to collect the required cacheability // metadata and combine both the published and the referenced access check diff --git a/web/modules/paragraphs/modules/paragraphs_library/src/Plugin/Validation/Constraint/ParagraphsLibraryItemHasAllowedParagraphsTypeConstraintValidator.php b/web/modules/paragraphs/modules/paragraphs_library/src/Plugin/Validation/Constraint/ParagraphsLibraryItemHasAllowedParagraphsTypeConstraintValidator.php index c216340c27..195dd07b0c 100644 --- a/web/modules/paragraphs/modules/paragraphs_library/src/Plugin/Validation/Constraint/ParagraphsLibraryItemHasAllowedParagraphsTypeConstraintValidator.php +++ b/web/modules/paragraphs/modules/paragraphs_library/src/Plugin/Validation/Constraint/ParagraphsLibraryItemHasAllowedParagraphsTypeConstraintValidator.php @@ -94,23 +94,25 @@ public function validate($value, Constraint $constraint) { /** @var \Drupal\paragraphs_library\LibraryItemInterface $library_item_entity */ foreach ($paragraph->get($field_name) as $entity_reference_item) { // Get the Paragraphs type of the library item. - $library_item_entity = $entity_reference_item->entity; - $used_paragraphs_type = $library_item_entity->get('paragraphs')->entity->getType(); - - // Check if the Paragraphs type of the item is not allowed in the - // field holding the parent Paragraph. - if (in_array($used_paragraphs_type, $allowed_paragraphs_types)) { - continue; + if ($library_item_entity = $entity_reference_item->entity) { + if ($used_paragraphs = $library_item_entity->get('paragraphs')->entity) { + $used_paragraphs_type = $used_paragraphs->getType(); + // Check if the Paragraphs type of the item is not allowed in the + // field holding the parent Paragraph. + if (in_array($used_paragraphs_type, $allowed_paragraphs_types)) { + continue; + } + + $paragraphs_type_entity = $this->entityTypeManager->getStorage('paragraphs_type')->load($used_paragraphs_type); + + $this->context->addViolation($constraint->message, [ + '@library_item_field_label' => $field_definition->getLabel(), + '@paragraphs_type_label' => $paragraphs_type_entity->label(), + '@paragraph_field_label' => $value->getFieldDefinition()->getLabel(), + ]); + } } - $paragraphs_type_entity = $this->entityTypeManager->getStorage('paragraphs_type')->load($used_paragraphs_type); - - $this->context->addViolation($constraint->message, [ - '@library_item_field_label' => $field_definition->getLabel(), - '@paragraphs_type_label' => $paragraphs_type_entity->label(), - '@paragraph_field_label' => $value->getFieldDefinition()->getLabel(), - ]); - } } } diff --git a/web/modules/paragraphs/modules/paragraphs_library/src/Tests/MultilingualBehaviorTest.php b/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/MultilingualBehaviorTest.php similarity index 88% rename from web/modules/paragraphs/modules/paragraphs_library/src/Tests/MultilingualBehaviorTest.php rename to web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/MultilingualBehaviorTest.php index 8454c9a92b..8e87363ead 100644 --- a/web/modules/paragraphs/modules/paragraphs_library/src/Tests/MultilingualBehaviorTest.php +++ b/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/MultilingualBehaviorTest.php @@ -1,9 +1,9 @@ <?php -namespace Drupal\paragraphs_library\Tests; +namespace Drupal\Tests\paragraphs_library\Functional; use Drupal\language\Entity\ConfigurableLanguage; -use Drupal\paragraphs\Tests\Experimental\ParagraphsExperimentalTestBase; +use Drupal\Tests\paragraphs\Functional\Experimental\ParagraphsExperimentalTestBase; /** * Tests paragraphs library multilingual functionality. @@ -79,8 +79,8 @@ public function setUp() { public function testReuseTranslationForNestedParagraphFromLibrary() { // Add nested paragraph directly in library. $this->drupalGet('admin/content/paragraphs/add/default'); - $this->drupalPostAjaxForm(NULL, NULL, 'paragraphs_nested_paragraph_add_more'); - $this->drupalPostAjaxForm(NULL, NULL, 'paragraphs_0_subform_field_err_field_test_content_add_more'); + $this->drupalPostForm(NULL, NULL, 'paragraphs_nested_paragraph_add_more'); + $this->drupalPostForm(NULL, NULL, 'paragraphs_0_subform_field_err_field_test_content_add_more'); $edit = [ 'label[0][value]' => 'En label Test nested paragraph', 'paragraphs[0][subform][field_err_field][0][subform][field_paragraphs_text][0][value]' => 'En label Example text for test in nested paragraph.', @@ -99,7 +99,7 @@ public function testReuseTranslationForNestedParagraphFromLibrary() { // Create test content. $this->drupalGet('node/add/paragraphed_test'); - $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_from_library_add_more'); + $this->drupalPostForm(NULL, NULL, 'field_paragraphs_from_library_add_more'); $edit = [ 'title[0][value]' => 'En label Test node nested', 'field_paragraphs[0][subform][field_reusable_paragraph][0][target_id]' => 'En label Test nested paragraph', @@ -138,8 +138,8 @@ public function testMoveTranslatedNestedParagraphToLibrary() { // Add node with text paragraph. $this->drupalGet('node/add/paragraphed_test'); - $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_nested_paragraph_add_more'); - $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_0_subform_field_err_field_test_content_add_more'); + $this->drupalPostForm(NULL, NULL, 'field_paragraphs_nested_paragraph_add_more'); + $this->drupalPostForm(NULL, NULL, 'field_paragraphs_0_subform_field_err_field_test_content_add_more'); $edit = [ 'title[0][value]' => 'En label Test node nested', 'field_paragraphs[0][subform][field_err_field][0][subform][field_paragraphs_text][0][value]' => 'En label Example text for test in nested paragraph', @@ -158,7 +158,7 @@ public function testMoveTranslatedNestedParagraphToLibrary() { // Convert translated paragraph to library. $this->drupalGet($node->toUrl('edit-form')); - $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_0_promote_to_library'); + $this->drupalPostForm(NULL, NULL, 'field_paragraphs_0_promote_to_library'); $this->drupalPostForm(NULL, NULL, 'Save (this translation)'); // Check translation. @@ -181,8 +181,8 @@ public function testDetachTranslatedNestedParagraphItemFromLibrary() { // Add paragraph directly in library. $this->drupalGet('admin/content/paragraphs/add/default'); - $this->drupalPostAjaxForm(NULL, NULL, 'paragraphs_nested_paragraph_add_more'); - $this->drupalPostAjaxForm(NULL, NULL, 'paragraphs_0_subform_field_err_field_test_content_add_more'); + $this->drupalPostForm(NULL, NULL, 'paragraphs_nested_paragraph_add_more'); + $this->drupalPostForm(NULL, NULL, 'paragraphs_0_subform_field_err_field_test_content_add_more'); $edit = [ 'label[0][value]' => 'En label Test nested paragraph', 'paragraphs[0][subform][field_err_field][0][subform][field_paragraphs_text][0][value]' => 'En label Example text for test.' @@ -201,7 +201,7 @@ public function testDetachTranslatedNestedParagraphItemFromLibrary() { // Create test content. $this->drupalGet('node/add/paragraphed_test'); - $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_from_library_add_more'); + $this->drupalPostForm(NULL, NULL, 'field_paragraphs_from_library_add_more'); $edit = [ 'title[0][value]' => 'En label Test node nested', 'field_paragraphs[0][subform][field_reusable_paragraph][0][target_id]' => 'En label Test nested paragraph', @@ -225,7 +225,7 @@ public function testDetachTranslatedNestedParagraphItemFromLibrary() { $this->drupalGet('node/' . $node->id()); $this->assertText('En label Example text for test.'); $this->clickLink('Edit'); - $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_0_unlink_from_library'); + $this->drupalPostForm(NULL, NULL, 'field_paragraphs_0_unlink_from_library'); $this->assertText('En label Example text for test.'); } @@ -237,8 +237,8 @@ public function testDetachBeforeTranslation() { // Add paragraph directly in library. $this->drupalGet('admin/content/paragraphs/add/default'); - $this->drupalPostAjaxForm(NULL, NULL, 'paragraphs_nested_paragraph_add_more'); - $this->drupalPostAjaxForm(NULL, NULL, 'paragraphs_0_subform_field_err_field_test_content_add_more'); + $this->drupalPostForm(NULL, NULL, 'paragraphs_nested_paragraph_add_more'); + $this->drupalPostForm(NULL, NULL, 'paragraphs_0_subform_field_err_field_test_content_add_more'); $edit = [ 'label[0][value]' => 'En label Test nested paragraph', 'paragraphs[0][subform][field_err_field][0][subform][field_paragraphs_text][0][value]' => 'En label Example text for test.' @@ -257,12 +257,12 @@ public function testDetachBeforeTranslation() { // Create test content. $this->drupalGet('node/add/paragraphed_test'); - $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_from_library_add_more'); + $this->drupalPostForm(NULL, NULL, 'field_paragraphs_from_library_add_more'); $edit = [ 'title[0][value]' => 'En label Test node nested', 'field_paragraphs[0][subform][field_reusable_paragraph][0][target_id]' => 'En label Test nested paragraph', ]; - $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_0_unlink_from_library'); + $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_unlink_from_library'); $edit = [ 'title[0][value]' => 'En label Test node nested', ]; diff --git a/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/ParagraphsLibraryItemTest.php b/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/ParagraphsLibraryItemTest.php index 7853987a0c..1e91637d12 100644 --- a/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/ParagraphsLibraryItemTest.php +++ b/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/ParagraphsLibraryItemTest.php @@ -2,11 +2,11 @@ namespace Drupal\Tests\paragraphs_library\Functional; -use Drupal\field_ui\Tests\FieldUiTestTrait; use Drupal\node\Entity\Node; use Drupal\paragraphs\Entity\Paragraph; use Drupal\paragraphs\Entity\ParagraphsType; use Drupal\Tests\BrowserTestBase; +use Drupal\Tests\field_ui\Traits\FieldUiTestTrait; use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait; /** @@ -30,6 +30,11 @@ class ParagraphsLibraryItemTest extends BrowserTestBase { 'field_ui', ]; + /** + * {@inheritdoc} + */ + protected $defaultTheme = 'classy'; + /** * {@inheritdoc} */ @@ -293,6 +298,7 @@ public function testLibraryItemUsageTab() { $assert_session->elementContains('css', 'table tbody tr td:nth-child(2)', 'Paragraph'); $assert_session->elementContains('css', 'table tbody tr td:nth-child(3)', 'English'); $assert_session->elementContains('css', 'table tbody tr td:nth-child(4)', 'Reusable paragraph'); + $assert_session->elementContains('css', 'table tbody tr td:nth-child(5)', 'Published'); // Assert breadcrumb. $assert_session->elementContains('css', '.breadcrumb ol li:nth-child(1)', 'Home'); @@ -311,13 +317,48 @@ public function testLibraryItemUsageTab() { $this->clickLink('Usage'); $assert_session->pageTextContains('Entity usage information for Test usage nested paragraph'); - // No usage shows up on this page. - // @todo once 2954039 lands, we expect to have a row here indicating that - // the host node references the paragraph in a non-default revision. - // Alternatively, if 2971131 lands first, we would have here an extra row - // with possibly a generic label (just with the entity ID or similar). In - // both cases this test will need to be updated. - $assert_session->elementNotExists('css', 'table tbody tr'); + // Assert there is a row here indicating that the host node references the + // paragraph in a non-default revision. + $assert_session->elementContains('css', 'table tbody tr td:nth-child(1)', 'Test content > field_paragraphs (previous revision)'); + $assert_session->elementContains('css', 'table tbody tr td:nth-child(2)', 'Paragraph'); + $assert_session->elementContains('css', 'table tbody tr td:nth-child(3)', 'English'); + $assert_session->elementContains('css', 'table tbody tr td:nth-child(4)', 'Reusable paragraph'); + $assert_session->elementContains('css', 'table tbody tr td:nth-child(5)', 'Published'); + } + + /** + * Test if the usage warning message shows up, when deleting a library item. + */ + public function testLibraryItemDeleteWarningMessage() { + $page = $this->getSession()->getPage(); + $assert_session = $this->assertSession(); + + // Create a paragraph in the library. + $this->drupalGet('admin/content/paragraphs/add/default'); + $page->pressButton('Add text'); + + $edit = [ + 'label[0][value]' => 'Test usage warning message', + 'paragraphs[0][subform][field_text][0][value]' => 'Example text.', + ]; + $this->drupalPostForm(NULL, $edit, 'Save'); + $assert_session->pageTextContains('Paragraph Test usage warning message has been created.'); + + // Create content with referenced paragraph. + $this->drupalGet('node/add/paragraphed_test'); + $page->pressButton('Add From library'); + $edit = [ + 'title[0][value]' => 'Test content', + 'field_paragraphs[0][subform][field_reusable_paragraph][0][target_id]' => 'Test usage warning message', + ]; + $this->drupalPostForm(NULL, $edit, 'Save'); + + $node = $this->drupalGetNodeByTitle('Test content'); + $library_item = $node->get('field_paragraphs')->entity->get('field_reusable_paragraph')->entity; + + // Check if there is a warning message on the delete form. + $this->drupalGet('/admin/content/paragraphs/' . $library_item->id() . '/delete'); + $assert_session->pageTextContains('There are recorded usages of this entity.'); } } diff --git a/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/ParagraphsLibraryItemTranslationTest.php b/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/ParagraphsLibraryItemTranslationTest.php index fb1ca21730..3fd2014f97 100644 --- a/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/ParagraphsLibraryItemTranslationTest.php +++ b/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/ParagraphsLibraryItemTranslationTest.php @@ -2,7 +2,7 @@ namespace Drupal\Tests\paragraphs_library\Functional; -use Drupal\field_ui\Tests\FieldUiTestTrait; +use Drupal\Tests\field_ui\Traits\FieldUiTestTrait; use Drupal\language\Entity\ConfigurableLanguage; use Drupal\paragraphs\Entity\ParagraphsType; use Drupal\Tests\BrowserTestBase; @@ -36,6 +36,11 @@ class ParagraphsLibraryItemTranslationTest extends BrowserTestBase { 'content_translation', ]; + /** + * {@inheritdoc} + */ + protected $defaultTheme = 'stark'; + /** * {@inheritdoc} */ @@ -85,6 +90,7 @@ public function testLibraryItemTranslation() { 'settings[paragraph][text][translatable]' => TRUE, 'settings[paragraph][text][fields][field_text]' => TRUE, 'settings[paragraphs_library_item][paragraphs_library_item][translatable]' => TRUE, + 'settings[node][paragraphed_test][settings][language][language_alterable]' => TRUE ]; $this->drupalPostForm('admin/config/regional/content-language', $edit, t('Save configuration')); @@ -143,6 +149,37 @@ public function testLibraryItemTranslation() { $this->clickLink('Edit', 1); $assert_session->fieldValueEquals('Label', 'text: DE Library text'); $assert_session->fieldValueEquals('Text', 'DE Library text'); + + // Add a node with a text paragraph. + $this->drupalGet('node/add/paragraphed_test'); + $this->drupalPostForm(NULL, NULL, 'Add text'); + $edit = [ + 'title[0][value]' => 'DE Llama Test', + 'langcode[0][value]' => 'de', + 'field_paragraphs[0][subform][field_text][0][value]' => 'DE Text Paragraph', + ]; + $this->drupalPostForm(NULL, $edit, 'Save'); + $assert_session->pageTextContains('paragraphed_test DE Llama Test has been created.'); + + // Translate the node to the default language. + $this->clickLink('Translate'); + $this->clickLink('Add'); + $edit = [ + 'title[0][value]' => 'EN Llama Test', + 'field_paragraphs[0][subform][field_text][0][value]' => 'EN Library text', + ]; + $this->drupalPostForm(NULL, $edit, 'Save (this translation)'); + $assert_session->pageTextContains('paragraphed_test EN Llama Test has been updated.'); + + // Assert the original node can promote paragraphs to the library. + $node = $this->drupalGetNodeByTitle('DE Llama Test'); + $this->drupalGet('de/node/' . $node->id() . '/edit'); + $page->pressButton('field_paragraphs_0_promote_to_library'); + $assert_session->fieldValueEquals('Reusable paragraph', 'text: DE Text Paragraph (2)'); + $this->drupalPostForm(NULL, NULL, 'Save'); + $assert_session->pageTextContains('paragraphed_test DE Llama Test has been updated.'); + $this->drupalGet('node/' . $node->id() . '/edit'); + $assert_session->pageTextContains('Reusable paragraph'); } } diff --git a/web/modules/paragraphs/modules/paragraphs_library/src/Tests/ParagraphsLibraryItemTest.php b/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/ParagraphsLibraryTest.php similarity index 88% rename from web/modules/paragraphs/modules/paragraphs_library/src/Tests/ParagraphsLibraryItemTest.php rename to web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/ParagraphsLibraryTest.php index b74f5686bc..5986cf5623 100644 --- a/web/modules/paragraphs/modules/paragraphs_library/src/Tests/ParagraphsLibraryItemTest.php +++ b/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/ParagraphsLibraryTest.php @@ -1,19 +1,16 @@ <?php -namespace Drupal\paragraphs_library\Tests; +namespace Drupal\Tests\paragraphs_library\Functional; use Drupal\Core\Url; -use Drupal\field_ui\Tests\FieldUiTestTrait; -use Drupal\paragraphs\Tests\Experimental\ParagraphsExperimentalTestBase; +use Drupal\Tests\paragraphs\Functional\Experimental\ParagraphsExperimentalTestBase; /** * Tests paragraphs library functionality. * * @group paragraphs_library */ -class ParagraphsLibraryItemTest extends ParagraphsExperimentalTestBase { - - use FieldUiTestTrait; +class ParagraphsLibraryTest extends ParagraphsExperimentalTestBase { /** * Modules to enable. @@ -38,7 +35,7 @@ protected function setUp() { */ public function testLibraryItems() { // Set default theme. - \Drupal::service('theme_handler')->install(['bartik']); + \Drupal::service('theme_installer')->install(['bartik']); $this->config('system.theme')->set('default', 'bartik')->save(); $this->loginAsAdmin(['create paragraphed_test content', 'edit any paragraphed_test content', 'administer paragraphs library']); @@ -50,7 +47,7 @@ public function testLibraryItems() { // Add a new library item. $this->drupalGet('admin/content/paragraphs'); $this->clickLink('Add library item'); - $this->drupalPostAjaxForm(NULL, [], 'paragraphs_text_paragraph_add_more'); + $this->drupalPostForm(NULL, [], 'paragraphs_text_paragraph_add_more'); $edit = [ 'label[0][value]' => 're usable paragraph label', 'paragraphs[0][subform][field_text][0][value]' => 're_usable_text', @@ -78,17 +75,17 @@ public function testLibraryItems() { $this->assertText('Used', 'Usage column is available.'); $this->assertText('Changed', 'Changed column is available.'); $result = $this->cssSelect('.views-field-count'); - $this->assertEqual(trim($result[1]->__toString()), '0', 'Usage info is correctly displayed.'); + $this->assertEqual(trim($result[1]->getText()), '0', 'Usage info is correctly displayed.'); $this->assertText('Delete'); // Check the changed field. $result = $this->cssSelect('.views-field-changed'); - $this->assertNotNull(trim($result[1]->__toString())); + $this->assertNotNull(trim($result[1]->getText())); $this->clickLink('Edit'); $this->assertFieldByName('label[0][value]', 're usable paragraph label'); $this->assertFieldByName('paragraphs[0][subform][field_text][0][value]', 're_usable_text'); // Create a node with the library paragraph. - $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_from_library_add_more'); + $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_from_library_add_more'); $edit = [ 'title[0][value]' => 'library_test', 'field_paragraphs[0][subform][field_reusable_paragraph][0][target_id]' => 're usable paragraph label (1)' @@ -97,12 +94,12 @@ public function testLibraryItems() { $library_items = \Drupal::entityTypeManager()->getStorage('paragraphs_library_item')->loadByProperties(['label' => 're usable paragraph label']); $this->drupalGet('admin/content/paragraphs/' . current($library_items)->id() . '/edit'); - $this->assertText('Library item is used 1 time.'); + $this->assertText('Modifications on this form will affect all existing usages of this entity.'); $this->assertText('Delete'); $this->drupalGet('admin/content/paragraphs'); $result = $this->cssSelect('.views-field-count'); - $this->assertEqual(trim($result[1]->__toString()), '1', 'Usage info is correctly displayed.'); + $this->assertEqual(trim($result[1]->getText()), '1', 'Usage info is correctly displayed.'); // Assert that the paragraph is shown correctly. $node_one = $this->getNodeByTitle('library_test'); @@ -110,7 +107,7 @@ public function testLibraryItems() { $this->assertText('re_usable_text'); // Create a new node with the library paragraph. - $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_from_library_add_more'); + $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_from_library_add_more'); $edit = [ 'title[0][value]' => 'library_test_new', 'field_paragraphs[0][subform][field_reusable_paragraph][0][target_id]' => 're usable paragraph label (1)' @@ -125,7 +122,7 @@ public function testLibraryItems() { $this->assertNoText('Paragraphs', 'Label from library item field paragraphs is hidden.'); $this->drupalGet('node/' . $node_two->id() . '/edit'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_from_library_add_more'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_from_library_add_more'); $edit = [ 'title[0][value]' => 'library_test_new', 'field_paragraphs[0][subform][field_reusable_paragraph][0][target_id]' => 're usable paragraph label (1)', @@ -134,21 +131,21 @@ public function testLibraryItems() { $this->drupalPostForm(NULL, $edit, 'Save'); $reusable_paragraphs_text = $this->xpath('//div[contains(@class, "field--name-field-paragraphs")]/div[@class="field__items"]/div[1]//div[@class="field__item"]/p'); - $this->assertEqual($reusable_paragraphs_text[0], 're_usable_text'); + $this->assertEqual($reusable_paragraphs_text[0]->getText(), 're_usable_text'); $second_reusable_paragraphs_text = $this->xpath('//div[contains(@class, "field--name-field-paragraphs")]/div[@class="field__items"]/div[2]//div[@class="field__item"]/p'); - $this->assertEqual($second_reusable_paragraphs_text[0], 're_usable_text'); + $this->assertEqual($second_reusable_paragraphs_text[0]->getText(), 're_usable_text'); // Edit the paragraph and change the text. $this->drupalGet('admin/content/paragraphs'); $this->assertText('Used', 'Usage column is available.'); $result = $this->cssSelect('.views-field-count'); - $this->assertEqual(trim($result[1]->__toString()), '4', 'Usage info is correctly displayed.'); + $this->assertEqual(trim($result[1]->getText()), '4', 'Usage info is correctly displayed.'); $this->assertNoLink('4', 'Link to usage statistics is not available for user without permission.'); $this->clickLink('Edit'); - $this->assertText('Library item is used 3 times.'); + $this->assertText('Modifications on this form will affect all existing usages of this entity.'); $edit = [ 'paragraphs[0][subform][field_text][0][value]' => 're_usable_text_new', ]; @@ -199,15 +196,14 @@ public function testLibraryItems() { $this->assertLink('4', 0, 'Link to usage statistics is available for user with permission.'); $element = $this->cssSelect('th.views-field-paragraphs__target-id'); - $this->assertEqual($element[0]->__toString(), 'Paragraphs', 'Paragraphs column is available.'); + $this->assertEqual($element[0]->getText(), 'Paragraphs', 'Paragraphs column is available.'); - $element = $this->cssSelect('.paragraphs-collapsed-description'); - $this->assertEqual(trim($element[0]->__toString()), 're_usable_text_new', 'Paragraphs summary available.'); + $element = $this->cssSelect('.paragraphs-description .paragraphs-content-wrapper .summary-content'); + $this->assertEqual(trim($element[0]->getText()), 're_usable_text_new', 'Paragraphs summary available.'); // Check that the deletion of library items does not cause errors. current($library_items)->delete(); $this->drupalGet('node/' . $node_one->id()); - $this->assertNoErrorsLogged(); // Test paragraphs library item field UI. $this->loginAsAdmin([ @@ -225,7 +221,6 @@ public function testLibraryItems() { $this->clickLink('Manage fields'); $this->clickLink(t('Add field')); $this->assertResponse(200); - $this->assertNoErrorsLogged(); $this->assertNoText('plugin does not exist'); $this->drupalGet('admin/config/content'); $this->clickLink('Paragraphs library item settings'); @@ -249,7 +244,7 @@ public function testConvertLibraryItemIntoParagraph() { // Add a new library item. $this->drupalGet('admin/content/paragraphs'); $this->clickLink('Add library item'); - $this->drupalPostAjaxForm(NULL, [], 'paragraphs_text_add_more'); + $this->drupalPostForm(NULL, [], 'paragraphs_text_add_more'); $edit = [ 'label[0][value]' => 'reusable paragraph label', 'paragraphs[0][subform][field_text][0][value]' => 'reusable_text', @@ -258,7 +253,7 @@ public function testConvertLibraryItemIntoParagraph() { $this->assertText('Paragraph reusable paragraph label has been created.'); // Add created library item to a node. - $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_from_library_add_more'); + $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_from_library_add_more'); $edit = [ 'title[0][value]' => 'Node with converted library item', 'field_paragraphs[0][subform][field_reusable_paragraph][0][target_id]' => 'reusable paragraph label', @@ -269,7 +264,7 @@ public function testConvertLibraryItemIntoParagraph() { // Convert library item to paragraph. $this->clickLink('Edit'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_unlink_from_library'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_0_unlink_from_library'); $this->assertFieldByName('field_paragraphs[0][subform][field_text][0][value]'); $this->assertNoFieldByName('field_paragraphs[0][subform][field_reusable_paragraph][0][target_id]'); $this->assertText('reusable_text'); @@ -329,7 +324,7 @@ public function testConvertParagraphIntoLibrary() { $edit = [ 'field_paragraphs[0][subform][field_text][0][value]' => 'Random text for testing converting into library.', ]; - $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_0_promote_to_library'); + $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_promote_to_library'); $this->assertText('From library'); $this->assertText('Reusable paragraph'); $this->assertFieldByName('field_paragraphs[0][subform][field_reusable_paragraph][0][target_id]', 'text: Random text for testing converting into library. (1)'); @@ -352,7 +347,7 @@ public function testConvertParagraphIntoLibrary() { $this->drupalPostForm(NULL, $edit, 'Save'); $node = $this->getNodeByTitle('NodeTitle'); $this->drupalGet('node/' . $node->id() . '/edit'); - $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_0_promote_to_library'); + $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_promote_to_library'); user_role_grant_permissions($user_role, ['administer paragraphs library']); $this->drupalGet('/admin/content/paragraphs'); $this->assertText('Text'); @@ -397,14 +392,25 @@ public function testLibraryItemParagraphsSummary() { 'fields[field_paragraphs][type]' => 'paragraphs', ]; $this->drupalPostForm(NULL, $edit, t('Save')); - $this->drupalPostAjaxForm('admin/content/paragraphs/add/default', [], 'paragraphs_nested_test_add_more'); - $this->drupalPostAjaxForm(NULL, [], 'paragraphs_0_subform_field_paragraphs_text_add_more'); + $this->drupalPostForm('admin/content/paragraphs/add/default', [], 'paragraphs_nested_test_add_more'); + $this->drupalPostForm(NULL, [], 'paragraphs_0_subform_field_paragraphs_text_add_more'); $edit = [ 'label[0][value]' => 'Test nested', 'paragraphs[0][subform][field_paragraphs][0][subform][field_text][0][value]' => 'test text paragraph', ]; $this->drupalPostForm(NULL, $edit, t('Save')); $this->assertText('test text paragraph'); + + // Assert that the user with the access content permission can see the + // paragraph type label. + $user = $this->drupalCreateUser([ + 'access content', + 'administer paragraphs library' + ]); + $this->drupalLogin($user); + $this->drupalGet('admin/content/paragraphs'); + $paragraph_type = $this->xpath('//table/tbody/tr/td[2]'); + $this->assertEqual(trim(strip_tags($paragraph_type[0]->getText())), 'nested_test'); } /** @@ -436,7 +442,7 @@ public function testLibraryitemValidation() { // Check the paragraph validation. $this->assertText('Paragraphs field is required.'); - $this->drupalPostAjaxForm(NULL, [], 'paragraphs_text_paragraph_add_more'); + $this->drupalPostForm(NULL, [], 'paragraphs_text_paragraph_add_more'); $edit['paragraphs[0][subform][field_text][0][value]'] = 're_usable_text'; // Check that the library item is created. @@ -466,7 +472,7 @@ public function testLibraryReferencingParagraphValidation() { // Add a library item with paragraphs type "Text". $this->drupalGet('admin/content/paragraphs'); $this->clickLink('Add library item'); - $this->drupalPostAjaxForm(NULL, [], 'paragraphs_text_add_more'); + $this->drupalPostForm(NULL, [], 'paragraphs_text_add_more'); $edit = [ 'label[0][value]' => 'reusable paragraph label', 'paragraphs[0][subform][field_text][0][value]' => 'reusable_text', @@ -477,7 +483,7 @@ public function testLibraryReferencingParagraphValidation() { // Create a node with a "From library" paragraph referencing the library // item. $this->drupalGet('node/add/paragraphed_test'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_from_library_add_more'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_from_library_add_more'); $edit = [ 'title[0][value]' => 'library_test', 'field_paragraphs[0][subform][field_reusable_paragraph][0][target_id]' => 'reusable paragraph label', @@ -526,8 +532,8 @@ public function testLibraryItemRevisions() { // Add nested paragraph directly in library. $this->drupalGet('admin/content/paragraphs/add/default'); - $this->drupalPostAjaxForm(NULL, NULL, 'paragraphs_nested_paragraph_add_more'); - $this->drupalPostAjaxForm(NULL, NULL, 'paragraphs_0_subform_field_err_field_test_content_add_more'); + $this->drupalPostForm(NULL, NULL, 'paragraphs_nested_paragraph_add_more'); + $this->drupalPostForm(NULL, NULL, 'paragraphs_0_subform_field_err_field_test_content_add_more'); $edit = [ 'label[0][value]' => 'Test revisions nested original', 'paragraphs[0][subform][field_err_field][0][subform][field_paragraphs_text][0][value]' => 'Example text for revision original.', diff --git a/web/modules/paragraphs/modules/paragraphs_library/tests/src/FunctionalJavascript/ParagraphsContentModerationTest.php b/web/modules/paragraphs/modules/paragraphs_library/tests/src/FunctionalJavascript/ParagraphsContentModerationTest.php index 19ce3705d1..0250273503 100644 --- a/web/modules/paragraphs/modules/paragraphs_library/tests/src/FunctionalJavascript/ParagraphsContentModerationTest.php +++ b/web/modules/paragraphs/modules/paragraphs_library/tests/src/FunctionalJavascript/ParagraphsContentModerationTest.php @@ -3,18 +3,17 @@ namespace Drupal\Tests\paragraphs_library\FunctionalJavascript; use Behat\Mink\Element\Element; -use Drupal\field_ui\Tests\FieldUiTestTrait; -use Drupal\FunctionalJavascriptTests\JavascriptTestBase; +use Drupal\Tests\field_ui\Traits\FieldUiTestTrait; +use Drupal\FunctionalJavascriptTests\WebDriverTestBase; use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait; use Drupal\Tests\paragraphs\Traits\ParagraphsLastEntityQueryTrait; -use Drupal\workflows\Entity\Workflow; /** * Tests Paragraphs, Paragraphs Library and Content Moderation integration. * * @group paragraphs_library */ -class ParagraphsContentModerationTest extends JavascriptTestBase { +class ParagraphsContentModerationTest extends WebDriverTestBase { use ParagraphsTestBaseTrait, FieldUiTestTrait, ParagraphsLastEntityQueryTrait; @@ -51,6 +50,11 @@ class ParagraphsContentModerationTest extends JavascriptTestBase { 'content_moderation', ]; + /** + * {@inheritdoc} + */ + protected $defaultTheme = 'classy'; + /** * {@inheritdoc} */ @@ -193,6 +197,8 @@ public function testModeratedParagraphedContent() { $this->assertNotNull($textfield); $page->fillField('field_paragraphs[1][subform][field_text][0][value]', 'Direct paragraph text 2'); $page->selectFieldOption('moderation_state[0][state]', 'published'); + $page->clickLink('Revision information'); + $page->find('css', 'a[href="#edit-revision-information"]')->click(); $page->fillField('revision_log[0][value]', 'Node revision #2 - This is a special version!'); $page->pressButton('Save'); $assert_session->pageTextContains('paragraphed_moderated_test Host page 1 (rev 2) has been updated.'); @@ -220,6 +226,7 @@ public function testModeratedParagraphedContent() { $this->assertNotNull($textfield); $page->fillField('field_paragraphs[2][subform][field_text][0][value]', 'Direct paragraph text 3'); $page->selectFieldOption('moderation_state[0][state]', 'published'); + $page->find('css', 'a[href="#edit-revision-information"]')->click(); $page->fillField('revision_log[0][value]', 'Node revision #3'); $page->pressButton('Save'); $assert_session->pageTextContains('paragraphed_moderated_test Host page 1 (rev 3) has been updated.'); @@ -259,6 +266,7 @@ public function testModeratedParagraphedContent() { $paragraph3_confirm_remove_button->press(); $assert_session->assertWaitOnAjaxRequest(); $page->selectFieldOption('moderation_state[0][state]', 'draft'); + $page->find('css', 'a[href="#edit-revision-information"]')->click(); $page->fillField('revision_log[0][value]', 'Node revision #4'); $page->pressButton('Save'); // The admin is currently at /node/*/latest. @@ -360,6 +368,7 @@ public function testModeratedParagraphedContent() { $this->drupalGet("/node/$host_node_id/edit"); $page->fillField('title[0][value]', 'Host page 1 (rev 6)'); $page->selectFieldOption('moderation_state[0][state]', 'published'); + $page->find('css', 'a[href="#edit-revision-information"]')->click(); $page->fillField('revision_log[0][value]', 'Node revision #6'); $page->pressButton('Save'); $assert_session->pageTextContains('paragraphed_moderated_test Host page 1 (rev 6) has been updated.'); @@ -442,6 +451,7 @@ public function testModeratedContentNestedParagraphs() { $page->fillField('paragraphs[0][subform][field_text][0][value]', 'This is the low-level text.'); // This is published initially. $page->selectFieldOption('moderation_state[0][state]', 'published'); + $page->find('css', 'a[href="#edit-revision-information"]')->click(); $page->fillField('revision_log[0][value]', 'Child initial revision.'); $page->pressButton('Save'); $assert_session->pageTextContains('Paragraph Child library item has been created.'); @@ -462,6 +472,7 @@ public function testModeratedContentNestedParagraphs() { $page->fillField('paragraphs[0][subform][field_nested_paragraphs][0][target_id]', "Child library item ($child_library_item_id)"); // Let's make this initially a draft. $page->selectFieldOption('moderation_state[0][state]', 'draft'); + $page->find('css', 'a[href="#edit-revision-information"]')->click(); $page->fillField('revision_log[0][value]', 'Rich item initial revision.'); $page->pressButton('Save'); $assert_session->pageTextContains('Paragraph Rich library item has been created.'); @@ -483,7 +494,7 @@ public function testModeratedContentNestedParagraphs() { $assert_session->pageTextContains('Rich library item'); $table = $assert_session->elementExists('css', 'table.views-table'); $rich_item_row = $this->getTableRowWithText($table, 'Rich library item'); - $rich_item_checkbox = $assert_session->elementExists('css', 'input[type="checkbox"]', $rich_item_row); + $rich_item_checkbox = $assert_session->elementExists('css', 'input[type="radio"]', $rich_item_row); $rich_item_checkbox->click(); $page->pressButton('Select reusable paragraph'); $session->wait(1000); @@ -491,6 +502,7 @@ public function testModeratedContentNestedParagraphs() { $assert_session->assertWaitOnAjaxRequest(); // Save the node as published. $page->selectFieldOption('moderation_state[0][state]', 'published'); + $page->find('css', 'a[href="#edit-revision-information"]')->click(); $page->fillField('revision_log[0][value]', 'Node initial revision'); $page->pressButton('Save'); @@ -507,6 +519,7 @@ public function testModeratedContentNestedParagraphs() { $this->drupalGet("/admin/content/paragraphs/{$rich_library_item_id}/edit"); $page->fillField('paragraphs[0][subform][field_intermediate_text][0][value]', 'First level text - published'); $page->selectFieldOption('moderation_state[0][state]', 'published'); + $page->find('css', 'a[href="#edit-revision-information"]')->click(); $page->fillField('revision_log[0][value]', 'Rich item first published revision.'); $page->pressButton('Save'); $assert_session->pageTextContains('Paragraph Rich library item has been updated.'); @@ -520,6 +533,7 @@ public function testModeratedContentNestedParagraphs() { $this->drupalGet("/admin/content/paragraphs/{$child_library_item_id}/edit"); $page->fillField('paragraphs[0][subform][field_text][0][value]', 'The low-level text has been modified (pending approval).'); $page->selectFieldOption('moderation_state[0][state]', 'draft'); + $page->find('css', 'a[href="#edit-revision-information"]')->click(); $page->fillField('revision_log[0][value]', 'Child item unapproved changes.'); $page->pressButton('Save'); $assert_session->pageTextContains('Paragraph Child library item has been updated.'); @@ -534,6 +548,7 @@ public function testModeratedContentNestedParagraphs() { $this->drupalGet("/admin/content/paragraphs/{$child_library_item_id}/edit"); $page->fillField('paragraphs[0][subform][field_text][0][value]', 'The low-level text has been modified (approved!).'); $page->selectFieldOption('moderation_state[0][state]', 'published'); + $page->find('css', 'a[href="#edit-revision-information"]')->click(); $page->fillField('revision_log[0][value]', 'Child item approved changes.'); $page->pressButton('Save'); $assert_session->pageTextContains('Paragraph Child library item has been updated.'); diff --git a/web/modules/paragraphs/modules/paragraphs_library/tests/src/FunctionalJavascript/ParagraphsLibraryItemEntityBrowserTest.php b/web/modules/paragraphs/modules/paragraphs_library/tests/src/FunctionalJavascript/ParagraphsLibraryItemEntityBrowserTest.php index 4405e17cbe..4247f71d6d 100644 --- a/web/modules/paragraphs/modules/paragraphs_library/tests/src/FunctionalJavascript/ParagraphsLibraryItemEntityBrowserTest.php +++ b/web/modules/paragraphs/modules/paragraphs_library/tests/src/FunctionalJavascript/ParagraphsLibraryItemEntityBrowserTest.php @@ -3,7 +3,7 @@ namespace Drupal\Tests\paragraphs_library\FunctionalJavascript; use Drupal\language\Entity\ConfigurableLanguage; -use Drupal\Tests\entity_browser\FunctionalJavascript\EntityBrowserJavascriptTestBase; +use Drupal\Tests\entity_browser\FunctionalJavascript\EntityBrowserWebDriverTestBase; use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait; /** @@ -11,7 +11,7 @@ * * @group paragraphs_library */ -class ParagraphsLibraryItemEntityBrowserTest extends EntityBrowserJavascriptTestBase { +class ParagraphsLibraryItemEntityBrowserTest extends EntityBrowserWebDriverTestBase { use ParagraphsTestBaseTrait; @@ -34,6 +34,11 @@ class ParagraphsLibraryItemEntityBrowserTest extends EntityBrowserJavascriptTest 'content_translation' ]; + /** + * {@inheritdoc} + */ + protected $defaultTheme = 'classy'; + /** * Tests a flow of adding/removing references with paragraphs. */ @@ -87,7 +92,8 @@ public function testEntityBrowserWidget() { $this->waitForAjaxToFinish(); $this->getSession()->switchToIFrame('entity_browser_iframe_paragraphs_library_items'); $this->waitForAjaxToFinish(); - $this->getSession()->getPage()->checkField('edit-entity-browser-select-paragraphs-library-item1'); + $style_selector = $this->getSession()->getPage()->find('css', 'input[value="paragraphs_library_item:1"].form-radio'); + $style_selector->click(); $this->getSession()->switchToIFrame(); $drop = <<<JS @@ -128,6 +134,90 @@ public function testEntityBrowserWidget() { // Check that there is only one translation of the paragraph listed. $rows = $this->xpath('//*[@id="entity-browser-paragraphs-library-items-form"]/div[1]/div[2]/table/tbody/tr'); $this->assertTrue(count($rows) == 1); + + // Add a text paragraph in a new library item. + $this->drupalGet('admin/content/paragraphs/add/default'); + $element = $this->getSession()->getPage()->find('xpath', '//*[contains(@class, "dropbutton-toggle")]'); + $element->click(); + $button = $this->getSession()->getPage()->findButton('Add text'); + $button->press(); + $this->waitForAjaxToFinish(); + $this->getSession()->getPage()->fillField('label[0][value]', 'Inner library item'); + $this->getSession()->getPage()->fillField('paragraphs[0][subform][field_text][0][value]', 'This is a reusable text.'); + $this->submitForm([], 'Save'); + // Add a library item inside a library item. + $this->drupalGet('admin/content/paragraphs/add/default'); + $this->getSession()->getPage()->fillField('label[0][value]', 'Outside library item'); + $button = $this->getSession()->getPage()->findButton('Add From library'); + $button->press(); + $this->waitForAjaxToFinish(); + $this->getSession()->getPage()->pressButton('Select reusable paragraph'); + $this->waitForAjaxToFinish(); + $this->getSession()->switchToIFrame('entity_browser_iframe_paragraphs_library_items'); + $this->waitForAjaxToFinish(); + $style_selector = $this->getSession()->getPage()->find('css', 'input[value="paragraphs_library_item:2"].form-radio'); + $style_selector->click(); + $this->getSession()->switchToIFrame(); + $drop = <<<JS + jQuery('input[type=submit][value="Select reusable paragraph"]', window.frames['entity_browser_iframe_paragraphs_library_items'].document).trigger('click') +JS; + $this->getSession()->evaluateScript($drop); + sleep(1); + $this->waitForAjaxToFinish(); + // Edit the inside library item after adding it. + $this->getSession()->getPage()->pressButton('Edit'); + $this->waitForAjaxToFinish(); + $this->assertSession()->fieldExists('paragraphs[0][subform][field_text][0][value]'); + $this->getSession()->getPage()->fillField('paragraphs[0][subform][field_text][0][value]', 'This is a reusable text UPDATED.'); + $save_button = $this->assertSession()->elementExists('css', '.ui-dialog .ui-dialog-buttonset button'); + $save_button->press(); + $this->waitForAjaxToFinish(); + $this->assertSession()->elementContains('css', '.paragraphs-collapsed-description .paragraphs-content-wrapper', 'This is a reusable text UPDATED.'); + $this->submitForm([], 'Save'); + // Edit the outside library item. + $this->getSession()->getPage()->clickLink('Outside library item'); + $this->getSession()->getPage()->clickLink('Edit'); + $this->assertSession()->elementContains('css', '.paragraphs-collapsed-description .paragraphs-content-wrapper', 'This is a reusable text UPDATED.'); + // Edit the inner library item and assert the fields and values. + $this->getSession()->getPage()->pressButton('Edit'); + $this->waitForAjaxToFinish(); + $this->assertSession()->fieldExists('paragraphs[0][subform][field_text][0][value]'); + + // Add a node with the outside library item. + $this->drupalGet('node/add'); + $title = $this->assertSession()->fieldExists('Title'); + $title->setValue('Overlay node'); + $this->getSession()->getPage()->pressButton('Add From library'); + $this->waitForAjaxToFinish(); + $this->getSession()->getPage()->pressButton('Select reusable paragraph'); + $this->waitForAjaxToFinish(); + $this->getSession()->switchToIFrame('entity_browser_iframe_paragraphs_library_items'); + $this->waitForAjaxToFinish(); + $style_selector = $this->getSession()->getPage()->find('css', 'input[value="paragraphs_library_item:3"].form-radio'); + $this->assertTrue($style_selector->isVisible()); + $style_selector->click(); + $this->getSession()->switchToIFrame(); + $drop = <<<JS + jQuery('input[type=submit][value="Select reusable paragraph"]', window.frames['entity_browser_iframe_paragraphs_library_items'].document).trigger('click') +JS; + $this->getSession()->evaluateScript($drop); + sleep(1); + $this->waitForAjaxToFinish(); + $this->assertSession()->elementContains('css', '.paragraphs-collapsed-description .paragraphs-content-wrapper', 'Inner library item'); + $this->submitForm([], 'Save'); + $this->assertSession()->pageTextContains('paragraphed_test Overlay node has been created.'); + // Edit the node. + $node = $this->getNodeByTitle('Overlay node'); + $this->drupalGet('node/' . $node->id() . '/edit'); + // Edit the Outside library item. + $this->getSession()->getPage()->pressButton('Edit'); + $this->waitForAjaxToFinish(); + // Edit the inner library item and assert its fields. + $modal_form = $this->getSession()->getPage()->find('css', '.ui-dialog .paragraphs-library-item-form'); + $save_button = $modal_form->find('css', '.edit-button'); + $save_button->press(); + $this->waitForAjaxToFinish(); + $this->assertSession()->fieldExists('paragraphs[0][subform][field_text][0][value]'); } } diff --git a/web/modules/paragraphs/modules/paragraphs_type_permissions/paragraphs_type_permissions.info.yml b/web/modules/paragraphs/modules/paragraphs_type_permissions/paragraphs_type_permissions.info.yml index 340e188bd4..d80c46fa7e 100644 --- a/web/modules/paragraphs/modules/paragraphs_type_permissions/paragraphs_type_permissions.info.yml +++ b/web/modules/paragraphs/modules/paragraphs_type_permissions/paragraphs_type_permissions.info.yml @@ -1,14 +1,13 @@ name: Paragraphs Type Permissions type: module description: 'Allows users to configure permissions for individual Paragraphs types.' -# core: 8.x +core_version_requirement: ^8.7.7 || ^9 package: Paragraphs dependencies: - paragraphs:paragraphs -# Information added by Drupal.org packaging script on 2019-02-20 -version: '8.x-1.6' -core: '8.x' +# Information added by Drupal.org packaging script on 2020-02-16 +version: '8.x-1.11' project: 'paragraphs' -datestamp: 1550669588 +datestamp: 1581850832 diff --git a/web/modules/paragraphs/modules/paragraphs_type_permissions/src/ParagraphsTypePermissions.php b/web/modules/paragraphs/modules/paragraphs_type_permissions/src/ParagraphsTypePermissions.php index da3ba5f1ff..b18f9a271e 100644 --- a/web/modules/paragraphs/modules/paragraphs_type_permissions/src/ParagraphsTypePermissions.php +++ b/web/modules/paragraphs/modules/paragraphs_type_permissions/src/ParagraphsTypePermissions.php @@ -2,7 +2,6 @@ namespace Drupal\paragraphs_type_permissions; -use Drupal\Core\Routing\UrlGeneratorTrait; use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\paragraphs\Entity\ParagraphsType; @@ -12,7 +11,6 @@ class ParagraphsTypePermissions { use StringTranslationTrait; - use UrlGeneratorTrait; /** * Returns an array of content permissions. diff --git a/web/modules/paragraphs/modules/paragraphs_type_permissions/src/Tests/ParagraphsTypePermissionsTest.php b/web/modules/paragraphs/modules/paragraphs_type_permissions/tests/src/Functional/ParagraphsTypePermissionsTest.php similarity index 86% rename from web/modules/paragraphs/modules/paragraphs_type_permissions/src/Tests/ParagraphsTypePermissionsTest.php rename to web/modules/paragraphs/modules/paragraphs_type_permissions/tests/src/Functional/ParagraphsTypePermissionsTest.php index 744af69503..a784efe1c7 100644 --- a/web/modules/paragraphs/modules/paragraphs_type_permissions/src/Tests/ParagraphsTypePermissionsTest.php +++ b/web/modules/paragraphs/modules/paragraphs_type_permissions/tests/src/Functional/ParagraphsTypePermissionsTest.php @@ -1,12 +1,12 @@ <?php -namespace Drupal\paragraphs_type_permissions\Tests; +namespace Drupal\Tests\paragraphs_type_permissions\Functional; -use Drupal\field_ui\Tests\FieldUiTestTrait; use Drupal\language\Entity\ConfigurableLanguage; -use Drupal\paragraphs\Tests\Classic\ParagraphsCoreVersionUiTestTrait; -use Drupal\simpletest\WebTestBase; +use Drupal\Tests\BrowserTestBase; +use Drupal\Tests\field_ui\Traits\FieldUiTestTrait; use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait; +use Drupal\Tests\paragraphs\Traits\ParagraphsCoreVersionUiTestTrait; use Drupal\user\Entity\Role; /** @@ -14,16 +14,14 @@ * * @group paragraphs */ -class ParagraphsTypePermissionsTest extends WebTestBase { +class ParagraphsTypePermissionsTest extends BrowserTestBase { use FieldUiTestTrait, ParagraphsCoreVersionUiTestTrait, ParagraphsTestBaseTrait; /** - * Modules to enable. - * - * @var array + * {@inheritdoc} */ - public static $modules = array( + protected static $modules = array( 'content_translation', 'image', 'field', @@ -34,6 +32,11 @@ class ParagraphsTypePermissionsTest extends WebTestBase { 'paragraphs_type_permissions', ); + /** + * {@inheritdoc} + */ + protected $defaultTheme = 'stark'; + /** * {@inheritdoc} */ @@ -140,11 +143,11 @@ public function testAnonymousParagraphsTypePermissions() { $this->drupalPostForm(NULL, NULL, t('Add images')); $this->drupalPostForm(NULL, NULL, t('Add text')); - $image_text = $this->drupalGetTestFiles('image')[0]; + $image_text = $this->getTestFiles('image')[0]; $this->drupalPostForm(NULL, [ 'files[field_paragraphs_demo_0_subform_field_image_demo_0]' => $image_text->uri, ], t('Upload')); - $images = $this->drupalGetTestFiles('image')[1]; + $images = $this->getTestFiles('image')[1]; $this->drupalPostForm(NULL, [ 'files[field_paragraphs_demo_1_subform_field_images_demo_0][]' => $images->uri, ], t('Upload')); @@ -190,7 +193,7 @@ public function testAnonymousParagraphsTypePermissions() { // Set edit mode to open. $this->drupalGet('admin/structure/types/manage/paragraphed_content_demo/form-display'); - $this->drupalPostAjaxForm(NULL, [], "field_paragraphs_demo_settings_edit"); + $this->drupalPostForm(NULL, [], "field_paragraphs_demo_settings_edit"); $edit = ['fields[field_paragraphs_demo][settings_edit_form][settings][edit_mode]' => 'open']; $this->drupalPostForm(NULL, $edit, t('Save')); @@ -253,6 +256,17 @@ public function testAnonymousParagraphsTypePermissions() { $this->assertText('Published'); $this->assertText('Images'); $this->assertText('You are not allowed to edit or remove this Paragraph.'); + $this->assertRaw('paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">image-test_0.png<'); + $this->assertNoRaw('paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">Paragraph type Text<'); + + // Check that the paragraph is collapsed by asserting the content summary. + $authenticated_role->grantPermission('view paragraph content text'); + $authenticated_role->save(); + $this->drupalLogin($authenticated_user); + $this->drupalGet('node/' . $node->id() . '/edit'); + $this->assertText('You are not allowed to edit or remove this Paragraph.'); + $this->assertRaw('paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">image-test_0.png<'); + $this->assertRaw('paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">Paragraph type Text<'); } } diff --git a/web/modules/paragraphs/paragraphs.info.yml b/web/modules/paragraphs/paragraphs.info.yml index 8bfdcd5737..6b54227d94 100644 --- a/web/modules/paragraphs/paragraphs.info.yml +++ b/web/modules/paragraphs/paragraphs.info.yml @@ -1,14 +1,14 @@ name: Paragraphs type: module description: 'Enables the creation of paragraphs entities.' -# core: 8.x +core_version_requirement: ^8.7.7 || ^9 package: Paragraphs configure: entity.paragraphs_type.collection dependencies: - entity_reference_revisions:entity_reference_revisions - drupal:file - - 'drupal:system (>= 8.5)' + test_dependencies: - diff:diff - replicate:replicate @@ -16,8 +16,7 @@ test_dependencies: - field_group:field_group - block_field:block_field -# Information added by Drupal.org packaging script on 2019-02-20 -version: '8.x-1.6' -core: '8.x' +# Information added by Drupal.org packaging script on 2020-02-16 +version: '8.x-1.11' project: 'paragraphs' -datestamp: 1550669588 +datestamp: 1581850832 diff --git a/web/modules/paragraphs/paragraphs.install b/web/modules/paragraphs/paragraphs.install index 927c7350aa..49bb4541b7 100644 --- a/web/modules/paragraphs/paragraphs.install +++ b/web/modules/paragraphs/paragraphs.install @@ -91,7 +91,6 @@ function paragraphs_update_8004() { } } - // Delete the storage definition if it was defined before. $storage_definition = $entity_definition_update_manager->getFieldStorageDefinition($field_name, 'paragraph'); if ($storage_definition) { @@ -220,6 +219,17 @@ function paragraphs_update_8012() { function paragraphs_update_8013() { $definition_update_manager = \Drupal::entityDefinitionUpdateManager(); $entity_type = $definition_update_manager->getEntityType('paragraph'); + + // Update the revision metadata keys to remove revision uid which is removed + // in 8017 and 8021. + if ($metadata_keys = $entity_type->get('revision_metadata_keys')) { + if (is_array($metadata_keys) && isset($metadata_keys['revision_user'])) { + unset($metadata_keys['revision_user']); + $metadata_keys['revision_default'] = 'revision_default'; + $entity_type->set('revision_metadata_keys', $metadata_keys); + } + } + $keys = $entity_type->getKeys(); $keys['published'] = 'status'; $entity_type->set('entity_keys', $keys); @@ -256,3 +266,201 @@ function paragraphs_update_8015() { } } } + +/** + * Remove the uid and revision_uid fields. + */ +function paragraphs_update_8016() { + $database = \Drupal::database(); + + $spec = array( + 'type' => 'varchar', + 'description' => "Revision UID", + 'length' => 20, + 'not null' => FALSE, + ); + + $schema = $database->schema(); + + if (!$schema->fieldExists('paragraphs_item_field_data', 'revision_uid')) { + $schema->addField('paragraphs_item_field_data', 'revision_uid', $spec); + } + + if (!$schema->fieldExists('paragraphs_item_revision_field_data', 'revision_uid')) { + $schema->addField('paragraphs_item_revision_field_data', 'revision_uid', $spec); + } + + $tables_fields = [ + 'paragraphs_item_revision' => 'revision_uid', + 'paragraphs_item_field_data' => 'uid', + 'paragraphs_item_revision_field_data' => 'uid', + ]; + + $entity_definition_update_manager = \Drupal::entityDefinitionUpdateManager(); + + foreach ($tables_fields as $table => $field) { + if ($database->schema()->fieldExists($table, $field)) { + $database->update($table) + ->fields([$field => NULL]) + ->execute(); + } + } + + foreach (array_unique($tables_fields) as $table => $field) { + $storage_definition = $entity_definition_update_manager->getFieldStorageDefinition($field, 'paragraph'); + if ($storage_definition) { + $entity_definition_update_manager->uninstallFieldStorageDefinition($storage_definition); + } + } +} + +/** + * Moved function content to paragraphs_update_8023(). + * see https://www.drupal.org/project/paragraphs/issues/2833935#comment-13471948 + */ +function paragraphs_update_8017() { + +} + +/** + * Make the parent fields revisionable. + */ +function paragraphs_update_8018(&$sandbox) { + $database = \Drupal::database(); + // Initialize some variables during the first pass through. + if (!isset($sandbox['total'])) { + // Add the parent fields to the revision data table. + foreach (['parent_id', 'parent_type', 'parent_field_name'] as $field_name) { + $column_schema = [ + 'type' => 'varchar_ascii', + 'length' => $field_name == 'parent_id' ? 255 : 32, + 'binary' => FALSE, + 'not null' => FALSE, + ]; + // Create fields if they don't already exist. + if (!$database->schema()->fieldExists('paragraphs_item_revision_field_data', $field_name)) { + $database->schema() + ->addField('paragraphs_item_revision_field_data', $field_name, $column_schema); + } + } + + // Get all paragraphs to update. + $paragraphs = \Drupal::database()->select('paragraphs_item_field_data', 'p') + ->countQuery() + ->execute() + ->fetchField(0); + $sandbox['total'] = $paragraphs; + $sandbox['current'] = 0; + } + + // Do not continue if no paragraphs are found. + if (empty($sandbox['total'])) { + $sandbox['#finished'] = 1; + return t('No Paragraphs to be processed.'); + } + + $paragraphs_per_batch = 50; + + $query = $database->select('paragraphs_item_field_data', 'p'); + $query->fields('p', ['id', 'parent_id', 'parent_type', 'parent_field_name']); + $query->range($sandbox['current'], $paragraphs_per_batch); + $result = $query->execute(); + + foreach ($result as $row) { + $database->update('paragraphs_item_revision_field_data') + ->fields([ + 'parent_id' => $row->parent_id, + 'parent_type' => $row->parent_type, + 'parent_field_name' => $row->parent_field_name, + ]) + ->condition('id', $row->id) + ->execute(); + $sandbox['current']++; + } + $sandbox['#finished'] = ($sandbox['current'] / $sandbox['total']); + return t('@count Paragraphs processed.', ['@count' => $sandbox['current']]); +} + +/** + * Update the field storage definitions of the parent fields. + */ +function paragraphs_update_8019() { + \Drupal::service('entity_field.manager')->clearCachedFieldDefinitions(); + $definition_update_manager = \Drupal::entityDefinitionUpdateManager(); + $last_installed_schema = \Drupal::service('entity.last_installed_schema.repository'); + foreach (['parent_id', 'parent_type', 'parent_field_name'] as $field_name) { + $column_schema = [ + 'type' => 'varchar_ascii', + 'length' => $field_name == 'parent_id' ? 255 : 32, + 'binary' => FALSE, + 'not null' => FALSE, + ]; + // Update the field storage repository. + $storage_definition = $definition_update_manager->getFieldStorageDefinition($field_name, 'paragraph'); + $storage_definition->setRevisionable(TRUE); + $last_installed_schema->setLastInstalledFieldStorageDefinition($storage_definition); + + // Update the stored field schema. + // @todo: There has to be a better way to do this. + $key = 'paragraph.field_schema_data.' . $field_name; + $field_schema = \Drupal::keyValue('entity.storage_schema.sql')->get($key); + $field_schema['paragraphs_item_revision_field_data']['fields'][$field_name] = $column_schema; + \Drupal::keyValue('entity.storage_schema.sql')->set($key, $field_schema); + } +} + +/** + * Remove the base field overrides for uid & revision_uid. + */ +function paragraphs_update_8020() { + $config_factory = \Drupal::configFactory(); + $names = $config_factory->listAll('core.base_field_override.paragraph.'); + foreach ($names as $name) { + $config = $config_factory->getEditable($name); + if (in_array($config->get('field_name'), ['uid', 'revision_uid'])) { + $config->delete(); + } + } +} + +/** + * Update the revision metadata keys to remove revision uid (fixes 8017). + */ +function paragraphs_update_8021() { + $entity_definition_update_manager = \Drupal::entityDefinitionUpdateManager(); + $entity_type = $entity_definition_update_manager->getEntityType('paragraph'); + if ($metadata_keys = $entity_type->get('revision_metadata_keys')) { + if (is_array($metadata_keys) && isset($metadata_keys['revision_user'])) { + unset($metadata_keys['revision_user']); + $metadata_keys['revision_default'] = 'revision_default'; + $entity_type->set('revision_metadata_keys', $metadata_keys); + $entity_definition_update_manager->updateEntityType($entity_type); + } + } +} + +/** + * Ensure that the parent indexes are added to the revision data table. + */ +function paragraphs_update_8022() { + $manager = \Drupal::entityDefinitionUpdateManager(); + + // Regenerate entity type indexes. + $manager->updateEntityType($manager->getEntityType('paragraph')); +} + +/** + * Update the revision metadata keys to remove revision uid. + */ +function paragraphs_update_8023() { + $entity_definition_update_manager = \Drupal::entityDefinitionUpdateManager(); + $entity_type = $entity_definition_update_manager->getEntityType('paragraph'); + if ($metadata_keys = $entity_type->get('revision_metadata_keys')) { + if (is_array($metadata_keys) && isset($metadata_keys['revision_user'])) { + unset($metadata_keys['revision_user']); + $metadata_keys['revision_default'] = 'revision_default'; + $entity_type->set('revision_metadata_keys', $metadata_keys); + $entity_definition_update_manager->updateEntityType($entity_type); + } + } +} diff --git a/web/modules/paragraphs/paragraphs.libraries.yml b/web/modules/paragraphs/paragraphs.libraries.yml index 28e81165e6..42f4733efa 100644 --- a/web/modules/paragraphs/paragraphs.libraries.yml +++ b/web/modules/paragraphs/paragraphs.libraries.yml @@ -1,12 +1,12 @@ drupal.paragraphs.admin: dependencies: - - core/jquery - - core/drupal - - core/drupalSettings - - core/jquery.once - - core/jquery.form - - core/drupal.ajax - - core/drupal.dropbutton + - core/jquery + - core/drupal + - core/drupalSettings + - core/jquery.once + - core/jquery.form + - core/drupal.ajax + - core/drupal.dropbutton css: theme: css/paragraphs.admin.css: {} @@ -68,10 +68,12 @@ drupal.paragraphs.modal: theme: css/paragraphs.modal.css: {} dependencies: + - core/drupal.dialog - core/drupal.dialog.ajax - core/jquery.once - - core/jquery.ui.tabs +# This library will be deleted in paragraphs_library_info_alter when +# core/sortable is available. sortable: website: https://github.com/RubaXa/Sortable license: @@ -89,7 +91,10 @@ paragraphs-dragdrop: dependencies: - core/jquery - core/drupal - - paragraphs/sortable + # Sortable is only in core from 8.8+. When the library is not available, the + # dependency will be changed with paragraphs/sortable in + # paragraphs_library_info_alter. + - core/sortable drupal.paragraphs.formatter: css: diff --git a/web/modules/paragraphs/paragraphs.module b/web/modules/paragraphs/paragraphs.module index 014a7a3bbc..20aacf17a0 100644 --- a/web/modules/paragraphs/paragraphs.module +++ b/web/modules/paragraphs/paragraphs.module @@ -15,6 +15,7 @@ use Drupal\paragraphs\Entity\ParagraphsType; use Drupal\paragraphs\Plugin\migrate\field\FieldCollection; use Drupal\Core\Render\Element; +use Drupal\Core\Entity\EntityTypeInterface; /** * Implements hook_help(). @@ -77,6 +78,10 @@ function paragraphs_theme() { 'render element' => 'element', 'template' => 'paragraphs-actions', ], + 'paragraphs_summary' => [ + 'render element' => 'element', + 'template' => 'paragraphs-summary', + ], ); } @@ -357,7 +362,7 @@ function paragraphs_preprocess_field_multiple_value_form(&$variables) { } // Add the paragraph type as a class to every row. - if (isset($variables['element'][0]['#paragraph_type'])) { + if (isset($variables['element']['#paragraphs_widget'])) { foreach ($variables['table']['#rows'] as $key => $row) { if (isset($row['data'][1]['data']['#paragraph_type'])) { $variables['table']['#rows'][$key]['class'][] = 'paragraph-type--' . str_replace('_', '-', $row['data'][1]['data']['#paragraph_type']); @@ -390,6 +395,11 @@ function paragraphs_preprocess_field_multiple_value_form(&$variables) { * Implements hook_libraries_info(). */ function paragraphs_libraries_info() { + // Drupal 8.8+ has the sortable library in core, so we don't need to provide custom library information here. + if (version_compare(\Drupal::VERSION, '8.8', '>=')) { + return []; + } + $libraries = [ 'Sortable' => [ 'name' => 'Sortable', @@ -421,6 +431,18 @@ function paragraphs_library_info_alter(&$libraries, $extension) { return; } + if (version_compare(\Drupal::VERSION, '8.8', '>=')) { + // When core/sortable is available, the paragraphs/sortable library can be removed. + unset($libraries['sortable']); + return $libraries; + } + else { + // If the core/sortable is not available, the paragraphs/sortable library should be used as a dependency of + // paragraphs-dragdrop instead. + $library_core_dep_key = array_search('core/sortable', $libraries['paragraphs-dragdrop']['dependencies']); + $libraries['paragraphs-dragdrop']['dependencies'][$library_core_dep_key] = 'paragraphs/sortable'; + } + if (\Drupal::moduleHandler()->moduleExists('libraries')) { $info = libraries_detect('Sortable'); } @@ -473,16 +495,16 @@ function paragraphs_library_info_alter(&$libraries, $extension) { * https://www.drupal.org/project/drupal/issues/2904765 is resolved */ function paragraphs_migration_plugins_alter(array &$migrations) { + /** @var \Drupal\migrate\Plugin\MigrationPluginManager $migration_plugin_manager */ + $migration_plugin_manager = \Drupal::service('plugin.manager.migration'); + /** @var \Drupal\migrate\Plugin\MigrateSourcePluginManager $source_plugin_manager */ + $source_plugin_manager = \Drupal::service('plugin.manager.migrate.source'); + foreach ($migrations as $key => &$migration) { - /** @var \Drupal\migrate\Plugin\MigrationPluginManager $migration_plugin_manager */ - $migration_plugin_manager = \Drupal::service('plugin.manager.migration'); - $migration_stub = $migration_plugin_manager->createStubMigration($migration); - /** @var \Drupal\migrate\Plugin\MigrateSourcePluginManager $source_plugin_manager */ - $source_plugin_manager = \Drupal::service('plugin.manager.migrate.source'); - $source = NULL; - $configuration = $migration['source']; - $source = $source_plugin_manager->createInstance($migration['source']['plugin'], $configuration, $migration_stub); - if ($source) { + if (!empty($migration['source'])) { + $configuration = $migration['source']; + $migration_stub = $migration_plugin_manager->createStubMigration($migration); + $source = $source_plugin_manager->createInstance($migration['source']['plugin'], $configuration, $migration_stub); if (is_a($migration['class'], FieldMigration::class, TRUE)) { // Field storage. @@ -516,6 +538,17 @@ function paragraphs_entity_type_alter(array &$entity_types) { $entity_types['paragraph']->setHandlerClass('moderation', ''); } +/** + * Implements hook_entity_base_field_info_alter(). + */ +function paragraphs_entity_base_field_info_alter(&$fields, EntityTypeInterface $entity_type) { + // Since the paragraph entity doesn't have uid fields anymore, remove the + // content_translation_uid from the field definitions. + if ($entity_type->id() == 'paragraph' && isset($fields['content_translation_uid'])) { + unset($fields['content_translation_uid']); + } +} + /** * Remove 'field_' prefix from field collection bundles. * @@ -578,3 +611,18 @@ function _paragraphs_migration_entity_type_adjust(array &$migration, $destinatio ]; $migration['process'][$destination] = $entity_type_process; } + +/** + * Prepares variables for. + * + * Default template: paragraphs-summary.html.twig + * + * @param array $variables + * An associative array containing: + * - buttons: An array of buttons to display in the modal form. + */ +function template_preprocess_paragraphs_summary(&$variables) { + $variables['content'] = $variables['element']['#summary']['content']; + $variables['behaviors'] = $variables['element']['#summary']['behaviors']; + $variables['expanded'] = !empty($variables['element']['#expanded']); +} diff --git a/web/modules/paragraphs/paragraphs.post_update.php b/web/modules/paragraphs/paragraphs.post_update.php index bd7d3e7354..8208016385 100644 --- a/web/modules/paragraphs/paragraphs.post_update.php +++ b/web/modules/paragraphs/paragraphs.post_update.php @@ -5,6 +5,10 @@ * Post update functions for Paragraphs. */ +use Drupal\Core\Database\Query\Condition; +use Drupal\Core\Entity\Sql\SqlEntityStorageInterface; +use Drupal\Core\Field\BaseFieldDefinition; +use Drupal\Core\Field\FieldStorageDefinitionInterface; use Drupal\Core\Site\Settings; use Drupal\field\Entity\FieldStorageConfig; @@ -110,6 +114,153 @@ function paragraphs_post_update_set_paragraphs_parent_fields(&$sandbox) { else { $sandbox['progress'] += Settings::get('paragraph_limit', 50); } - // Update #finished, 1 if the the whole update has finished. + // Update #finished, 1 if the whole update has finished. $sandbox['#finished'] = empty($sandbox['max']) ? 1 : ($sandbox['current_paragraph_field_id'] / $sandbox['max']); } + +/** + * Update the parent fields with revisionable data. + */ +function paragraphs_post_update_rebuild_parent_fields(array &$sandbox) { + $database = \Drupal::database(); + $entity_type_manager = \Drupal::entityTypeManager(); + /** @var \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager */ + $entity_field_manager = \Drupal::service('entity_field.manager'); + $entity_definition_update_manager = \Drupal::entityDefinitionUpdateManager(); + $paragraph_revisions_data_table = $entity_type_manager->getDefinition('paragraph')->getRevisionDataTable(); + $paragraph_storage = $entity_type_manager->getStorage('paragraph'); + + if (!isset($sandbox['current_index'])) { + $entity_reference_revisions_fields = $entity_field_manager->getFieldMapByFieldType('entity_reference_revisions'); + $paragraph_field_ids = []; + foreach ($entity_reference_revisions_fields as $entity_type_id => $fields) { + // Skip non-revisionable entity types. + $entity_type_definition = $entity_definition_update_manager->getEntityType($entity_type_id); + if (!$entity_type_definition || !$entity_type_definition->isRevisionable()) { + continue; + } + + // Skip non-SQL entity storage implementations. + $storage = $entity_type_manager->getStorage($entity_type_id); + if (!$storage instanceof SqlEntityStorageInterface) { + continue; + } + + $storage_definitions = $entity_field_manager->getFieldStorageDefinitions($entity_type_id); + $storage_definitions = array_intersect_key($storage_definitions, $fields); + + // Process the fields that reference paragraphs. + $storage_definitions = array_filter($storage_definitions, function (FieldStorageDefinitionInterface $field_storage) { + return $field_storage->getSetting('target_type') === 'paragraph'; + }); + + foreach ($storage_definitions as $field_name => $field_storage) { + // Get the field revision table name. + $table_mapping = $storage->getTableMapping(); + $column_names = $table_mapping->getColumnNames($field_name); + $revision_column = $column_names['target_revision_id']; + + if ($field_storage instanceof BaseFieldDefinition && $field_storage->getCardinality() === 1) { + $field_revision_table = $storage->getRevisionDataTable() ?: $storage->getRevisionTable(); + $entity_id_column = $entity_type_definition->getKey('id'); + } + else { + $field_revision_table = $table_mapping->getDedicatedRevisionTableName($field_storage); + $entity_id_column = 'entity_id'; + } + + // Build a data array of the needed data to do the query. + $data = [ + 'entity_type_id' => $entity_type_id, + 'field_name' => $field_name, + 'revision_table' => $field_revision_table, + 'entity_id_column' => $entity_id_column, + 'revision_column' => $revision_column, + 'langcode_column' => $entity_type_definition->getKey('langcode'), + ]; + + // Nested paragraphs must be updated first. + if ($entity_type_id === 'paragraph') { + array_unshift($paragraph_field_ids, $data); + } + else { + $paragraph_field_ids[] = $data; + } + } + } + + if (empty($paragraph_field_ids)) { + // There are no paragraph fields. Return before initializing the sandbox. + return; + } + + // Initialize the sandbox. + $sandbox['current_index'] = 0; + $sandbox['paragraph_field_ids'] = $paragraph_field_ids; + $sandbox['max'] = count($paragraph_field_ids); + $sandbox['max_revision_id'] = NULL; + } + + $current_field = $sandbox['paragraph_field_ids'][$sandbox['current_index']]; + $revision_column = $current_field['revision_column']; + $entity_id_column = $current_field['entity_id_column']; + $entity_type_id = $current_field['entity_type_id']; + $field_name = $current_field['field_name']; + + // Select the field values from the revision of the parent entity type. + $query = $database->select($current_field['revision_table'], 'f'); + + // Join tables by paragraph revision IDs. + $query->innerJoin($paragraph_revisions_data_table, 'p', "f.$revision_column = p.revision_id"); + $query->fields('f', [$entity_id_column, $revision_column]); + + // Select paragraphs with at least one wrong parent field. + $or_group = new Condition('OR'); + $or_group->where("p.parent_id <> f.$entity_id_column"); + $or_group->condition('p.parent_type', $entity_type_id, '<>'); + $or_group->condition('p.parent_field_name', $field_name, '<>'); + $query->condition($or_group); + + // Match the langcode so we can deal with revisions translations. + if (!empty($current_field['langcode_column'])) { + $query->where('p.langcode = f.' . $current_field['langcode_column']); + } + + // Order the query by revision ID and limit the number of results. + $query->orderBy('p.revision_id'); + + // Only check the revisions that are not already processed. + if ($sandbox['max_revision_id']) { + $query->condition('p.revision_id', $sandbox['max_revision_id'], '>'); + } + // Limit the number of processed paragraphs per run. + $query->range(0, Settings::get('paragraph_limit', 100)); + + $results = $query->execute()->fetchAll(); + + // Update the parent fields of the identified paragraphs revisions. + foreach ($results as $result) { + /** @var \Drupal\paragraphs\ParagraphInterface $revision */ + $revision = $paragraph_storage->loadRevision($result->$revision_column); + if ($revision) { + $revision->set('parent_id', $result->$entity_id_column); + $revision->set('parent_type', $entity_type_id); + $revision->set('parent_field_name', $field_name); + $revision->save(); + } + } + + // Continue with the next element in case we processed all the paragraphs + // assigned to the current paragraph field. + if (count($results) < Settings::get('paragraph_limit', 100)) { + $sandbox['current_index']++; + $sandbox['max_revision_id'] = NULL; + } + else { + $last_revision_result = end($results); + $sandbox['max_revision_id'] = $last_revision_result->$revision_column; + } + + // Update finished key if the whole update has finished. + $sandbox['#finished'] = empty($sandbox['max']) ? 1 : ($sandbox['current_index'] / $sandbox['max']); +} diff --git a/web/modules/paragraphs/paragraphs.services.yml b/web/modules/paragraphs/paragraphs.services.yml index f700392878..b8c96660c1 100644 --- a/web/modules/paragraphs/paragraphs.services.yml +++ b/web/modules/paragraphs/paragraphs.services.yml @@ -3,3 +3,8 @@ services: class: Drupal\paragraphs\ParagraphsBehaviorManager parent: default_plugin_manager arguments: ['@entity_type.manager', '@config.factory'] + paragraphs_type.uuid_lookup: + class: \Drupal\paragraphs\ParagraphsTypeIconUuidLookup + arguments: ['@cache.bootstrap', '@lock', '@entity_type.manager'] + tags: + - { name: needs_destruction } diff --git a/web/modules/paragraphs/src/Entity/Paragraph.php b/web/modules/paragraphs/src/Entity/Paragraph.php index ac6fc93bad..c96fac05e9 100644 --- a/web/modules/paragraphs/src/Entity/Paragraph.php +++ b/web/modules/paragraphs/src/Entity/Paragraph.php @@ -5,21 +5,21 @@ use Drupal\Component\Utility\NestedArray; use Drupal\Component\Utility\Unicode; use Drupal\Core\Entity\ContentEntityInterface; -use Drupal\Core\Entity\Entity\EntityFormDisplay; use Drupal\Core\Entity\EntityPublishedTrait; use Drupal\Core\Entity\EntityStorageInterface; -use Drupal\Core\Entity\RevisionLogEntityTrait; use Drupal\Core\Field\BaseFieldDefinition; use Drupal\Core\Entity\ContentEntityBase; use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Field\ChangedFieldItemList; +use Drupal\Core\Field\EntityReferenceFieldItemListInterface; use Drupal\Core\Field\FieldDefinitionInterface; +use Drupal\Core\Render\Markup; use Drupal\Core\TypedData\TranslatableInterface; use Drupal\field\Entity\FieldStorageConfig; -use Drupal\entity_reference_revisions\EntityNeedsSaveInterface; use Drupal\entity_reference_revisions\EntityNeedsSaveTrait; use Drupal\field\FieldConfigInterface; use Drupal\paragraphs\ParagraphInterface; +use Drupal\user\EntityOwnerInterface; use Drupal\user\UserInterface; /** @@ -30,6 +30,13 @@ * @ContentEntityType( * id = "paragraph", * label = @Translation("Paragraph"), + * label_collection = @Translation("Paragraphs"), + * label_singular = @Translation("Paragraph"), + * label_plural = @Translation("Paragraphs"), + * label_count = @PluralTranslation( + * singular = "@count Paragraph", + * plural = "@count Paragraphs", + * ), * bundle_label = @Translation("Paragraph type"), * handlers = { * "view_builder" = "Drupal\paragraphs\ParagraphViewBuilder", @@ -58,9 +65,6 @@ * "revision" = "revision_id", * "published" = "status" * }, - * revision_metadata_keys = { - * "revision_user" = "revision_uid", - * }, * bundle_entity_type = "paragraphs_type", * field_ui_base_route = "entity.paragraphs_type.edit_form", * common_reference_revisions_target = TRUE, @@ -143,18 +147,25 @@ public function setParentEntity(ContentEntityInterface $parent, $parent_field_na * {@inheritdoc} */ public function label() { - $label = ''; - if ($parent = $this->getParentEntity()) { + if (($parent = $this->getParentEntity()) && $parent->hasField($this->get('parent_field_name')->value)) { $parent_field = $this->get('parent_field_name')->value; - $values = $parent->{$parent_field}; - foreach ($values as $key => $value) { + $field = $parent->get($parent_field); + $found = FALSE; + foreach ($field as $key => $value) { if ($value->entity->id() == $this->id()) { - $label = $parent->label() . ' > ' . $value->getFieldDefinition()->getLabel(); - } else { - // A previous or draft revision or a deleted stale Paragraph. - $label = $parent->label() . ' > ' . $value->getFieldDefinition()->getLabel() . ' (previous revision)'; + $found = TRUE; + break; } } + if ($found) { + $label = $parent->label() . ' > ' . $field->getFieldDefinition()->getLabel(); + } else { + // A previous or draft revision or a deleted stale Paragraph. + $label = $parent->label() . ' > ' . $field->getFieldDefinition()->getLabel() . ' (previous revision)'; + } + } + else { + $label = t('Orphaned @type: @summary', ['@summary' => Unicode::truncate(strip_tags($this->getSummary()), 50, FALSE, TRUE), '@type' => $this->get('type')->entity->label()]); } return $label; } @@ -165,16 +176,6 @@ public function label() { public function preSave(EntityStorageInterface $storage) { parent::preSave($storage); - // If no owner has been set explicitly, make the current user the owner. - if (!$this->getOwner()) { - $this->setOwnerId(\Drupal::currentUser()->id()); - } - // If no revision author has been set explicitly, make the node owner the - // revision author. - if (!$this->getRevisionAuthor()) { - $this->setRevisionAuthorId($this->getOwnerId()); - } - // If behavior settings are not set then get them from the entity. if ($this->unserializedBehaviorSettings !== NULL) { $this->set('behavior_settings', serialize($this->unserializedBehaviorSettings)); @@ -247,31 +248,53 @@ public function getCreatedTime() { /** * {@inheritdoc} + * + * @deprecated Paragraphs no longer have their own author, + * check the parent entity instead. */ public function getOwner() { - return $this->get('uid')->entity; + $parent = $this->getParentEntity(); + if ($parent instanceof EntityOwnerInterface) { + return $parent->getOwner(); + } + else { + return NULL; + } } /** * {@inheritdoc} + * + * @deprecated Paragraphs no longer have their own author, + * check the parent entity instead. */ public function getOwnerId() { - return $this->get('uid')->target_id; + $parent = $this->getParentEntity(); + if ($parent instanceof EntityOwnerInterface) { + return $parent->getOwnerId(); + } + else { + return NULL; + } } /** * {@inheritdoc} + * + * @deprecated Paragraphs no longer have their own author, + * check the parent entity instead. */ public function setOwnerId($uid) { - $this->set('uid', $uid); return $this; } /** * {@inheritdoc} + * + * @deprecated Paragraphs no longer have their own author, + * check the parent entity instead. */ public function setOwner(UserInterface $account) { - $this->set('uid', $account->id()); return $this; } @@ -291,16 +314,27 @@ public function getParagraphType() { /** * {@inheritdoc} + * + * @deprecated Paragraphs no longer have their own author, + * check the parent entity instead. */ public function getRevisionAuthor() { - return $this->get('revision_uid')->entity; + $parent = $this->getParentEntity(); + + if ($parent) { + return $parent->get('revision_uid')->entity; + } + + return NULL; } /** * {@inheritdoc} + * + * @deprecated Paragraphs no longer have their own author, + * check the parent entity instead. */ public function setRevisionAuthorId($uid) { - $this->set('revision_uid', $uid); return $this; } @@ -329,20 +363,6 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { ->setDescription(t('The paragraphs entity language code.')) ->setRevisionable(TRUE); - $fields['uid'] = BaseFieldDefinition::create('entity_reference') - ->setLabel(t('Authored by')) - ->setDescription(t('The user ID of the paragraphs author.')) - ->setRevisionable(TRUE) - ->setSetting('target_type', 'user') - ->setSetting('handler', 'default') - ->setDefaultValueCallback('Drupal\paragraphs\Entity\Paragraph::getCurrentUserId') - ->setTranslatable(TRUE) - ->setDisplayOptions('form', array( - 'region' => 'hidden', - 'weight' => 0, - )) - ->setDisplayConfigurable('form', TRUE); - $fields['status'] = BaseFieldDefinition::create('boolean') ->setLabel(t('Published')) ->setRevisionable(TRUE) @@ -361,28 +381,25 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { )) ->setDisplayConfigurable('form', TRUE); - $fields['revision_uid'] = BaseFieldDefinition::create('entity_reference') - ->setLabel(t('Revision user ID')) - ->setDescription(t('The user ID of the author of the current revision.')) - ->setSetting('target_type', 'user') - ->setRevisionable(TRUE); - $fields['parent_id'] = BaseFieldDefinition::create('string') ->setLabel(t('Parent ID')) ->setDescription(t('The ID of the parent entity of which this entity is referenced.')) - ->setSetting('is_ascii', TRUE); + ->setSetting('is_ascii', TRUE) + ->setRevisionable(TRUE); $fields['parent_type'] = BaseFieldDefinition::create('string') ->setLabel(t('Parent type')) ->setDescription(t('The entity parent type to which this entity is referenced.')) ->setSetting('is_ascii', TRUE) - ->setSetting('max_length', EntityTypeInterface::ID_MAX_LENGTH); + ->setSetting('max_length', EntityTypeInterface::ID_MAX_LENGTH) + ->setRevisionable(TRUE); $fields['parent_field_name'] = BaseFieldDefinition::create('string') ->setLabel(t('Parent field name')) ->setDescription(t('The entity parent field name to which this entity is referenced.')) ->setSetting('is_ascii', TRUE) - ->setSetting('max_length', FieldStorageConfig::NAME_MAX_LENGTH); + ->setSetting('max_length', FieldStorageConfig::NAME_MAX_LENGTH) + ->setRevisionable(TRUE); $fields['behavior_settings'] = BaseFieldDefinition::create('string_long') ->setLabel(t('Behavior settings')) @@ -393,29 +410,17 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { return $fields; } - /** - * Default value callback for 'uid' base field definition. - * - * @see ::baseFieldDefinitions() - * - * @return array - * An array of default values. - */ - public static function getCurrentUserId() { - return array(\Drupal::currentUser()->id()); - } - /** * {@inheritdoc} */ public function createDuplicate() { $duplicate = parent::createDuplicate(); // Loop over entity fields and duplicate nested paragraphs. - foreach ($duplicate->getFields() as $field) { - if ($field->getFieldDefinition()->getType() == 'entity_reference_revisions') { - if ($field->getFieldDefinition()->getTargetEntityTypeId() == "paragraph") { - foreach ($field as $item) { - $item->entity = $item->entity->createDuplicate(); + foreach ($duplicate->getFields() as $fieldItemList) { + if ($fieldItemList instanceof EntityReferenceFieldItemListInterface && $fieldItemList->getSetting('target_type') === $this->getEntityTypeId()) { + foreach ($fieldItemList as $delta => $item) { + if ($item->entity) { + $fieldItemList[$delta] = $item->entity->createDuplicate(); } } } @@ -427,10 +432,26 @@ public function createDuplicate() { * {@inheritdoc} */ public function getSummary(array $options = []) { + $summary_items = $this->getSummaryItems($options); + $summary = [ + '#theme' => 'paragraphs_summary', + '#summary' => $summary_items, + '#expanded' => isset($options['expanded']) ? $options['expanded'] : FALSE, + ]; + + return \Drupal::service('renderer')->renderPlain($summary); + } + + /** + * {@inheritdoc} + */ + public function getSummaryItems(array $options = []) { + $summary = ['content' => [], 'behaviors' => []]; $show_behavior_summary = isset($options['show_behavior_summary']) ? $options['show_behavior_summary'] : TRUE; $depth_limit = isset($options['depth_limit']) ? $options['depth_limit'] : 1; + + // Add content summary items. $this->summaryCount = 0; - $summary = []; $components = entity_get_form_display('paragraph', $this->getType(), 'default')->getComponents(); uasort($components, 'Drupal\Component\Utility\SortArray::sortByWeightElement'); foreach (array_keys($components) as $field_name) { @@ -448,40 +469,43 @@ public function getSummary(array $options = []) { if ($field_definition->getType() == 'image' || $field_definition->getType() == 'file') { $file_summary = $this->getFileSummary($field_name); if ($file_summary != '') { - $summary[] = $file_summary; + $summary['content'][] = $file_summary; } } $text_summary = $this->getTextSummary($field_name, $field_definition); if ($text_summary != '') { - $summary[] = $text_summary; + $summary['content'][] = $text_summary; } if ($field_definition->getType() == 'entity_reference_revisions') { // Decrease the depth, since we are entering a nested paragraph. $nested_summary = $this->getNestedSummary($field_name, [ - 'show_behavior_summary' => $show_behavior_summary, + 'show_behavior_summary' => FALSE, 'depth_limit' => $depth_limit - 1 ]); - if ($nested_summary != '') { - $summary[] = $nested_summary; - } + $summary['content'] = array_merge($summary['content'], $nested_summary); } - if ($field_type = $field_definition->getType() == 'entity_reference') { - if ($this->get($field_name)->entity && $this->get($field_name)->entity->access('view label')) { - $entity = $this->get($field_name)->entity; - // Switch to the entity translation in the current context if exists. - $entity = \Drupal::service('entity.repository')->getTranslationFromContext($entity, $this->activeLangcode); - $summary[] = $entity->label(); + if ($field_definition->getType() === 'entity_reference') { + $referenced_entities = $this->get($field_name)->referencedEntities(); + /** @var \Drupal\Core\Entity\EntityInterface[] $referenced_entities */ + foreach ($referenced_entities as $referenced_entity) { + if ($referenced_entity->access('view label')) { + // Switch to the entity translation in the current context. + $entity = \Drupal::service('entity.repository')->getTranslationFromContext($referenced_entity, $this->activeLangcode); + $summary['content'][] = $entity->label(); + } } } // Add the Block admin label referenced by block_field. if ($field_definition->getType() == 'block_field') { if (!empty($this->get($field_name)->first())) { - $block_admin_label = $this->get($field_name)->first()->getBlock()->getPluginDefinition()['admin_label']; - $summary[] = $block_admin_label; + if ($block = $block_admin_label = $this->get($field_name)->first()->getBlock()) { + $block_admin_label = $block->getPluginDefinition()['admin_label']; + } + $summary['content'][] = $block_admin_label; } } @@ -489,26 +513,31 @@ public function getSummary(array $options = []) { if (!empty($this->get($field_name)->first())) { // If title is not set, fallback to the uri. if ($title = $this->get($field_name)->title) { - $summary[] = $title; + $summary['content'][] = $title; } else { - $summary[] = $this->get($field_name)->uri; + $summary['content'][] = $this->get($field_name)->uri; } } } } + // Add behaviors summary items. if ($show_behavior_summary) { $paragraphs_type = $this->getParagraphType(); foreach ($paragraphs_type->getEnabledBehaviorPlugins() as $plugin_id => $plugin) { if ($plugin_summary = $plugin->settingsSummary($this)) { - $summary = array_merge($summary, $plugin_summary); + foreach ($plugin_summary as $plugin_summary_element) { + if (!is_array($plugin_summary_element)) { + $plugin_summary_element = ['value' => $plugin_summary_element]; + } + $summary['behaviors'][] = $plugin_summary_element; + } } } } - $collapsed_summary_text = implode(', ', $summary); - return strip_tags($collapsed_summary_text); + return $summary; } /** @@ -551,8 +580,7 @@ public function getIcons(array $options = []) { protected function getFieldsToSkipFromChangedCheck() { // A list of revision fields which should be skipped from the comparision. $fields = [ - $this->getEntityType()->getKey('revision'), - 'revision_uid' + $this->getEntityType()->getKey('revision') ]; return $fields; @@ -631,7 +659,7 @@ protected function getFileSummary($field_name) { elseif ($file_value->alt != '') { $text = $file_value->alt; } - elseif ($file_value->entity->getFileName()) { + elseif ($file_value->entity && $file_value->entity->getFileName()) { $text = $file_value->entity->getFileName(); } @@ -647,7 +675,7 @@ protected function getFileSummary($field_name) { } /** - * Returns summary for nested paragraphs. + * Returns summary items for nested paragraphs. * * @param string $field_name * Field definition id for paragraph. @@ -656,32 +684,25 @@ protected function getFileSummary($field_name) { * See \Drupal\paragraphs\ParagraphInterface::getSummary() for all of the * available options. * - * @return string - * Short summary for nested Paragraphs type - * or NULL if the summary is empty. + * @return array + * List of content summary items for nested elements. */ protected function getNestedSummary($field_name, array $options) { - $summary = []; + $summary_content = []; if ($options['depth_limit'] >= 0) { foreach ($this->get($field_name) as $item) { $entity = $item->entity; if ($entity instanceof ParagraphInterface) { // Switch to the entity translation in the current context if exists. $entity = \Drupal::service('entity.repository')->getTranslationFromContext($entity, $this->activeLangcode); - $summary[] = $entity->getSummary($options); + $content_summary_items = $entity->getSummaryItems($options)['content']; + $summary_content = array_merge($summary_content, array_values($content_summary_items)); $this->summaryCount++; } } } - $summary = array_filter($summary); - - if (empty($summary)) { - return NULL; - } - - $paragraph_summary = implode(', ', $summary); - return $paragraph_summary; + return $summary_content; } /** @@ -717,14 +738,11 @@ public function getTextSummary($field_name, FieldDefinitionInterface $field_defi } $text = $this->get($field_name)->value; - if (strlen($text) > 150) { - $text = Unicode::truncate($text, 150); - } - - $summary = trim(strip_tags($text)); + $summary = Unicode::truncate(trim(strip_tags($text)), 150); if (empty($summary)) { - // Tease raw HTML to have at least some summary. - $summary = htmlspecialchars(trim($text)); + // Autoescape is applied to the summary when it is rendered with twig, + // make it a Markup object so HTML tags are displayed correctly. + $summary = Markup::create(Unicode::truncate(htmlspecialchars(trim($text)), 150)); } } diff --git a/web/modules/paragraphs/src/Entity/ParagraphsType.php b/web/modules/paragraphs/src/Entity/ParagraphsType.php index fb06b01747..9b815c0988 100644 --- a/web/modules/paragraphs/src/Entity/ParagraphsType.php +++ b/web/modules/paragraphs/src/Entity/ParagraphsType.php @@ -5,16 +5,26 @@ use Drupal\Core\Config\Entity\ConfigEntityBundleBase; use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Entity\EntityWithPluginCollectionInterface; +use Drupal\file\Entity\File; use Drupal\paragraphs\ParagraphsBehaviorCollection; use Drupal\paragraphs\ParagraphsTypeInterface; +use Drupal\Core\File\FileSystemInterface; -/** + /** * Defines the ParagraphsType entity. * * @ConfigEntityType( * id = "paragraphs_type", * label = @Translation("Paragraphs type"), + * label_collection = @Translation("Paragraphs types"), + * label_singular = @Translation("Paragraphs type"), + * label_plural = @Translation("Paragraphs types"), + * label_count = @PluralTranslation( + * singular = "@count Paragraphs type", + * plural = "@count Paragraphs types", + * ), * handlers = { + * "access" = "Drupal\paragraphs\ParagraphsTypeAccessControlHandler", * "list_builder" = "Drupal\paragraphs\Controller\ParagraphsTypeListBuilder", * "form" = { * "add" = "Drupal\paragraphs\Form\ParagraphsTypeForm", @@ -32,6 +42,7 @@ * "id", * "label", * "icon_uuid", + * "icon_default", * "description", * "behavior_plugins", * }, @@ -73,6 +84,13 @@ class ParagraphsType extends ConfigEntityBundleBase implements ParagraphsTypeInt */ protected $icon_uuid; + /** + * Default icon encoded as data URL scheme (RFC 2397). + * + * @var string + */ + protected $icon_default; + /** * The Paragraphs type behavior plugins configuration keyed by their id. * @@ -88,11 +106,61 @@ class ParagraphsType extends ConfigEntityBundleBase implements ParagraphsTypeInt */ protected $behaviorCollection; + /** + * Restores the icon file from the default icon value. + * + * @return \Drupal\file\FileInterface|bool + * The icon's file entity or FALSE if no default icon set. + */ + protected function restoreDefaultIcon() { + // Default icon data in RFC 2397 format ("data" URL scheme). + if ($this->icon_default && $icon_data = fopen($this->icon_default, 'r')) { + // Compose the default icon file destination. + $icon_meta = stream_get_meta_data($icon_data); + // File extension from MIME, only JPG/JPEG, PNG and SVG expected. + list(, $icon_file_ext) = explode('image/', $icon_meta['mediatype']); + // SVG special case. + if ($icon_file_ext == 'svg+xml') { + $icon_file_ext = 'svg'; + } + + $filesystem = \Drupal::service('file_system'); + $icon_upload_path = ParagraphsTypeInterface::ICON_UPLOAD_LOCATION; + $icon_file_destination = $icon_upload_path . $this->id() . '-default-icon.' . $icon_file_ext; + // Check the directory exists before writing data to it. + $filesystem->prepareDirectory($icon_upload_path, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS); + // Save the default icon file. + $icon_file_uri = $filesystem->saveData($icon_data, $icon_file_destination); + if ($icon_file_uri) { + // Create the icon file entity. + $icon_entity_values = [ + 'uri' => $icon_file_uri, + 'uid' => \Drupal::currentUser()->id(), + 'uuid' => $this->icon_uuid, + 'status' => FILE_STATUS_PERMANENT, + ]; + + // Delete existent icon file if it exists. + if ($old_icon = $this->getFileByUuid($this->icon_uuid)) { + $old_icon->delete(); + } + + $new_icon = File::create($icon_entity_values); + $new_icon->save(); + $this->updateFileIconUsage($new_icon, $old_icon); + return $new_icon; + } + } + + return FALSE; + } + /** * {@inheritdoc} */ public function getIconFile() { - if ($this->icon_uuid && $icon = $this->getFileByUuid($this->icon_uuid)) { + $icon = $this->getFileByUuid($this->icon_uuid) ?: $this->restoreDefaultIcon(); + if ($this->icon_uuid && $icon) { return $icon; } @@ -141,6 +209,29 @@ public function calculateDependencies() { return $this; } + /** + * {@inheritdoc} + */ + public function onDependencyRemoval(array $dependencies) { + $changed = parent::onDependencyRemoval($dependencies); + $behavior_plugins = $this->getBehaviorPlugins(); + foreach ($dependencies['module'] as $module) { + /** @var \Drupal\Component\Plugin\PluginInspectionInterface $plugin */ + foreach ($behavior_plugins as $instance_id => $plugin) { + $definition = (array) $plugin->getPluginDefinition(); + // If a module providing a behavior plugin is being uninstalled, + // remove the plugin and dependency so this paragraph bundle is not + // deleted too. + if (isset($definition['provider']) && $definition['provider'] === $module) { + unset($this->behavior_plugins[$instance_id]); + $this->getBehaviorPlugins()->removeInstanceId($instance_id); + $changed = TRUE; + } + } + } + return $changed; + } + /** * {@inheritdoc} */ @@ -180,24 +271,12 @@ public function hasEnabledBehaviorPlugin($plugin_id) { * {@inheritdoc} */ public function postSave(EntityStorageInterface $storage, $update = TRUE) { - // Update the file usage for the icon files. if (!$update || $this->icon_uuid != $this->original->icon_uuid) { - // The icon has changed. Update file usage. - /** @var \Drupal\file\FileUsage\FileUsageInterface $file_usage */ - $file_usage = \Drupal::service('file.usage'); - - // Add usage of the new icon file, if it exists. It might not exist, if - // this Paragraphs type was imported as configuration, or if the icon has - // just been removed. - if ($this->icon_uuid && $new_icon = $this->getFileByUuid($this->icon_uuid)) { - $file_usage->add($new_icon, 'paragraphs', 'paragraphs_type', $this->id()); - } - if ($update) { - // Delete usage of the old icon file, if it exists. - if ($this->original->icon_uuid && $old_icon = $this->getFileByUuid($this->original->icon_uuid)) { - $file_usage->delete($old_icon, 'paragraphs', 'paragraphs_type', $this->id()); - } - } + // Update the file usage for the icon file. + $new_icon_file = $this->icon_uuid ? $this->getFileByUuid($this->icon_uuid) : FALSE; + // Update the file usage of the old icon as well if the icon was changed. + $old_icon_file = $update && $this->original->icon_uuid ? $this->getFileByUuid($this->original->icon_uuid) : FALSE; + $this->updateFileIconUsage($new_icon_file, $old_icon_file); } parent::postSave($storage, $update); @@ -210,17 +289,36 @@ public function postSave(EntityStorageInterface $storage, $update = TRUE) { * The file entity's UUID. * * @return \Drupal\file\FileInterface|null - * The file entity. NULL if the UUID is invalid. + * The file entity. NULL if the UUID is invalid. */ protected function getFileByUuid($uuid) { - $files = $this->entityTypeManager() - ->getStorage('file') - ->loadByProperties(['uuid' => $uuid]); - if ($files) { - return current($files); + if ($id = \Drupal::service('paragraphs_type.uuid_lookup')->get($uuid)) { + return $this->entityTypeManager()->getStorage('file')->load($id); } return NULL; } + /** + * Updates the icon file usage information. + * + * @param \Drupal\file\FileInterface|mixed $new_icon + * The new icon file, FALSE on deletion. + * @param \Drupal\file\FileInterface|mixed $old_icon + * (optional) Old icon, on update or deletion. + */ + protected function updateFileIconUsage($new_icon, $old_icon = FALSE) { + /** @var \Drupal\file\FileUsage\FileUsageInterface $file_usage */ + $file_usage = \Drupal::service('file.usage'); + + if ($new_icon) { + // Add usage of the new icon file. + $file_usage->add($new_icon, 'paragraphs', 'paragraphs_type', $this->id()); + } + if ($old_icon) { + // Delete usage of the old icon file. + $file_usage->delete($old_icon, 'paragraphs', 'paragraphs_type', $this->id()); + } + } + } diff --git a/web/modules/paragraphs/src/Feeds/Target/Paragraphs.php b/web/modules/paragraphs/src/Feeds/Target/Paragraphs.php index b71cd84ead..e025ad8628 100644 --- a/web/modules/paragraphs/src/Feeds/Target/Paragraphs.php +++ b/web/modules/paragraphs/src/Feeds/Target/Paragraphs.php @@ -15,7 +15,7 @@ * @FeedsTarget( * id = "paragraphs", * field_types = {"entity_reference_revisions"}, - * arguments = {"@entity.manager", "@current_user"} + * arguments = {"@entity_type.manager", "@current_user"} * ) */ class Paragraphs extends Text implements ConfigurableTargetInterface { diff --git a/web/modules/paragraphs/src/Form/ParagraphsTypeDeleteConfirm.php b/web/modules/paragraphs/src/Form/ParagraphsTypeDeleteConfirm.php index 6642d18079..ac6bb77c35 100644 --- a/web/modules/paragraphs/src/Form/ParagraphsTypeDeleteConfirm.php +++ b/web/modules/paragraphs/src/Form/ParagraphsTypeDeleteConfirm.php @@ -56,7 +56,7 @@ public function deleteExistingEntities(array $form, FormStateInterface $form_sta // Delete existing entities. $storage->delete($paragraphs); - drupal_set_message($this->formatPlural(count($paragraphs), 'Entity is successfully deleted.', 'All @count entities are successfully deleted.')); + $this->messenger()->addMessage($this->formatPlural(count($paragraphs), 'Entity is successfully deleted.', 'All @count entities are successfully deleted.')); } // Set form to rebuild. diff --git a/web/modules/paragraphs/src/Form/ParagraphsTypeForm.php b/web/modules/paragraphs/src/Form/ParagraphsTypeForm.php index cf20195b3f..c92774da52 100644 --- a/web/modules/paragraphs/src/Form/ParagraphsTypeForm.php +++ b/web/modules/paragraphs/src/Form/ParagraphsTypeForm.php @@ -5,10 +5,11 @@ use Drupal\Core\Entity\EntityForm; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Form\SubformState; -use Drupal\Core\Messenger\Messenger; +use Drupal\Core\Messenger\MessengerInterface; use Drupal\field_ui\FieldUI; use Drupal\paragraphs\ParagraphsBehaviorManager; use Symfony\Component\DependencyInjection\ContainerInterface; +use Drupal\paragraphs\ParagraphsTypeInterface; /** * Form controller for paragraph type forms. @@ -41,10 +42,10 @@ class ParagraphsTypeForm extends EntityForm { * * @param \Drupal\paragraphs\ParagraphsBehaviorManager $paragraphs_behavior_manager * The paragraphs type feature manager service. - * @param \Drupal\Core\Messenger\Messenger $messenger + * @param \Drupal\Core\Messenger\MessengerInterface $messenger * The messenger service. */ - public function __construct(ParagraphsBehaviorManager $paragraphs_behavior_manager, Messenger $messenger) { + public function __construct(ParagraphsBehaviorManager $paragraphs_behavior_manager, MessengerInterface $messenger) { $this->paragraphsBehaviorManager = $paragraphs_behavior_manager; $this->messenger = $messenger; } @@ -95,7 +96,7 @@ public function form(array $form, FormStateInterface $form_state) { $form['icon_file'] = [ '#title' => $this->t('Paragraph type icon'), '#type' => 'managed_file', - '#upload_location' => 'public://paragraphs_type_icon/', + '#upload_location' => ParagraphsTypeInterface::ICON_UPLOAD_LOCATION, '#upload_validators' => [ 'file_validate_extensions' => ['png jpg svg'], ], @@ -116,12 +117,12 @@ public function form(array $form, FormStateInterface $form_state) { if ($behavior_plugin_definitions = $this->paragraphsBehaviorManager->getApplicableDefinitions($paragraphs_type)) { $form['message'] = [ '#type' => 'container', - '#markup' => $this->t('Behavior plugins are only supported by the EXPERIMENTAL paragraphs widget.'), + '#markup' => $this->t('Behavior plugins are only supported by the EXPERIMENTAL paragraphs widget.', [], ['context' => 'paragraphs']), '#attributes' => ['class' => ['messages', 'messages--warning']] ]; $form['behavior_plugins'] = [ '#type' => 'details', - '#title' => $this->t('Behaviors'), + '#title' => $this->t('Behaviors', [], ['context' => 'paragraphs']), '#tree' => TRUE, '#open' => TRUE ]; @@ -168,12 +169,16 @@ public function validateForm(array &$form, FormStateInterface $form_state) { $paragraphs_type = $this->entity; $icon_file = $form_state->getValue(['icon_file', '0']); - // Set the file UUID to the paragraph configuration. + // Set the icon file UUID and default value to the paragraph configuration. if (!empty($icon_file) && $file = $this->entityTypeManager->getStorage('file')->load($icon_file)) { $paragraphs_type->set('icon_uuid', $file->uuid()); + $paragraphs_type->set( + 'icon_default', + 'data:' . $file->getMimeType() . ';base64,' . base64_encode(file_get_contents($file->getFileUri()))); } else { $paragraphs_type->set('icon_uuid', NULL); + $paragraphs_type->set('icon_default', NULL); } if ($behavior_plugin_definitions = $this->paragraphsBehaviorManager->getApplicableDefinitions($paragraphs_type)) { @@ -218,7 +223,7 @@ public function save(array $form, FormStateInterface $form_state) { $this->messenger->addMessage($this->t('Saved the %label Paragraphs type.', array( '%label' => $paragraphs_type->label(), ))); - if (($status == SAVED_NEW && \Drupal::moduleHandler()->moduleExists('field_ui')) + if (($status == SAVED_NEW && $this->moduleHandler->moduleExists('field_ui')) && $route_info = FieldUI::getOverviewRouteInfo('paragraph', $paragraphs_type->id())) { $form_state->setRedirectUrl($route_info); } @@ -234,7 +239,7 @@ protected function actions(array $form, FormStateInterface $form_state) { $form = parent::actions($form, $form_state); // We want to display the button only on add page. - if ($this->entity->isNew() && \Drupal::moduleHandler()->moduleExists('field_ui')) { + if ($this->entity->isNew() && $this->moduleHandler->moduleExists('field_ui')) { $form['submit']['#value'] = $this->t('Save and manage fields'); } diff --git a/web/modules/paragraphs/src/ParagraphInterface.php b/web/modules/paragraphs/src/ParagraphInterface.php index b3a3181114..6d7969b345 100644 --- a/web/modules/paragraphs/src/ParagraphInterface.php +++ b/web/modules/paragraphs/src/ParagraphInterface.php @@ -36,7 +36,7 @@ public function getParentEntity(); public function setParentEntity(ContentEntityInterface $parent, $parent_field_name); /** - * Returns short summary for paragraph. + * Returns a short summary for the Paragraph. * * @param array $options * (optional) Array of additional options, with the following elements: @@ -47,10 +47,26 @@ public function setParentEntity(ContentEntityInterface $parent, $parent_field_na * allowed. Defaults to 1 to show nested paragraphs only on top level. * * @return string - * The text without tags. + * The template based summary. */ public function getSummary(array $options = []); + /** + * Returns the summary items of the Paragraph. + * + * @param array $options + * (optional) Array of additional options, with the following elements: + * - 'show_behavior_summary': Whether the summary should contain the + * behavior settings. Defaults to TRUE to show behavior settings in the + * summary. + * - 'depth_limit': Depth limit of how many nested paragraph summaries are + * allowed. Defaults to 1 to show nested paragraphs only on top level. + * + * @return array + * A list of summary items, grouped into the keys 'content' and 'behaviors'. + */ + public function getSummaryItems(array $options = []); + /** * Returns info icons render array for a paragraph. * diff --git a/web/modules/paragraphs/src/ParagraphStorageSchema.php b/web/modules/paragraphs/src/ParagraphStorageSchema.php index d79c4ce038..e37a769888 100644 --- a/web/modules/paragraphs/src/ParagraphStorageSchema.php +++ b/web/modules/paragraphs/src/ParagraphStorageSchema.php @@ -17,7 +17,10 @@ class ParagraphStorageSchema extends SqlContentEntityStorageSchema { protected function getEntitySchema(ContentEntityTypeInterface $entity_type, $reset = FALSE) { $schema = parent::getEntitySchema($entity_type, $reset); - $schema['paragraphs_item_field_data']['indexes'] += array( + $schema[$this->storage->getDataTable()]['indexes'] += array( + 'paragraphs__parent_fields' => array('parent_type', 'parent_id', 'parent_field_name'), + ); + $schema[$this->storage->getRevisionDataTable()]['indexes'] += array( 'paragraphs__parent_fields' => array('parent_type', 'parent_id', 'parent_field_name'), ); diff --git a/web/modules/paragraphs/src/ParagraphsBehaviorBase.php b/web/modules/paragraphs/src/ParagraphsBehaviorBase.php index f2cf8915a5..6edd3c1daa 100644 --- a/web/modules/paragraphs/src/ParagraphsBehaviorBase.php +++ b/web/modules/paragraphs/src/ParagraphsBehaviorBase.php @@ -2,9 +2,9 @@ namespace Drupal\paragraphs; -use Drupal\Core\Plugin\PluginBase; use Drupal\Component\Utility\NestedArray; -use Drupal\Core\Entity\EntityFieldManager; +use Drupal\Core\Entity\EntityFieldManagerInterface; +use Drupal\Core\Plugin\PluginBase; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\field\FieldConfigInterface; @@ -30,10 +30,10 @@ abstract class ParagraphsBehaviorBase extends PluginBase implements ParagraphsBe * The plugin_id for the plugin instance. * @param mixed $plugin_definition * The plugin implementation definition. - * @param \Drupal\Core\Entity\EntityFieldManager $entity_field_manager + * @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager * The entity field manager. */ - public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityFieldManager $entity_field_manager) { + public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityFieldManagerInterface $entity_field_manager) { parent::__construct($configuration, $plugin_id, $plugin_definition); $this->configuration += $this->defaultConfiguration(); $this->entityFieldManager = $entity_field_manager; diff --git a/web/modules/paragraphs/src/ParagraphsBehaviorInterface.php b/web/modules/paragraphs/src/ParagraphsBehaviorInterface.php index b152d5ec3e..e3ecb3b87a 100644 --- a/web/modules/paragraphs/src/ParagraphsBehaviorInterface.php +++ b/web/modules/paragraphs/src/ParagraphsBehaviorInterface.php @@ -2,10 +2,11 @@ namespace Drupal\paragraphs; +use Drupal\Component\Plugin\ConfigurableInterface; +use Drupal\Component\Plugin\DependentPluginInterface; use Drupal\Core\Entity\Display\EntityViewDisplayInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Plugin\PluginFormInterface; -use Drupal\Component\Plugin\ConfigurablePluginInterface; use Drupal\paragraphs\Entity\Paragraph; use Drupal\paragraphs\Entity\ParagraphsType; @@ -16,7 +17,7 @@ * adding properties and attributes, it can also add extra classes to the render * elements so extra styling can be applied. */ -interface ParagraphsBehaviorInterface extends PluginFormInterface, ConfigurablePluginInterface { +interface ParagraphsBehaviorInterface extends PluginFormInterface, ConfigurableInterface, DependentPluginInterface { /** * Builds a behavior perspective for each paragraph based on its type. diff --git a/web/modules/paragraphs/src/ParagraphsServiceProvider.php b/web/modules/paragraphs/src/ParagraphsServiceProvider.php index d781b8e183..db38ed640e 100644 --- a/web/modules/paragraphs/src/ParagraphsServiceProvider.php +++ b/web/modules/paragraphs/src/ParagraphsServiceProvider.php @@ -15,7 +15,7 @@ class ParagraphsServiceProvider extends ServiceProviderBase { /** * {@inheritdoc} */ - public function alter(ContainerBuilder $container) { + public function register(ContainerBuilder $container) { $modules = $container->getParameter('container.modules'); // Check for installed Replicate module. if (isset($modules['replicate']) ) { diff --git a/web/modules/paragraphs/src/ParagraphsTypeAccessControlHandler.php b/web/modules/paragraphs/src/ParagraphsTypeAccessControlHandler.php new file mode 100644 index 0000000000..0bf68e342a --- /dev/null +++ b/web/modules/paragraphs/src/ParagraphsTypeAccessControlHandler.php @@ -0,0 +1,34 @@ +<?php + +namespace Drupal\paragraphs; + +use Drupal\Core\Access\AccessResult; +use Drupal\Core\Entity\EntityAccessControlHandler; +use Drupal\Core\Entity\EntityInterface; +use Drupal\Core\Session\AccountInterface; + +/** + * Defines the access control handler for the Paragraphs type entity type. + * + * @see \Drupal\paragraphs\Entity\ParagraphsType + */ +class ParagraphsTypeAccessControlHandler extends EntityAccessControlHandler { + + /** + * {@inheritdoc} + */ + protected $viewLabelOperation = TRUE; + + /** + * {@inheritdoc} + */ + protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) { + switch ($operation) { + case 'view label': + return AccessResult::allowedIfHasPermission($account, 'access content'); + default: + return parent::checkAccess($entity, $operation, $account); + } + } + +} diff --git a/web/modules/paragraphs/src/ParagraphsTypeIconUuidLookup.php b/web/modules/paragraphs/src/ParagraphsTypeIconUuidLookup.php new file mode 100644 index 0000000000..9786eb1023 --- /dev/null +++ b/web/modules/paragraphs/src/ParagraphsTypeIconUuidLookup.php @@ -0,0 +1,55 @@ +<?php + +namespace Drupal\paragraphs; + +use Drupal\Core\Cache\CacheBackendInterface; +use Drupal\Core\Cache\CacheCollector; +use Drupal\Core\Entity\EntityTypeManagerInterface; +use Drupal\Core\Lock\LockBackendInterface; + +/** + * A cache collector that caches IDs for the paragraphs_type entity icon UUIDs. + */ +class ParagraphsTypeIconUuidLookup extends CacheCollector { + + /** + * The entity type manager. + * + * @var \Drupal\Core\Entity\EntityTypeManagerInterface + */ + protected $entityTypeManager; + + /** + * Constructs a ParagraphsTypeIconUuidLookup instance. + * + * @param \Drupal\Core\Cache\CacheBackendInterface $cache + * The cache backend. + * @param \Drupal\Core\Lock\LockBackendInterface $lock + * The lock backend. + * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager + * The entity type manager. + */ + public function __construct(CacheBackendInterface $cache, LockBackendInterface $lock, EntityTypeManagerInterface $entity_type_manager) { + parent::__construct('paragraphs_type_icon_uuid', $cache, $lock); + $this->entityTypeManager = $entity_type_manager; + } + + /** + * {@inheritdoc} + */ + protected function resolveCacheMiss($key) { + $ids = $this->entityTypeManager->getStorage('file')->getQuery() + ->condition('uuid', $key) + ->execute(); + + // Only cache if there is a match, otherwise creating new entities would + // require to invalidate the cache. + $id = reset($ids); + if ($id) { + $this->storage[$key] = $id; + $this->persist($key); + } + return $id; + } + +} diff --git a/web/modules/paragraphs/src/ParagraphsTypeInterface.php b/web/modules/paragraphs/src/ParagraphsTypeInterface.php index 9eb889ea30..9cee2ee496 100644 --- a/web/modules/paragraphs/src/ParagraphsTypeInterface.php +++ b/web/modules/paragraphs/src/ParagraphsTypeInterface.php @@ -9,6 +9,13 @@ */ interface ParagraphsTypeInterface extends ConfigEntityInterface { + /** + * Icon upload location. + * + * @var string + */ + const ICON_UPLOAD_LOCATION = 'public://paragraphs_type_icon/'; + /** * Returns the ordered collection of feature plugin instances. * diff --git a/web/modules/paragraphs/src/Plugin/EntityReferenceSelection/ParagraphSelection.php b/web/modules/paragraphs/src/Plugin/EntityReferenceSelection/ParagraphSelection.php index 3d8e4e27d7..2aa7acd0cc 100644 --- a/web/modules/paragraphs/src/Plugin/EntityReferenceSelection/ParagraphSelection.php +++ b/web/modules/paragraphs/src/Plugin/EntityReferenceSelection/ParagraphSelection.php @@ -2,15 +2,10 @@ namespace Drupal\paragraphs\Plugin\EntityReferenceSelection; -use Drupal\Core\Entity\EntityManagerInterface; -use Drupal\Core\Entity\EntityTypeBundleInfoInterface; use Drupal\Core\Entity\Plugin\EntityReferenceSelection\DefaultSelection; -use Drupal\Core\Extension\ModuleHandlerInterface; -use Drupal\Core\Session\AccountInterface; use Drupal\Core\Url; use Drupal\Core\Form\FormStateInterface; use Drupal\Component\Utility\NestedArray; -use Symfony\Component\DependencyInjection\ContainerInterface; /** * Default plugin implementation of the Entity Reference Selection plugin. @@ -25,52 +20,6 @@ */ class ParagraphSelection extends DefaultSelection { - /** - * Entity type bundle info service. - * - * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface - */ - public $entityTypeBundleInfo; - - /** - * ParagraphSelection constructor. - * - * @param array $configuration - * A configuration array containing information about the plugin instance. - * @param string $plugin_id - * The plugin_id for the plugin instance. - * @param mixed $plugin_definition - * The plugin implementation definition. - * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager - * The entity manager service. - * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler - * The module handler service. - * @param \Drupal\Core\Session\AccountInterface $current_user - * The current user. - * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info - * Entity type bundle info service. - */ - public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityManagerInterface $entity_manager, ModuleHandlerInterface $module_handler, AccountInterface $current_user, EntityTypeBundleInfoInterface $entity_type_bundle_info) { - parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_manager, $module_handler, $current_user); - - $this->entityTypeBundleInfo = $entity_type_bundle_info; - } - - /** - * {@inheritdoc} - */ - public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { - return new static( - $configuration, - $plugin_id, - $plugin_definition, - $container->get('entity.manager'), - $container->get('module_handler'), - $container->get('current_user'), - $container->get('entity_type.bundle.info') - ); - } - /** * {@inheritdoc} */ @@ -176,7 +125,7 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta $weight++; } - if (!count($bundle_options)) { + if (empty($bundle_options)) { $form['allowed_bundles_explain'] = [ '#type' => 'markup', '#markup' => $this->t('You did not add any Paragraph types yet, click <a href=":here">here</a> to add one.', [':here' => Url::fromRoute('paragraphs.type_add')->toString()]), @@ -297,9 +246,9 @@ public function validateReferenceableNewEntities(array $entities) { protected function buildEntityQuery($match = NULL, $match_operator = 'CONTAINS') { $target_type = $this->configuration['target_type']; $handler_settings = $this->configuration['handler_settings']; - $entity_type = $this->entityManager->getDefinition($target_type); + $entity_type = $this->entityTypeManager->getDefinition($target_type); - $query = $this->entityManager->getStorage($target_type)->getQuery(); + $query = $this->entityTypeManager->getStorage($target_type)->getQuery(); // If 'target_bundles' is NULL, all bundles are referenceable, no further // conditions are needed. diff --git a/web/modules/paragraphs/src/Plugin/Field/FieldFormatter/ParagraphsSummaryFormatter.php b/web/modules/paragraphs/src/Plugin/Field/FieldFormatter/ParagraphsSummaryFormatter.php index 2e0bc36332..6987d5ba54 100644 --- a/web/modules/paragraphs/src/Plugin/Field/FieldFormatter/ParagraphsSummaryFormatter.php +++ b/web/modules/paragraphs/src/Plugin/Field/FieldFormatter/ParagraphsSummaryFormatter.php @@ -5,7 +5,6 @@ use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Field\FieldItemListInterface; use Drupal\Core\Field\Plugin\Field\FieldFormatter\EntityReferenceFormatterBase; -use Drupal\paragraphs\Entity\Paragraph; use Drupal\paragraphs\ParagraphInterface; /** @@ -28,7 +27,6 @@ public function viewElements(FieldItemListInterface $items, $langcode) { $elements = []; foreach ($this->getEntitiesToView($items, $langcode) as $delta => $entity) { if ($entity->id()) { - $summary = $entity->getSummary(); $elements[$delta] = [ '#type' => 'container', '#attributes' => [ @@ -49,9 +47,8 @@ public function viewElements(FieldItemListInterface $items, $langcode) { ] ]; $elements[$delta]['summary']['description'] = [ - '#markup' => $summary, - '#prefix' => '<div class="paragraphs-collapsed-description">', - '#suffix' => '</div>', + '#theme' => 'paragraphs_summary', + '#summary' => $entity->getSummaryItems(), ]; } } diff --git a/web/modules/paragraphs/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php b/web/modules/paragraphs/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php index 48d6d2c48e..4fe506f939 100644 --- a/web/modules/paragraphs/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php +++ b/web/modules/paragraphs/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php @@ -6,8 +6,6 @@ use Drupal\Component\Utility\Html; use Drupal\Core\Entity\Entity\EntityFormDisplay; use Drupal\Core\Entity\EntityInterface; -use Drupal\Core\Entity\EntityReferenceSelection\SelectionPluginManagerInterface; -use Drupal\Core\Entity\RevisionableInterface; use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Field\FieldFilteredMarkup; use Drupal\Core\Field\FieldStorageDefinitionInterface; @@ -15,13 +13,10 @@ use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Field\FieldItemListInterface; use Drupal\Core\Render\Element; -use Drupal\node\Entity\Node; -use Drupal\paragraphs; use Drupal\paragraphs\ParagraphInterface; use Symfony\Component\Validator\ConstraintViolationInterface; use Drupal\paragraphs\Plugin\EntityReferenceSelection\ParagraphSelection; - /** * Plugin implementation of the 'entity_reference paragraphs' widget. * @@ -235,7 +230,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen $host = $items->getEntity(); $widget_state = static::getWidgetState($parents, $field_name, $form_state); - $entity_manager = \Drupal::entityTypeManager(); + $entity_type_manager = \Drupal::entityTypeManager(); $target_type = $this->getFieldSetting('target_type'); $item_mode = isset($widget_state['paragraphs'][$delta]['mode']) ? $widget_state['paragraphs'][$delta]['mode'] : 'edit'; @@ -265,10 +260,10 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen } elseif (isset($widget_state['selected_bundle'])) { - $entity_type = $entity_manager->getDefinition($target_type); + $entity_type = $entity_type_manager->getDefinition($target_type); $bundle_key = $entity_type->getKey('bundle'); - $paragraphs_entity = $entity_manager->getStorage($target_type)->create(array( + $paragraphs_entity = $entity_type_manager->getStorage($target_type)->create(array( $bundle_key => $widget_state['selected_bundle'], )); $paragraphs_entity->setParentEntity($items->getEntity(), $field_name); @@ -401,8 +396,10 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen $actions = array(); $links = array(); + // Avoid checking delete access for new entities. + $delete_access = $paragraphs_entity->isNew() || $paragraphs_entity->access('delete'); // Hide the button when translating. - $button_access = $paragraphs_entity->access('delete') && !$this->isTranslating; + $button_access = $delete_access && !$this->isTranslating; if ($item_mode != 'remove') { $links['remove_button'] = [ '#type' => 'submit', @@ -418,7 +415,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen 'effect' => 'fade', ], '#access' => $button_access, - '#prefix' => '<li class="remove">', + '#prefix' => '<li class="remove dropbutton__item dropbutton__item--extrasmall">', '#suffix' => '</li>', '#paragraphs_mode' => 'remove', ]; @@ -442,7 +439,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen 'effect' => 'fade', ), '#access' => $paragraphs_entity->access('update'), - '#prefix' => '<li class="collapse">', + '#prefix' => '<li class="collapse dropbutton__item dropbutton__item--extrasmall">', '#suffix' => '</li>', '#paragraphs_mode' => 'collapsed', '#paragraphs_show_warning' => TRUE, @@ -453,21 +450,21 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen '#type' => 'container', '#markup' => $this->t('You are not allowed to edit this @title.', array('@title' => $this->getSetting('title'))), '#attributes' => ['class' => ['messages', 'messages--warning']], - '#access' => !$paragraphs_entity->access('update') && $paragraphs_entity->access('delete'), + '#access' => !$paragraphs_entity->access('update') && $delete_access, ); $info['remove_button_info'] = array( '#type' => 'container', '#markup' => $this->t('You are not allowed to remove this @title.', array('@title' => $this->getSetting('title'))), '#attributes' => ['class' => ['messages', 'messages--warning']], - '#access' => !$paragraphs_entity->access('delete') && $paragraphs_entity->access('update'), + '#access' => !$delete_access && $paragraphs_entity->access('update'), ); $info['edit_remove_button_info'] = array( '#type' => 'container', '#markup' => $this->t('You are not allowed to edit or remove this @title.', array('@title' => $this->getSetting('title'))), '#attributes' => ['class' => ['messages', 'messages--warning']], - '#access' => !$paragraphs_entity->access('update') && !$paragraphs_entity->access('delete'), + '#access' => !$paragraphs_entity->access('update') && !$delete_access, ); } elseif ($item_mode == 'preview' || $item_mode == 'closed') { @@ -485,7 +482,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen 'effect' => 'fade', ), '#access' => $paragraphs_entity->access('update'), - '#prefix' => '<li class="edit">', + '#prefix' => '<li class="edit dropbutton__item dropbutton__item--extrasmall">', '#suffix' => '</li>', '#paragraphs_mode' => 'edit', ); @@ -509,21 +506,21 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen '#type' => 'container', '#markup' => $this->t('You are not allowed to edit this @title.', array('@title' => $this->getSetting('title'))), '#attributes' => ['class' => ['messages', 'messages--warning']], - '#access' => !$paragraphs_entity->access('update') && $paragraphs_entity->access('delete'), + '#access' => !$paragraphs_entity->access('update') && $delete_access, ); $info['remove_button_info'] = array( '#type' => 'container', '#markup' => $this->t('You are not allowed to remove this @title.', array('@title' => $this->getSetting('title'))), '#attributes' => ['class' => ['messages', 'messages--warning']], - '#access' => !$paragraphs_entity->access('delete') && $paragraphs_entity->access('update'), + '#access' => !$delete_access && $paragraphs_entity->access('update'), ); $info['edit_remove_button_info'] = array( '#type' => 'container', '#markup' => $this->t('You are not allowed to edit or remove this @title.', array('@title' => $this->getSetting('title'))), '#attributes' => ['class' => ['messages', 'messages--warning']], - '#access' => !$paragraphs_entity->access('update') && !$paragraphs_entity->access('delete'), + '#access' => !$paragraphs_entity->access('update') && !$delete_access, ); } elseif ($item_mode == 'remove') { @@ -545,7 +542,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen 'wrapper' => $widget_state['ajax_wrapper_id'], 'effect' => 'fade', ], - '#prefix' => '<li class="confirm-remove">', + '#prefix' => '<li class="confirm-remove dropbutton__item dropbutton__item--extrasmall">', '#suffix' => '</li>', '#paragraphs_mode' => 'removed', ]; @@ -563,13 +560,13 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen 'wrapper' => $widget_state['ajax_wrapper_id'], 'effect' => 'fade', ], - '#prefix' => '<li class="restore">', + '#prefix' => '<li class="restore dropbutton__item dropbutton__item--extrasmall">', '#suffix' => '</li>', '#paragraphs_mode' => 'edit', ]; } - if (count($links)) { + if (!empty($links)) { $show_links = 0; foreach($links as $link_item) { if (!isset($link_item['#access']) || $link_item['#access']) { @@ -583,7 +580,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen if ($show_links > 1) { $element['top']['links']['#theme_wrappers'] = array('dropbutton_wrapper', 'paragraphs_dropbutton_wrapper'); $element['top']['links']['prefix'] = array( - '#markup' => '<ul class="dropbutton">', + '#markup' => '<ul class="dropbutton dropbutton--multiple dropbutton--extrasmall">', '#weight' => -999, ); $element['top']['links']['suffix'] = array( @@ -602,7 +599,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen } } - if (count($info)) { + if (!empty($info)) { $show_info = FALSE; foreach($info as $info_item) { if (!isset($info_item['#access']) || $info_item['#access']) { @@ -617,7 +614,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen } } - if (count($actions)) { + if (!empty($actions)) { $show_actions = FALSE; foreach($actions as $action_item) { if (!isset($action_item['#access']) || $action_item['#access']) { @@ -648,7 +645,12 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen ]; field_group_attach_groups($element['subform'], $context); - $element['subform']['#pre_render'][] = 'field_group_form_pre_render'; + if (function_exists('field_group_form_pre_render')) { + $element['subform']['#pre_render'][] = 'field_group_form_pre_render'; + } + if (function_exists('field_group_form_process')) { + $element['subform']['#process'][] = 'field_group_form_process'; + } } if ($item_mode == 'edit') { @@ -690,20 +692,19 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen } } elseif ($item_mode == 'preview') { + $view_builder = $entity_type_manager->getViewBuilder($paragraphs_entity->getEntityTypeId()); $element['subform'] = array(); $element['behavior_plugins'] = []; - $element['preview'] = entity_view($paragraphs_entity, 'preview', $paragraphs_entity->language()->getId()); + $element['preview'] = $view_builder->view($paragraphs_entity, 'preview', $paragraphs_entity->language()->getId()); $element['preview']['#access'] = $paragraphs_entity->access('view'); } elseif ($item_mode == 'closed') { $element['subform'] = array(); $element['behavior_plugins'] = []; if ($paragraphs_entity) { - $summary = $paragraphs_entity->getSummary(); $element['top']['paragraph_summary']['fields_info'] = [ - '#markup' => $summary, - '#prefix' => '<div class="paragraphs-collapsed-description">', - '#suffix' => '</div>', + '#theme' => 'paragraphs_summary', + '#summary' => $paragraphs_entity->getSummaryItems(), ]; } } @@ -766,7 +767,6 @@ public function getAllowedTypes() { } } - return $return_bundles; } @@ -1004,6 +1004,7 @@ protected function getAccessibleOptions() { $access_control_handler = $entity_type_manager->getAccessControlHandler($target_type); $dragdrop_settings = $this->getSelectionHandlerSetting('target_bundles_drag_drop'); + $this->accessOptions = []; foreach ($bundles as $machine_name => $bundle) { if ($dragdrop_settings || (empty($this->getSelectionHandlerSetting('target_bundles')) || in_array($machine_name, $this->getSelectionHandlerSetting('target_bundles')))) { @@ -1036,7 +1037,7 @@ protected function buildButtonsAddMode() { $drop_button = TRUE; $add_more_elements['#theme_wrappers'] = ['dropbutton_wrapper']; $add_more_elements['prefix'] = [ - '#markup' => '<ul class="dropbutton">', + '#markup' => '<ul class="dropbutton dropbutton--multiple dropbutton--extrasmall">', '#weight' => -999, ]; $add_more_elements['suffix'] = [ @@ -1063,7 +1064,7 @@ protected function buildButtonsAddMode() { ]; if ($drop_button) { - $add_more_elements['add_more_button_' . $machine_name]['#prefix'] = '<li>'; + $add_more_elements['add_more_button_' . $machine_name]['#prefix'] = '<li class="dropbutton__item dropbutton__item--extrasmall">'; $add_more_elements['add_more_button_' . $machine_name]['#suffix'] = '</li>'; } } @@ -1328,7 +1329,8 @@ public function massageFormValues(array $values, array $form, FormStateInterface } // If our mode is remove don't save or reference this entity. // @todo: Maybe we should actually delete it here? - elseif($widget_state['paragraphs'][$item['_original_delta']]['mode'] == 'remove' || $widget_state['paragraphs'][$item['_original_delta']]['mode'] == 'removed') { + elseif(isset($widget_state['paragraphs'][$item['_original_delta']]['mode']) + && in_array($widget_state['paragraphs'][$item['_original_delta']]['mode'], ['remove', 'removed'])) { $item['target_id'] = NULL; $item['target_revision_id'] = NULL; } diff --git a/web/modules/paragraphs/src/Plugin/Field/FieldWidget/ParagraphsWidget.php b/web/modules/paragraphs/src/Plugin/Field/FieldWidget/ParagraphsWidget.php index 4a2c63d527..7c2a7070c1 100644 --- a/web/modules/paragraphs/src/Plugin/Field/FieldWidget/ParagraphsWidget.php +++ b/web/modules/paragraphs/src/Plugin/Field/FieldWidget/ParagraphsWidget.php @@ -341,7 +341,7 @@ public function settingsSummary() { } $features_labels = array_intersect_key($this->getSettingOptions('features'), array_filter($this->getSetting('features'))); if (!empty($features_labels)) { - $summary[] = $this->t('Features: @features', ['@features' => implode($features_labels, ', ')]); + $summary[] = $this->t('Features: @features', ['@features' => implode(', ', $features_labels)]); } return $summary; @@ -437,7 +437,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen else { // If the node is being translated, the paragraphs should be all open // when the form is not being rebuilt (E.g. when clicked on a paragraphs - // action) and when the the translation is being added. + // action) and when the translation is being added. if (!$form_state->isRebuilding() && $host->getTranslationStatus($langcode) == TranslationStatusInterface::TRANSLATION_CREATED) { $item_mode = 'edit'; } @@ -603,6 +603,11 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen '#access' => $this->duplicateButtonAccess($paragraphs_entity), ]; + // Force the closed mode when the user cannot edit the Paragraph. + if (!$paragraphs_entity->access('update')) { + $item_mode = 'closed'; + } + if ($item_mode != 'remove') { $widget_actions['dropdown_actions']['remove_button'] = [ '#type' => 'submit', @@ -640,7 +645,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen '#paragraphs_mode' => 'closed', '#paragraphs_show_warning' => TRUE, '#attributes' => [ - 'class' => ['paragraphs-icon-button', 'paragraphs-icon-button-collapse'], + 'class' => ['paragraphs-icon-button', 'paragraphs-icon-button-collapse', 'button--extrasmall'], 'title' => $this->t('Collapse'), ], ]; @@ -664,7 +669,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen '#access' => $paragraphs_entity->access('update') && !$translating_force_close, '#paragraphs_mode' => 'edit', '#attributes' => [ - 'class' => ['paragraphs-icon-button', 'paragraphs-icon-button-edit'], + 'class' => ['paragraphs-icon-button', 'paragraphs-icon-button-edit', 'button--extrasmall'], 'title' => $this->t('Edit'), ], ]); @@ -677,10 +682,10 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen ]; } - if (!$paragraphs_entity->access('view')) { + if (!$paragraphs_entity->isPublished()) { $info['preview'] = [ '#theme' => 'paragraphs_info_icon', - '#message' => $this->t('You are not allowed to view this @title.', array('@title' => $this->getSetting('title'))), + '#message' => $this->t('Unpublished'), '#icon' => 'view', ]; } @@ -696,14 +701,16 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen ]; } - if (!$paragraphs_entity->access('update') && $paragraphs_entity->access('delete')) { + // Avoid checking delete access for new entities. + $delete_access = $paragraphs_entity->isNew() || $paragraphs_entity->access('delete'); + if (!$paragraphs_entity->access('update') && $delete_access) { $info['edit'] = [ '#theme' => 'paragraphs_info_icon', '#message' => $this->t('You are not allowed to edit this @title.', ['@title' => $this->getSetting('title')]), '#icon' => 'edit-disabled', ]; } - elseif (!$paragraphs_entity->access('delete') && $paragraphs_entity->access('update')) { + elseif (!$delete_access && $paragraphs_entity->access('update')) { $info['remove'] = [ '#theme' => 'paragraphs_info_icon', '#message' => $this->t('You are not allowed to remove this @title.', ['@title' => $this->getSetting('title')]), @@ -726,13 +733,13 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen // Allow modules to alter widget actions. \Drupal::moduleHandler()->alter('paragraphs_widget_actions', $widget_actions, $context); - if (count($widget_actions['actions'])) { + if (!empty($widget_actions['actions'])) { // Expand all actions to proper submit elements and add it to top // actions sub component. $element['top']['actions']['actions'] = array_map([$this, 'expandButton'], $widget_actions['actions']); } - if (count($widget_actions['dropdown_actions'])) { + if (!empty($widget_actions['dropdown_actions'])) { // Expand all dropdown actions to proper submit elements and add // them to top dropdown actions sub component. $element['top']['actions']['dropdown_actions'] = array_map([$this, 'expandButton'], $widget_actions['dropdown_actions']); @@ -753,13 +760,29 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen ]; field_group_attach_groups($element['subform'], $context); - $element['subform']['#pre_render'][] = 'field_group_form_pre_render'; + if (function_exists('field_group_form_pre_render')) { + $element['subform']['#pre_render'][] = 'field_group_form_pre_render'; + } + if (function_exists('field_group_form_process')) { + $element['subform']['#process'][] = 'field_group_form_process'; + } } if ($item_mode == 'edit') { $display->buildForm($paragraphs_entity, $element['subform'], $form_state); $hide_untranslatable_fields = $paragraphs_entity->isDefaultTranslationAffectedOnly(); + $summary = $paragraphs_entity->getSummaryItems(); + if (!empty($summary)) { + $element['top']['summary']['fields_info'] = [ + '#theme' => 'paragraphs_summary', + '#summary' => $summary, + '#expanded' => TRUE, + '#access' => $paragraphs_entity->access('update') || $paragraphs_entity->access('view'), + ]; + } + $info = array_merge($info, $paragraphs_entity->getIcons()); + foreach (Element::children($element['subform']) as $field) { if ($paragraphs_entity->hasField($field)) { $field_definition = $paragraphs_entity->get($field)->getFieldDefinition(); @@ -780,6 +803,12 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen if (!$is_paragraph_field) { $element['subform'][$field]['#attributes']['class'][] = 'paragraphs-content'; + $element['top']['summary']['fields_info'] = [ + '#theme' => 'paragraphs_summary', + '#summary' => $summary, + '#expanded' => TRUE, + '#access' => $paragraphs_entity->access('update') || $paragraphs_entity->access('view'), + ]; } $translatable = $field_definition->isTranslatable(); // Hide untranslatable fields when configured to do so except @@ -831,12 +860,12 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen else { // The closed paragraph is displayed as a summary. if ($paragraphs_entity) { - $summary = $paragraphs_entity->getSummary(); + $summary = $paragraphs_entity->getSummaryItems(); if (!empty($summary)) { $element['top']['summary']['fields_info'] = [ - '#markup' => $summary, - '#prefix' => '<div class="paragraphs-collapsed-description">', - '#suffix' => '</div>', + '#theme' => 'paragraphs_summary', + '#summary' => $summary, + '#expanded' => FALSE, '#access' => $paragraphs_entity->access('update') || $paragraphs_entity->access('view'), ]; } @@ -850,7 +879,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen } // If we have any info items lets add them to the top section. - if (count($info)) { + if (!empty($info)) { foreach ($info as $info_item) { if (!isset($info_item['#access']) || $info_item['#access']) { $element['top']['icons']['items'] = $info; @@ -898,6 +927,7 @@ protected function buildModalAddForm(array &$element) { 'class' => [ 'paragraph-type-add-modal', 'first-button', + 'paragraphs-add-wrapper', ], ], '#access' => $this->allowReferenceChanges(), @@ -962,7 +992,7 @@ public function getAllowedTypes(FieldDefinitionInterface $field_definition = NUL $bundles = \Drupal::service('entity_type.bundle.info')->getBundleInfo($field_definition ? $field_definition->getSetting('target_type') : $this->fieldDefinition->getSetting('target_type')); $weight = 0; foreach ($bundles as $machine_name => $bundle) { - if (!count($this->getSelectionHandlerSetting('target_bundles')) + if (empty($this->getSelectionHandlerSetting('target_bundles')) || in_array($machine_name, $this->getSelectionHandlerSetting('target_bundles'))) { $return_bundles[$machine_name] = array( @@ -975,7 +1005,6 @@ public function getAllowedTypes(FieldDefinitionInterface $field_definition = NUL } } - return $return_bundles; } @@ -1034,7 +1063,7 @@ public function formMultipleElements(FieldItemListInterface $items, array &$form $field_prefix = strtr($this->fieldIdPrefix, '_', '-'); if (count($this->fieldParents) == 0) { if ($items->getEntity()->getEntityTypeId() != 'paragraph') { - $tabs = '<ul class="paragraphs-tabs tabs primary clearfix"><li id="content" class="tabs__tab"><a href="#' . $field_prefix . '-values">Content</a></li><li id="behavior" class="tabs__tab"><a href="#' . $field_prefix . '-values">Behavior</a></li></ul>'; + $tabs = '<ul class="paragraphs-tabs tabs primary clearfix"><li id="content" class="tabs__tab"><a href="#' . $field_prefix . '-values">' . $this->t('Content', [], ['context' => 'paragraphs']) . '</a></li><li id="behavior" class="tabs__tab"><a href="#' . $field_prefix . '-values">' . $this->t('Behavior', [], ['context' => 'paragraphs']) . '</a></li></ul>'; } } if (count($this->fieldParents) > 0) { @@ -1060,6 +1089,9 @@ public function formMultipleElements(FieldItemListInterface $items, array &$form 'callback' => [get_class($this), 'dragDropModeAjax'], 'wrapper' => $this->fieldWrapperId, ], + '#limit_validation_errors' => [ + array_merge($this->fieldParents, [$field_name]), + ], '#button_type' => 'primary', ]); @@ -1158,6 +1190,7 @@ public function formMultipleElements(FieldItemListInterface $items, array &$form } $elements['#allow_reference_changes'] = $this->allowReferenceChanges(); + $elements['#paragraphs_widget'] = TRUE; $elements['#attached']['library'][] = 'paragraphs/drupal.paragraphs.widget'; return $elements; @@ -1279,7 +1312,7 @@ protected function buildNestedParagraphsFoDragDrop(FormStateInterface $form_stat foreach ($field_definitions as $child_field_name => $field_definition) { $child_path = implode('][', array_merge($array_parents, [$child_field_name])); $cardinality = $field_definition->getFieldStorageDefinition()->getCardinality(); - $allowed_types = implode(array_keys($this->getAllowedTypes($field_definition)), ','); + $allowed_types = implode(',', array_keys($this->getAllowedTypes($field_definition))); $elements[$child_field_name] = [ '#type' => 'container', '#attributes' => ['class' => ['paragraphs-dragdrop-wrapper']], @@ -1340,9 +1373,9 @@ protected function buildNestedParagraphsFoDragDrop(FormStateInterface $form_stat } $element['top']['summary']['fields_info'] = [ - '#markup' => $child_paragraph->getSummary($summary_options), - '#prefix' => '<div class="paragraphs-collapsed-description">', - '#suffix' => '</div>', + '#theme' => 'paragraphs_summary', + '#summary' => $child_paragraph->getSummaryItems($summary_options), + '#expanded' => FALSE, '#access' => $child_paragraph->access('update') || $child_paragraph->access('view'), ]; @@ -1520,7 +1553,7 @@ public static function getSubmitElementInfo(array $form, FormStateInterface $for protected function buildDropbutton(array $elements = []) { $build = [ '#type' => 'container', - '#attributes' => ['class' => ['paragraphs-dropbutton-wrapper']], + '#attributes' => ['class' => ['paragraphs-dropbutton-wrapper', 'paragraphs-add-wrapper']], ]; $operations = []; @@ -1555,15 +1588,13 @@ protected function buildButtonsAddMode() { $add_mode = $this->getSetting('add_mode'); $paragraphs_type_storage = \Drupal::entityTypeManager()->getStorage('paragraphs_type'); - // Build the buttons. - $add_more_elements = []; foreach ($options as $machine_name => $label) { $button_key = 'add_more_button_' . $machine_name; $add_more_elements[$button_key] = $this->expandButton([ '#type' => 'submit', '#name' => $this->fieldIdPrefix . '_' . $machine_name . '_add_more', '#value' => $add_mode == 'modal' ? $label : $this->t('Add @type', ['@type' => $label]), - '#attributes' => ['class' => ['field-add-more-submit']], + '#attributes' => ['class' => ['field-add-more-submit', 'paragraphs-add-wrapper']], '#limit_validation_errors' => [array_merge($this->fieldParents, [$this->fieldDefinition->getName(), 'add_more'])], '#submit' => [[get_class($this), 'addMoreSubmit']], '#ajax' => [ @@ -1585,7 +1616,7 @@ protected function buildButtonsAddMode() { } elseif ($add_mode == 'modal') { $this->buildModalAddForm($add_more_elements); - $add_more_elements['add_modal_form_area']['#suffix'] = $this->t('to %type', ['%type' => $this->fieldDefinition->getLabel()]); + $add_more_elements['add_modal_form_area']['#suffix'] = '<span class="paragraphs-add-suffix">' . $this->t('to %type', ['%type' => $this->fieldDefinition->getLabel()]) . '</span>'; } $add_more_elements['#weight'] = 1; @@ -1602,13 +1633,28 @@ protected function buildSelectAddMode() { $field_name = $this->fieldDefinition->getName(); $field_title = $this->fieldDefinition->getLabel(); $setting_title = $this->getSetting('title'); + $select_options = $this->getAccessibleOptions(); + + $add_more_elements = [ + '#type' => 'container', + '#attributes' => [ + 'class' => ['paragraphs-add-wrapper'], + ], + ]; + $add_more_elements['add_more_select'] = [ '#type' => 'select', - '#options' => $this->getAccessibleOptions(), + '#options' => $select_options, '#title' => $this->t('@title type', ['@title' => $setting_title]), '#label_display' => 'hidden', ]; + // Do not present the select element if only one option is available. + if (count($select_options) === 1) { + $add_more_elements['add_more_select']['#type'] = 'value'; + $add_more_elements['add_more_select']['#value'] = key($select_options); + } + $text = $this->t('Add @title', ['@title' => $setting_title]); if ($this->realItemCount > 0) { @@ -1645,6 +1691,13 @@ public static function addMoreAjax(array $form, FormStateInterface $form_state) $element[$delta]['#prefix'] = '<div class="ajax-new-content">' . (isset($element[$delta]['#prefix']) ? $element[$delta]['#prefix'] : ''); $element[$delta]['#suffix'] = (isset($element[$delta]['#suffix']) ? $element[$delta]['#suffix'] : '') . '</div>'; + // Clear the Add more delta. + NestedArray::setValue( + $element, + ['add_more', 'add_modal_form_area', 'add_more_delta', '#value'], + '' + ); + return $element; } @@ -1771,7 +1824,7 @@ public static function duplicateSubmit(array $form, FormStateInterface $form_sta // Check if the replicate module is enabled. if (\Drupal::hasService('replicate.replicator')) { - $duplicate_entity = \Drupal::getContainer()->get('replicate.replicator')->replicateEntity($entity); + $duplicate_entity = \Drupal::getContainer()->get('replicate.replicator')->cloneEntity($entity); } else { $duplicate_entity = $entity->createDuplicate(); @@ -2210,20 +2263,27 @@ public function massageFormValues(array $values, array $form, FormStateInterface // We can only use the entity form display to display validation errors // if it is in edit mode. - if ($widget_state['paragraphs'][$item['_original_delta']]['mode'] === 'edit') { + if (!$form_state->isValidationComplete() && $widget_state['paragraphs'][$item['_original_delta']]['mode'] === 'edit') { $display->validateFormValues($paragraphs_entity, $element[$item['_original_delta']]['subform'], $form_state); } // Assume that the entity is being saved/previewed, in this case, // validate even the closed paragraphs. If there are validation errors, // add them on the parent level. Validation errors do not rebuild the // form so it's not possible to auto-uncollapse the form at this point. - elseif ($form_state->getLimitValidationErrors() === NULL) { + elseif (!$form_state->isValidationComplete() && $form_state->getLimitValidationErrors() === NULL) { $violations = $paragraphs_entity->validate(); $violations->filterByFieldAccess(); - if (count($violations)) { + if (!empty($violations)) { + /** @var \Symfony\Component\Validator\ConstraintViolationInterface $violation */ foreach ($violations as $violation) { - /** @var \Symfony\Component\Validator\ConstraintViolationInterface $violation */ - $form_state->setError($element[$item['_original_delta']], $violation->getMessage()); + + // Ignore text format related validation errors by ignoring + // the .format property. + if (substr($violation->getPropertyPath(), -7) === '.format') { + continue; + } + + $form_state->setError($element[$item['_original_delta']], $this->t('Validation error on collapsed paragraph @path: @message', ['@path' => $violation->getPropertyPath(), '@message' => $violation->getMessage()])); } } } @@ -2507,7 +2567,7 @@ public function buildHeaderActions(array $field_state, FormStateInterface $form_ // order and with the right settings. if ($mode === 'closed') { $edit_all['#attributes'] = [ - 'class' => ['paragraphs-icon-button', 'paragraphs-icon-button-edit'], + 'class' => ['paragraphs-icon-button', 'paragraphs-icon-button-edit', 'button--extrasmall'], 'title' => $this->t('Edit all'), ]; $edit_all['#title'] = $this->t('Edit All'); @@ -2516,7 +2576,7 @@ public function buildHeaderActions(array $field_state, FormStateInterface $form_ } else { $collapse_all['#attributes'] = [ - 'class' => ['paragraphs-icon-button', 'paragraphs-icon-button-collapse'], + 'class' => ['paragraphs-icon-button', 'paragraphs-icon-button-collapse', 'button--extrasmall'], 'title' => $this->t('Collapse all'), ]; $actions['actions']['collapse_all'] = $collapse_all; @@ -2610,7 +2670,8 @@ protected function allowReferenceChanges() { * TRUE if we can remove paragraph, otherwise FALSE. */ protected function removeButtonAccess(ParagraphInterface $paragraph) { - if (!$paragraph->access('delete')) { + // Avoid checking delete access for new entities. + if (!$paragraph->isNew() && !$paragraph->access('delete')) { return FALSE; } diff --git a/web/modules/paragraphs/src/Plugin/migrate/field/FieldCollection.php b/web/modules/paragraphs/src/Plugin/migrate/field/FieldCollection.php index c21997bd83..19d9a21e4d 100644 --- a/web/modules/paragraphs/src/Plugin/migrate/field/FieldCollection.php +++ b/web/modules/paragraphs/src/Plugin/migrate/field/FieldCollection.php @@ -28,32 +28,6 @@ class FieldCollection extends FieldPluginBase { */ const FIELD_COLLECTION_PREFIX_LENGTH = 6; - /** - * {@inheritdoc} - */ - public function processFieldFormatter(MigrationInterface $migration) { - $this->addViewModeProcess($migration); - - // Workaround for Drupal 8.4. In D8.5+ this should only call the parent. - // @todo Remove all but parent call after Drupal 8.6 is released. - // @see https://www.drupal.org/project/paragraphs/issues/2950492 - // - // Core issue: - // @see https://www.drupal.org/project/drupal/issues/2843617 - $process = $migration->getProcess(); - if (is_array($process['options/type'][0]['source'])) { - // Backwards compatibility with D8.5. - // @todo replace with parent::alterFieldFormatterMigration - // @see https://www.drupal.org/project/paragraphs/issues/2994933 - // @see https://www.drupal.org/node/2944598 - parent::processFieldFormatter($migration); - } - else { - $options_type[0]['map']['field_collection_view'] = 'entity_reference_revisions_entity_view'; - $migration->mergeProcessOfProperty('options/type', $options_type); - } - } - /** * {@inheritdoc} */ @@ -80,13 +54,6 @@ public function getFieldWidgetMap() { + parent::getFieldWidgetMap(); } - /** - * {@inheritdoc} - */ - public function processField(MigrationInterface $migration) { - $this->alterFieldMigration($migration); - } - /** * {@inheritdoc} */ @@ -99,13 +66,6 @@ public function alterFieldMigration(MigrationInterface $migration) { $migration->mergeProcessOfProperty('settings', $settings); } - /** - * {@inheritdoc} - */ - public function processFieldInstance(MigrationInterface $migration) { - $this->alterFieldInstanceMigration($migration); - } - /** * {@inheritdoc} */ diff --git a/web/modules/paragraphs/src/Plugin/migrate/field/Paragraphs.php b/web/modules/paragraphs/src/Plugin/migrate/field/Paragraphs.php index cf7f1ee131..bb3d82121c 100644 --- a/web/modules/paragraphs/src/Plugin/migrate/field/Paragraphs.php +++ b/web/modules/paragraphs/src/Plugin/migrate/field/Paragraphs.php @@ -23,18 +23,6 @@ */ class Paragraphs extends FieldPluginBase { - /** - * {@inheritdoc} - */ - public function processFieldWidget(MigrationInterface $migration) { - // Backwards compatibility with D8.5. - // @todo replace with parent::alterFieldWidgetMigration - // @see https://www.drupal.org/project/paragraphs/issues/2994933 - // @see https://www.drupal.org/node/2944598 - parent::processFieldWidget($migration); - $this->paragraphAlterFieldWidgetMigration($migration); - } - /** * {@inheritdoc} */ @@ -43,32 +31,6 @@ public function alterFieldWidgetMigration(MigrationInterface $migration) { $this->paragraphAlterFieldWidgetMigration($migration); } - /** - * {@inheritdoc} - */ - public function processFieldFormatter(MigrationInterface $migration) { - $this->addViewModeProcess($migration); - - // Workaround for Drupal 8.4. In D8.5+ this should only call the parent. - // @todo Remove all but parent call after Drupal 8.6 is released. - // @see https://www.drupal.org/project/paragraphs/issues/2950492 - // - // Core issue: - // @see https://www.drupal.org/project/drupal/issues/2843617 - $process = $migration->getProcess(); - if (is_array($process['options/type'][0]['source'])) { - // Backwards compatibility with D8.5. - // @todo replace with parent::alterFieldFormatterMigration - // @see https://www.drupal.org/project/paragraphs/issues/2994933 - // @see https://www.drupal.org/node/2944598 - parent::processFieldFormatter($migration); - } - else { - $options_type[0]['map']['paragraphs_view'] = 'entity_reference_revisions_entity_view'; - $migration->mergeProcessOfProperty('options/type', $options_type); - } - } - /** * {@inheritdoc} */ @@ -95,13 +57,6 @@ public function getFieldWidgetMap() { + parent::getFieldWidgetMap(); } - /** - * {@inheritdoc} - */ - public function processField(MigrationInterface $migration) { - $this->alterFieldMigration($migration); - } - /** * {@inheritdoc} */ @@ -115,13 +70,6 @@ public function alterFieldMigration(MigrationInterface $migration) { $migration->mergeProcessOfProperty('settings', $settings); } - /** - * {@inheritdoc} - */ - public function processFieldInstance(MigrationInterface $migration) { - $this->alterFieldInstanceMigration($migration); - } - /** * {@inheritdoc} */ diff --git a/web/modules/paragraphs/src/Plugin/migrate/process/ProcessPluginBase.php b/web/modules/paragraphs/src/Plugin/migrate/process/ProcessPluginBase.php index 9a04e29841..ff56d9e8ef 100644 --- a/web/modules/paragraphs/src/Plugin/migrate/process/ProcessPluginBase.php +++ b/web/modules/paragraphs/src/Plugin/migrate/process/ProcessPluginBase.php @@ -2,7 +2,7 @@ namespace Drupal\paragraphs\Plugin\migrate\process; -use Drupal\Component\Plugin\ConfigurablePluginInterface; +use Drupal\Component\Plugin\ConfigurableInterface; use Drupal\Component\Utility\NestedArray; use Drupal\Core\Entity\EntityTypeBundleInfoInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; @@ -12,7 +12,7 @@ /** * Base class for Paragraphs process plugins. */ -abstract class ProcessPluginBase extends MigrateProcessPluginBase implements ConfigurablePluginInterface, ContainerFactoryPluginInterface { +abstract class ProcessPluginBase extends MigrateProcessPluginBase implements ConfigurableInterface, ContainerFactoryPluginInterface { /** * The entity bundle info service. @@ -63,11 +63,4 @@ public function defaultConfiguration() { return []; } - /** - * {@inheritdoc} - */ - public function calculateDependencies() { - return []; - } - } diff --git a/web/modules/paragraphs/src/Plugin/migrate/source/DrupalSqlBase.php b/web/modules/paragraphs/src/Plugin/migrate/source/DrupalSqlBase.php index 641ac491ea..c1a1b9ffed 100644 --- a/web/modules/paragraphs/src/Plugin/migrate/source/DrupalSqlBase.php +++ b/web/modules/paragraphs/src/Plugin/migrate/source/DrupalSqlBase.php @@ -2,10 +2,10 @@ namespace Drupal\paragraphs\Plugin\migrate\source; +use Drupal\Component\Plugin\ConfigurableInterface; use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase as MigrateDrupalSqlBase; -use Drupal\Component\Plugin\ConfigurablePluginInterface; use Drupal\Component\Utility\NestedArray; -use Drupal\Core\Entity\EntityManagerInterface; +use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\State\StateInterface; use Drupal\migrate\Plugin\MigrationInterface; @@ -15,13 +15,13 @@ * Add and implement Configurable Plugin interface to * Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase. */ -abstract class DrupalSqlBase extends MigrateDrupalSqlBase implements ConfigurablePluginInterface { +abstract class DrupalSqlBase extends MigrateDrupalSqlBase implements ConfigurableInterface { /** * {@inheritdoc} */ - public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, StateInterface $state, EntityManagerInterface $entity_manager) { - parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $state, $entity_manager); + public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, StateInterface $state, EntityTypeManagerInterface $entity_type_manager) { + parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $state, $entity_type_manager); $this->setConfiguration($configuration); } diff --git a/web/modules/paragraphs/src/Plugin/migrate/source/d7/FieldCollectionItem.php b/web/modules/paragraphs/src/Plugin/migrate/source/d7/FieldCollectionItem.php index ea8dd8eba2..d96646be7b 100644 --- a/web/modules/paragraphs/src/Plugin/migrate/source/d7/FieldCollectionItem.php +++ b/web/modules/paragraphs/src/Plugin/migrate/source/d7/FieldCollectionItem.php @@ -58,8 +58,6 @@ public function query() { * {@inheritdoc} */ public function prepareRow(Row $row) { - parent::prepareRow($row); - // Remove field_ prefix for new bundle. $bundle = $row->getSourceProperty('field_name'); $bundle = substr($bundle, FieldCollection::FIELD_COLLECTION_PREFIX_LENGTH); @@ -74,6 +72,8 @@ public function prepareRow(Row $row) { $value = $this->getFieldValues('field_collection_item', $field_name, $item_id, $revision_id); $row->setSourceProperty($field_name, $value); } + + return parent::prepareRow($row); } /** diff --git a/web/modules/paragraphs/src/Plugin/migrate/source/d7/FieldableEntity.php b/web/modules/paragraphs/src/Plugin/migrate/source/d7/FieldableEntity.php index 82587120c3..24dbdd63cc 100644 --- a/web/modules/paragraphs/src/Plugin/migrate/source/d7/FieldableEntity.php +++ b/web/modules/paragraphs/src/Plugin/migrate/source/d7/FieldableEntity.php @@ -2,10 +2,10 @@ namespace Drupal\paragraphs\Plugin\migrate\source\d7; +use Drupal\Component\Plugin\ConfigurableInterface; use Drupal\migrate_drupal\Plugin\migrate\source\d7\FieldableEntity as MigrateFieldableEntity; -use Drupal\Component\Plugin\ConfigurablePluginInterface; use Drupal\Component\Utility\NestedArray; -use Drupal\Core\Entity\EntityManagerInterface; +use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\State\StateInterface; use Drupal\migrate\Plugin\MigrationInterface; @@ -15,13 +15,13 @@ * Add and implement Configurable Plugin interface to * Drupal\migrate_drupal\Plugin\migrate\source\d7\FieldableEntity. */ -abstract class FieldableEntity extends MigrateFieldableEntity implements ConfigurablePluginInterface { +abstract class FieldableEntity extends MigrateFieldableEntity implements ConfigurableInterface { /** * {@inheritdoc} */ - public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, StateInterface $state, EntityManagerInterface $entity_manager) { - parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $state, $entity_manager); + public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, StateInterface $state, EntityTypeManagerInterface $entity_type_manager) { + parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $state, $entity_type_manager); $this->setConfiguration($configuration); } diff --git a/web/modules/paragraphs/src/Plugin/migrate/source/d7/ParagraphsItem.php b/web/modules/paragraphs/src/Plugin/migrate/source/d7/ParagraphsItem.php index 49075a3745..5bd1f6f93f 100644 --- a/web/modules/paragraphs/src/Plugin/migrate/source/d7/ParagraphsItem.php +++ b/web/modules/paragraphs/src/Plugin/migrate/source/d7/ParagraphsItem.php @@ -78,7 +78,7 @@ public function fields() { 'item_id' => $this->t('The paragraph_item id'), 'revision_id' => $this->t('The paragraph_item revision id'), 'bundle' => $this->t('The paragraph bundle'), - 'field_name' => $this - t('The paragrpah field_name'), + 'field_name' => $this->t('The paragraph field_name'), ]; return $fields; diff --git a/web/modules/paragraphs/src/Tests/Classic/ParagraphsTestBase.php b/web/modules/paragraphs/src/Tests/Classic/ParagraphsTestBase.php index efa726fb48..031ecc54ad 100644 --- a/web/modules/paragraphs/src/Tests/Classic/ParagraphsTestBase.php +++ b/web/modules/paragraphs/src/Tests/Classic/ParagraphsTestBase.php @@ -3,12 +3,7 @@ namespace Drupal\paragraphs\Tests\Classic; use Drupal\Core\Entity\Entity\EntityFormDisplay; -use Drupal\Core\Entity\Entity\EntityViewDisplay; -use Drupal\field\Entity\FieldConfig; -use Drupal\field\Entity\FieldStorageConfig; -use Drupal\field_ui\Tests\FieldUiTestTrait; -use Drupal\node\Entity\NodeType; -use Drupal\paragraphs\Entity\ParagraphsType; +use Drupal\Tests\field_ui\Traits\FieldUiTestTrait; use Drupal\simpletest\WebTestBase; use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait; diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalTestBase.php b/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalTestBase.php index 752b5de6b5..8542be2482 100644 --- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalTestBase.php +++ b/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalTestBase.php @@ -3,10 +3,7 @@ namespace Drupal\paragraphs\Tests\Experimental; use Drupal\Core\Entity\Entity\EntityFormDisplay; -use Drupal\Core\Entity\Entity\EntityViewDisplay; -use Drupal\field\Entity\FieldConfig; -use Drupal\field\Entity\FieldStorageConfig; -use Drupal\field_ui\Tests\FieldUiTestTrait; +use Drupal\Tests\field_ui\Traits\FieldUiTestTrait; use Drupal\paragraphs\Tests\Classic\ParagraphsTestBase; use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait; diff --git a/web/modules/paragraphs/templates/paragraphs-summary.html.twig b/web/modules/paragraphs/templates/paragraphs-summary.html.twig new file mode 100644 index 0000000000..b7f9330bbb --- /dev/null +++ b/web/modules/paragraphs/templates/paragraphs-summary.html.twig @@ -0,0 +1,45 @@ +{# +/** + * @file + * Default theme implementation for a paragraphs summary. + * + * Available variables: + * - expanded: Whether the summary is expanded or not. + * - content: Array of content summary items. + * - behaviors: Array of behavior summary items. + * + * @see template_preprocess() + * + * @ingroup themeable + */ +#} +{% set classes = [ + 'paragraphs-description', + expanded ? 'paragraphs-expanded-description' : 'paragraphs-collapsed-description' +] %} +{% spaceless %} + {% if content is not empty or behaviors is not empty %} + <div{{ attributes.addClass(classes) }}> + {% if content is not empty %} + <div class="paragraphs-content-wrapper"> + {%- for content_item in content -%} + <span class="summary-content">{{ content_item }}</span> + {%- if not loop.last -%}, {% endif %} + {%- endfor -%} + </div> + {% endif %} + {% if behaviors is not empty %} + <div class="paragraphs-plugin-wrapper"> + {%- for behavior_item in behaviors -%} + <span class="summary-plugin"> + {%- if behavior_item.label is not null -%} + <span class="summary-plugin-label">{{ behavior_item.label }}</span> + {%- endif -%} + {{ behavior_item.value -}} + </span> + {%- endfor -%} + </div> + {% endif %} + </div> + {% endif %} +{% endspaceless %} diff --git a/web/modules/paragraphs/tests/modules/paragraphs_test/paragraphs_test.info.yml b/web/modules/paragraphs/tests/modules/paragraphs_test/paragraphs_test.info.yml index a78e17e5e3..094c654fc5 100644 --- a/web/modules/paragraphs/tests/modules/paragraphs_test/paragraphs_test.info.yml +++ b/web/modules/paragraphs/tests/modules/paragraphs_test/paragraphs_test.info.yml @@ -1,15 +1,14 @@ name: Paragraphs test type: module description: Resources for Paragraphs tests -# core: 8.x +core_version_requirement: ^8.7.7 || ^9 hidden: true package: Paragraphs dependencies: - - paragraphs + - paragraphs:paragraphs -# Information added by Drupal.org packaging script on 2019-02-20 -version: '8.x-1.6' -core: '8.x' +# Information added by Drupal.org packaging script on 2020-02-16 +version: '8.x-1.11' project: 'paragraphs' -datestamp: 1550669588 +datestamp: 1581850832 diff --git a/web/modules/paragraphs/tests/modules/paragraphs_test/src/Plugin/paragraphs/Behavior/TestBoldTextBehavior.php b/web/modules/paragraphs/tests/modules/paragraphs_test/src/Plugin/paragraphs/Behavior/TestBoldTextBehavior.php index 376c522141..73b8c7fa35 100644 --- a/web/modules/paragraphs/tests/modules/paragraphs_test/src/Plugin/paragraphs/Behavior/TestBoldTextBehavior.php +++ b/web/modules/paragraphs/tests/modules/paragraphs_test/src/Plugin/paragraphs/Behavior/TestBoldTextBehavior.php @@ -61,7 +61,12 @@ public static function isApplicable(ParagraphsType $paragraphs_type) { */ public function settingsSummary(Paragraph $paragraph) { $bold_setting = $paragraph->getBehaviorSetting($this->getPluginId(), 'bold_text'); - return [$bold_setting ? $this->t('Bold: Yes') : $this->t('Bold: No')]; + return [ + [ + 'label' => $this->t('Bold'), + 'value' => $bold_setting ? $this->t('Yes') : $this->t('No') + ] + ]; } /** diff --git a/web/modules/paragraphs/tests/modules/paragraphs_test/src/Plugin/paragraphs/Behavior/TestTextColorBehavior.php b/web/modules/paragraphs/tests/modules/paragraphs_test/src/Plugin/paragraphs/Behavior/TestTextColorBehavior.php index 16f0bd3d57..5966d8b149 100644 --- a/web/modules/paragraphs/tests/modules/paragraphs_test/src/Plugin/paragraphs/Behavior/TestTextColorBehavior.php +++ b/web/modules/paragraphs/tests/modules/paragraphs_test/src/Plugin/paragraphs/Behavior/TestTextColorBehavior.php @@ -97,6 +97,11 @@ public function view(array &$build, Paragraph $paragraphs_entity, EntityViewDisp */ public function settingsSummary(Paragraph $paragraph) { $text_color = $paragraph->getBehaviorSetting($this->pluginId, 'text_color'); - return [$this->t('Text color: @color', ['@color' => $text_color])]; + return [ + [ + 'label' => $this->t('Text color'), + 'value' => $text_color + ] + ]; } } diff --git a/web/modules/paragraphs/src/Tests/Classic/ParagraphsAccessTest.php b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsAccessTest.php similarity index 90% rename from web/modules/paragraphs/src/Tests/Classic/ParagraphsAccessTest.php rename to web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsAccessTest.php index 78ba75f484..bc636570fc 100644 --- a/web/modules/paragraphs/src/Tests/Classic/ParagraphsAccessTest.php +++ b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsAccessTest.php @@ -1,13 +1,12 @@ <?php -namespace Drupal\paragraphs\Tests\Classic; +namespace Drupal\Tests\paragraphs\Functional\Classic; use Drupal\Core\Entity\Entity\EntityFormDisplay; -use Drupal\field_ui\Tests\FieldUiTestTrait; use Drupal\image\Entity\ImageStyle; use Drupal\language\Entity\ConfigurableLanguage; +use Drupal\Tests\field_ui\Traits\FieldUiTestTrait; use Drupal\user\RoleInterface; -use Drupal\user\Entity\Role; /** * Tests the access check of paragraphs. @@ -93,7 +92,7 @@ public function testParagraphAccessCheck() { // Remove the "access content" for anonymous users. That results in // anonymous users not being able to "view" the host entity. - /* @var Role $role */ + /* @var \Drupal\user\Entity\Role $role */ $role = \Drupal::entityTypeManager() ->getStorage('user_role') ->load(RoleInterface::ANONYMOUS_ID); @@ -117,25 +116,31 @@ public function testParagraphAccessCheck() { // Add a new paragraphs images item. $this->drupalPostForm(NULL, NULL, t('Add images')); - $images = $this->drupalGetTestFiles('image'); + $images = $this->getTestFiles('image'); + $file_system = \Drupal::service('file_system'); // Create a file, upload it. - file_unmanaged_copy($images[0]->uri, 'temporary://privateImage.jpg'); + $file_system->copy($images[0]->uri, 'temporary://privateImage.jpg'); $file_path = $this->container->get('file_system') ->realpath('temporary://privateImage.jpg'); // Create a file, upload it. - file_unmanaged_copy($images[1]->uri, 'temporary://privateImage2.jpg'); + $file_system->copy($images[1]->uri, 'temporary://privateImage2.jpg'); $file_path_2 = $this->container->get('file_system') ->realpath('temporary://privateImage2.jpg'); $edit = array( 'title[0][value]' => 'Security test node', - 'files[field_paragraphs_demo_0_subform_field_images_demo_0][]' => [$file_path, $file_path_2], + 'files[field_paragraphs_demo_0_subform_field_images_demo_0][]' => $file_path, ); $this->drupalPostForm(NULL, $edit, t('Upload')); - $this->drupalPostForm(NULL, [], t('Preview')); + + $edit = array( + 'files[field_paragraphs_demo_0_subform_field_images_demo_1][]' => $file_path_2, + ); + + $this->drupalPostForm(NULL, $edit, t('Preview')); $image_style = ImageStyle::load('medium'); $img1_url = $image_style->buildUrl('private://' . date('Y-m') . '/privateImage.jpg'); $image_url = file_url_transform_relative($img1_url); @@ -182,8 +187,8 @@ public function testParagraphAccessCheck() { // Check the remove button is present. $this->assertNotNull($this->xpath('//*[@name="field_paragraphs_demo_0_remove"]')); // Delete the Paragraph and save. - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_demo_0_remove'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_demo_0_confirm_remove'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_demo_0_remove'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_demo_0_confirm_remove'); $this->drupalPostForm(NULL, [], t('Save')); $node = $this->getNodeByTitle('delete_permissions'); $this->assertUrl('node/' . $node->id()); diff --git a/web/modules/paragraphs/src/Tests/Classic/ParagraphsAddModesTest.php b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsAddModesTest.php similarity index 97% rename from web/modules/paragraphs/src/Tests/Classic/ParagraphsAddModesTest.php rename to web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsAddModesTest.php index d8f24c6971..e934a77978 100644 --- a/web/modules/paragraphs/src/Tests/Classic/ParagraphsAddModesTest.php +++ b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsAddModesTest.php @@ -1,8 +1,7 @@ <?php -namespace Drupal\paragraphs\Tests\Classic; +namespace Drupal\Tests\paragraphs\Functional\Classic; -use Drupal\field_ui\Tests\FieldUiTestTrait; use Drupal\paragraphs\Entity\ParagraphsType; /** @@ -12,8 +11,6 @@ */ class ParagraphsAddModesTest extends ParagraphsTestBase { - use FieldUiTestTrait; - /** * Tests that paragraphs field does not allow default values. */ @@ -125,7 +122,7 @@ protected function assertAddButtons($options) { $buttons = $this->xpath('//input[@class="field-add-more-submit button js-form-submit form-submit"]'); // Check if the buttons are in the same order as the given array. foreach ($buttons as $key => $button) { - $this->assertEqual($button['value'], $options[$key]); + $this->assertEqual($button->getValue(), $options[$key]); } $this->assertTrue(count($buttons) == count($options), 'The amount of drop down options matches with the given array'); } @@ -143,7 +140,7 @@ protected function assertSelectOptions($options, $paragraphs_field) { $buttons = $this->xpath('//*[@name="' . $paragraphs_field . '[add_more][add_more_select]"]/option'); // Check if the options are in the same order as the given array. foreach ($buttons as $key => $button) { - $this->assertEqual($button['value'], $options[$key]); + $this->assertEqual($button->getValue(), $options[$key]); } $this->assertTrue(count($buttons) == count($options), 'The amount of select options matches with the given array'); $this->assertNotEqual($this->xpath('//*[@name="' . $paragraphs_field .'_add_more"]'), [], 'The add button is displayed'); diff --git a/web/modules/paragraphs/src/Tests/Classic/ParagraphsAdministrationTest.php b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsAdministrationTest.php similarity index 84% rename from web/modules/paragraphs/src/Tests/Classic/ParagraphsAdministrationTest.php rename to web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsAdministrationTest.php index 482b1e936a..08dc9184b1 100644 --- a/web/modules/paragraphs/src/Tests/Classic/ParagraphsAdministrationTest.php +++ b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsAdministrationTest.php @@ -1,8 +1,7 @@ <?php -namespace Drupal\paragraphs\Tests\Classic; +namespace Drupal\Tests\paragraphs\Functional\Classic; -use Drupal\field_ui\Tests\FieldUiTestTrait; use Drupal\paragraphs\Entity\Paragraph; /** @@ -12,8 +11,6 @@ */ class ParagraphsAdministrationTest extends ParagraphsTestBase { - use FieldUiTestTrait; - /** * Modules to enable. * @@ -65,8 +62,8 @@ public function testParagraphsRevisions() { // Create node with our paragraphs. $this->drupalGet('node/add/paragraphs'); - $this->drupalPostAjaxForm(NULL, array(), 'field_paragraphs_text_add_more'); - $this->drupalPostAjaxForm(NULL, array(), 'field_paragraphs_text_add_more'); + $this->drupalPostForm(NULL, array(), 'field_paragraphs_text_add_more'); + $this->drupalPostForm(NULL, array(), 'field_paragraphs_text_add_more'); $edit = [ 'title[0][value]' => 'TEST TITEL', 'field_paragraphs[0][subform][field_text][0][value]' => 'Test text 1', @@ -144,7 +141,7 @@ public function testParagraphsCreation() { // Assert suggested 'Add a paragraph type' link when there is no type yet. $this->drupalGet('admin/structure/paragraphs_type'); - $this->assertText('There are no paragraphs type entities yet.'); + $this->assertText('There are no Paragraphs types yet.'); $this->drupalGet('admin/structure/types/manage/paragraphs/fields/add-field'); $edit = [ 'new_storage_type' => 'field_ui:entity_reference_revisions:paragraph', @@ -180,7 +177,7 @@ public function testParagraphsCreation() { // Change the add more button to select mode. $this->clickLink(t('Manage form display')); - $this->drupalPostAjaxForm(NULL, ['fields[field_paragraphs][type]' => 'entity_reference_paragraphs'], 'field_paragraphs_settings_edit'); + $this->drupalPostForm(NULL, ['fields[field_paragraphs][type]' => 'entity_reference_paragraphs'], 'field_paragraphs_settings_edit'); $this->drupalPostForm(NULL, ['fields[field_paragraphs][settings_edit_form][settings][add_mode]' => 'select'], t('Update')); $this->drupalPostForm(NULL, [], t('Save')); @@ -209,7 +206,7 @@ public function testParagraphsCreation() { $field_name = 'field_paragraphs'; // Click on the widget settings button to open the widget settings form. - $this->drupalPostAjaxForm(NULL, array(), $field_name . "_settings_edit"); + $this->drupalPostForm(NULL, array(), $field_name . "_settings_edit"); // Enable setting. $edit = array('fields[' . $field_name . '][settings_edit_form][settings][add_mode]' => 'button'); @@ -219,7 +216,7 @@ public function testParagraphsCreation() { $this->drupalGet('admin/structure/types/manage/article/form-display'); $this->assertText('Add mode: Buttons', 'Checking the settings value.'); - $this->drupalPostAjaxForm(NULL, array(), $field_name . "_settings_edit"); + $this->drupalPostForm(NULL, array(), $field_name . "_settings_edit"); // Assert the 'Buttons' option is selected. $this->assertOptionSelected('edit-fields-field-paragraphs-settings-edit-form-settings-add-mode', 'button', 'Updated value is correct!.'); @@ -229,11 +226,11 @@ public function testParagraphsCreation() { // Checking changes on article. $this->assertRaw('<div class="paragraphs-dropbutton-wrapper"><input', 'Updated value in article.'); - $this->drupalPostAjaxForm(NULL, array(), 'field_paragraphs_text_image_add_more'); - $this->drupalPostAjaxForm(NULL, array(), 'field_paragraphs_text_image_add_more'); + $this->drupalPostForm(NULL, array(), 'field_paragraphs_text_image_add_more'); + $this->drupalPostForm(NULL, array(), 'field_paragraphs_text_image_add_more'); // Upload some images. - $files = $this->drupalGetTestFiles('image'); + $files = $this->getTestFiles('image'); $file_system = \Drupal::service('file_system'); $edit = array( @@ -264,25 +261,25 @@ public function testParagraphsCreation() { // Test for closed setting. $this->drupalGet('admin/structure/types/manage/article/form-display'); // Click on the widget settings button to open the widget settings form. - $this->drupalPostAjaxForm(NULL, array(), "field_paragraphs_settings_edit"); + $this->drupalPostForm(NULL, array(), "field_paragraphs_settings_edit"); // Enable setting. $edit = array('fields[field_paragraphs][settings_edit_form][settings][edit_mode]' => 'closed'); $this->drupalPostForm(NULL, $edit, t('Save')); // Check if the setting is stored. $this->assertText('Edit mode: Closed', 'Checking the settings value.'); - $this->drupalPostAjaxForm(NULL, array(), "field_paragraphs_settings_edit"); + $this->drupalPostForm(NULL, array(), "field_paragraphs_settings_edit"); // Assert the 'Closed' option is selected. $this->assertOptionSelected('edit-fields-field-paragraphs-settings-edit-form-settings-edit-mode', 'closed', 'Updated value correctly.'); $this->drupalGet('node/1/edit'); // The textareas for paragraphs should not be visible. $this->assertNoRaw('field_paragraphs[0][subform][field_text][0][value]'); $this->assertNoRaw('field_paragraphs[1][subform][field_text][0][value]'); - $this->assertRaw('<div class="paragraphs-collapsed-description">Test text 1, ' . $files[0]->filename); - $this->assertRaw('<div class="paragraphs-collapsed-description">Test text 2, ' . $files[1]->filename); + $this->assertRaw('<span class="summary-content">Test text 1</span>, <span class="summary-content">' . $files[0]->filename); + $this->assertRaw('<span class="summary-content">Test text 2</span>, <span class="summary-content">' . $files[1]->filename); // Test for preview option. $this->drupalGet('admin/structure/types/manage/article/form-display'); - $this->drupalPostAjaxForm(NULL, array(), "field_paragraphs_settings_edit"); + $this->drupalPostForm(NULL, array(), "field_paragraphs_settings_edit"); $edit = array('fields[field_paragraphs][settings_edit_form][settings][edit_mode]' => 'preview'); $this->drupalPostForm(NULL, $edit, t('Save')); $this->assertText('Edit mode: Preview', 'Checking the settings value.'); @@ -295,7 +292,7 @@ public function testParagraphsCreation() { // Test for open option. $this->drupalGet('admin/structure/types/manage/article/form-display'); - $this->drupalPostAjaxForm(NULL, array(), "field_paragraphs_settings_edit"); + $this->drupalPostForm(NULL, array(), "field_paragraphs_settings_edit"); // Assert the 'Preview' option is selected. $this->assertOptionSelected('edit-fields-field-paragraphs-settings-edit-form-settings-edit-mode', 'preview', 'Updated value correctly.'); // Restore the value to Open for next test. @@ -317,19 +314,21 @@ public function testParagraphsCreation() { $this->assertFieldByName('field_paragraphs[1][subform][field_text][0][value]', 'Test text 2'); $this->assertRaw('<a href="' . $img2_url . '" type="' . $img2_mime . '; length=' . $img2_size . '">' . $files[1]->filename . '</a>'); // Remove 2nd paragraph. - $this->drupalPostForm(NULL, NULL, t('Remove')); + $this->getSession()->getPage()->find('css', '[name="field_paragraphs_1_remove"]')->press(); + // Confirm the removal. + $this->drupalPostForm(NULL, [], t('Confirm removal')); $this->assertNoField('field_paragraphs[1][subform][field_text][0][value]'); $this->assertNoRaw('<a href="' . $img2_url . '" type="' . $img2_mime . '; length=' . $img2_size . '">' . $files[1]->filename . '</a>'); // Assert the paragraph is not deleted unless the user saves the node. $this->drupalGet('node/' . $node->id() . '/edit'); $this->assertRaw('<a href="' . $img2_url . '" type="' . $img2_mime . '; length=' . $img2_size . '">' . $files[1]->filename . '</a>'); // Remove the second paragraph. - $this->drupalPostForm(NULL, [], t('Remove')); + $this->getSession()->getPage()->find('css', '[name="field_paragraphs_1_remove"]')->press(); + // Confirm the removal. + $this->drupalPostForm(NULL, [], t('Confirm removal')); $this->assertNoRaw('<a href="' . $img2_url . '" type="' . $img2_mime . '; length=' . $img2_size . '">' . $files[1]->filename . '</a>'); $edit = [ 'field_paragraphs[0][subform][field_image][0][alt]' => 'test_alt', - 'field_paragraphs[0][subform][field_image][0][width]' => 300, - 'field_paragraphs[0][subform][field_image][0][height]' => 300, ]; $this->drupalPostForm(NULL, $edit, t('Save')); // Assert the paragraph is deleted after the user saves the node. @@ -375,11 +374,11 @@ public function testParagraphsCreation() { // Add a new article. $this->drupalGet('node/add/article'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_nested_test_add_more'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_nested_test_add_more'); $edit = [ 'field_paragraphs[0][subform][field_paragraphs][add_more][add_more_select]' => 'image', ]; - $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_0_subform_field_paragraphs_add_more'); + $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_subform_field_paragraphs_add_more'); // Test the new field is displayed. $this->assertFieldByName('files[field_paragraphs_0_subform_field_paragraphs_0_subform_field_image_only_0]'); @@ -399,7 +398,7 @@ public function testParagraphsCreation() { // Test that unsupported widgets are not displayed. $this->drupalGet('admin/structure/types/manage/article/form-display'); $select = $this->xpath('//*[@id="edit-fields-field-paragraphs-type"]')[0]; - $this->assertEqual(count($select->option), 2); + $this->assertCount(2, $select->findAll('css', 'option')); $this->assertRaw('value="entity_reference_paragraphs" selected="selected"'); // Check that Paragraphs is not displayed as an entity_reference field @@ -425,12 +424,12 @@ public function testParagraphsCreation() { ), array()); $this->clickLink(t('Manage form display')); $this->drupalPostForm(NULL, [], 'Save'); - $this->drupalPostAjaxForm('node/add/article', [], 'field_paragraphs_nested_test_add_more'); + $this->drupalPostForm('node/add/article', [], 'field_paragraphs_nested_test_add_more'); $edit = [ 'field_paragraphs[0][subform][field_paragraphs][add_more][add_more_select]' => 'nested_double_test', ]; - $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_0_subform_field_paragraphs_add_more'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_subform_field_paragraphs_0_subform_field_paragraphs_image_add_more'); + $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_subform_field_paragraphs_add_more'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_0_subform_field_paragraphs_0_subform_field_paragraphs_image_add_more'); $edit = array( 'title[0][value]' => 'Nested twins', ); @@ -444,7 +443,7 @@ public function testParagraphsCreation() { $this->drupalPostForm(NULL, ['required' => FALSE], t('Save settings')); // Set the Paragraph field edit mode to 'Closed'. - $this->drupalPostAjaxForm('admin/structure/types/manage/article/form-display', [], 'field_paragraphs_settings_edit'); + $this->drupalPostForm('admin/structure/types/manage/article/form-display', [], 'field_paragraphs_settings_edit'); $this->drupalPostForm(NULL, ['fields[field_paragraphs][settings_edit_form][settings][edit_mode]' => 'closed'], t('Update')); $this->drupalPostForm(NULL, [], t('Save')); @@ -461,7 +460,7 @@ public function testParagraphsCreation() { $node = $this->drupalGetNodeByTitle('Nested twins'); // Create a node with a reference in a Paragraph. - $this->drupalPostAjaxForm('node/add/article', [], 'field_paragraphs_node_test_add_more'); + $this->drupalPostForm('node/add/article', [], 'field_paragraphs_node_test_add_more'); \Drupal::service('entity_field.manager')->clearCachedFieldDefinitions(); $edit = [ 'field_paragraphs[0][subform][field_entity_reference][0][target_id]' => $node->label() . ' (' . $node->id() . ')', @@ -483,7 +482,7 @@ public function testParagraphsCreation() { $this->assertText('The referenced entity (node: 4) does not exist'); $this->assertText('Entity reference (value 1) field is required.'); // Try to collapse with an invalid reference. - $this->drupalPostAjaxForm(NULL, ['field_paragraphs[0][subform][field_entity_reference][0][target_id]' => 'foo'], 'field_paragraphs_0_collapse'); + $this->drupalPostForm(NULL, ['field_paragraphs[0][subform][field_entity_reference][0][target_id]' => 'foo'], 'field_paragraphs_0_collapse'); // Paragraph should be still in edit mode. $this->assertFieldByName('field_paragraphs[0][subform][field_entity_reference][0][target_id]'); $this->assertFieldByName('field_paragraphs[0][subform][field_entity_reference][1][target_id]'); @@ -491,11 +490,11 @@ public function testParagraphsCreation() { // Assert the validation message. $this->assertText('There are no entities matching "foo".'); // Attempt to remove the Paragraph. - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_remove'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_0_remove'); $elements = $this->xpath('//*[@name="field_paragraphs_0_confirm_remove"]'); $this->assertTrue(!empty($elements), "'Confirm removal' button appears."); // Restore the Paragraph and fix the broken reference. - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_restore'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_0_restore'); $node = $this->drupalGetNodeByTitle('Example publish/unpublish'); $edit = ['field_paragraphs[0][subform][field_entity_reference][0][target_id]' => $node->label() . ' (' . $node->id() . ')']; $this->drupalPostForm(NULL, $edit, t('Save')); @@ -505,22 +504,22 @@ public function testParagraphsCreation() { $node->delete(); // Set the Paragraph field edit mode to 'Preview'. - $this->drupalPostAjaxForm('admin/structure/types/manage/article/form-display', [], 'field_paragraphs_settings_edit'); + $this->drupalPostForm('admin/structure/types/manage/article/form-display', [], 'field_paragraphs_settings_edit'); $this->drupalPostForm(NULL, ['fields[field_paragraphs][settings_edit_form][settings][edit_mode]' => 'preview'], t('Update')); $this->drupalPostForm(NULL, [], t('Save')); $node = $this->drupalGetNodeByTitle('choke test'); // Attempt to edit the Paragraph. - $this->drupalPostAjaxForm('node/' . $node->id() . '/edit', [], 'field_paragraphs_0_edit'); + $this->drupalPostForm('node/' . $node->id() . '/edit', [], 'field_paragraphs_0_edit'); // Try to save with an invalid reference. $edit = ['field_paragraphs[0][subform][field_entity_reference][0][target_id]' => 'foo']; $this->drupalPostForm(NULL, $edit, t('Save')); $this->assertText('There are no entities matching "foo".'); // Remove the Paragraph and save the node. - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_remove'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_0_remove'); $elements = $this->xpath('//*[@name="field_paragraphs_0_confirm_remove"]'); $this->assertTrue(!empty($elements), "'Confirm removal' button appears."); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_confirm_remove'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_0_confirm_remove'); $this->drupalPostForm(NULL, [], t('Save')); $this->assertText('choke test has been updated.'); @@ -532,34 +531,7 @@ public function testParagraphsCreation() { $this->drupalGet('admin/content/files'); $this->clickLink('1 place'); $label = $this->xpath('//tbody/tr/td[1]'); - $this->assertEqual(trim(htmlspecialchars_decode(strip_tags($label[0]->asXML()))), 'test required > field_paragraphs > Paragraphs'); - } - - /** - * Asserts that a select option in the current page is checked. - * - * @param string $id - * ID of select field to assert. - * @param string $option - * Option to assert. - * @param string $message - * (optional) A message to display with the assertion. Do not translate - * messages: use format_string() to embed variables in the message text, not - * t(). If left blank, a default message will be displayed. - * @param string $group - * (optional) The group this message is in, which is displayed in a column - * in test output. Use 'Debug' to indicate this is debugging output. Do not - * translate this string. Defaults to 'Browser'; most tests do not override - * this default. - * - * @return bool - * TRUE on pass, FALSE on fail. - * - * @todo Remove function once core issue is resolved: https://www.drupal.org/node/2530092 - */ - protected function assertOptionSelected($id, $option, $message = '', $group = 'Browser') { - $elements = $this->xpath('//select[contains(@id, :id)]//option[@value=:option]', array(':id' => $id, ':option' => $option)); - return $this->assertTrue(isset($elements[0]) && !empty($elements[0]['selected']), $message ? $message : SafeMarkup::format('Option @option for field @id is selected.', array('@option' => $option, '@id' => $id)), $group); + $this->assertEqual(trim(htmlspecialchars_decode(strip_tags($label[0]->getText()))), 'test required > field_paragraphs > Paragraphs'); } /** diff --git a/web/modules/paragraphs/tests/src/Functional/ParagraphsClassicContentModerationTranslationsTest.php b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsClassicContentModerationTranslationsTest.php similarity index 98% rename from web/modules/paragraphs/tests/src/Functional/ParagraphsClassicContentModerationTranslationsTest.php rename to web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsClassicContentModerationTranslationsTest.php index 34b0e0f2d0..c8be65e788 100644 --- a/web/modules/paragraphs/tests/src/Functional/ParagraphsClassicContentModerationTranslationsTest.php +++ b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsClassicContentModerationTranslationsTest.php @@ -1,13 +1,8 @@ <?php -namespace Drupal\Tests\paragraphs\Functional; +namespace Drupal\Tests\paragraphs\Functional\Classic; -use Drupal\field_ui\Tests\FieldUiTestTrait; -use Drupal\paragraphs\Tests\Classic\ParagraphsCoreVersionUiTestTrait; use Drupal\language\Entity\ConfigurableLanguage; -use Drupal\Tests\BrowserTestBase; -use Drupal\Tests\paragraphs\FunctionalJavascript\LoginAdminTrait; -use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait; use Drupal\Tests\paragraphs\Traits\ParagraphsLastEntityQueryTrait; /** @@ -15,12 +10,8 @@ * * @group paragraphs */ -class ParagraphsClassicContentModerationTranslationsTest extends BrowserTestBase { +class ParagraphsClassicContentModerationTranslationsTest extends ParagraphsTestBase { - use LoginAdminTrait; - use FieldUiTestTrait; - use ParagraphsTestBaseTrait; - use ParagraphsCoreVersionUiTestTrait; use ParagraphsLastEntityQueryTrait; /** diff --git a/web/modules/paragraphs/src/Tests/Classic/ParagraphsConfigTest.php b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsConfigTest.php similarity index 97% rename from web/modules/paragraphs/src/Tests/Classic/ParagraphsConfigTest.php rename to web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsConfigTest.php index 64945433e9..fbaa9db07c 100644 --- a/web/modules/paragraphs/src/Tests/Classic/ParagraphsConfigTest.php +++ b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsConfigTest.php @@ -1,6 +1,6 @@ <?php -namespace Drupal\paragraphs\Tests\Classic; +namespace Drupal\Tests\paragraphs\Functional\Classic; use Drupal\language\Entity\ConfigurableLanguage; use Drupal\node\Entity\NodeType; @@ -51,7 +51,7 @@ public function testFieldTranslationDisabled() { $this->drupalPostForm('admin/config/regional/content-language', $edit, t('Save configuration')); // Create a node with a paragraph. - $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'paragraphs_field_paragraph_type_test_add_more'); + $this->drupalPostForm('node/add/paragraphed_test', [], 'paragraphs_field_paragraph_type_test_add_more'); $edit = ['title[0][value]' => 'paragraphed_title']; $this->drupalPostForm(NULL, $edit, t('Save')); @@ -159,7 +159,7 @@ public function testRequiredParagraphsField() { ]; $this->drupalPostForm(NULL, $edit, t('Save')); $this->assertText('paragraphs field is required.'); - $this->drupalPostAjaxForm(NULL, [], 'paragraphs_paragraph_type_test_add_more'); + $this->drupalPostForm(NULL, [], 'paragraphs_paragraph_type_test_add_more'); $this->drupalPostForm(NULL, $edit, t('Save')); $this->assertText('paragraphed_test test_title has been created.'); } diff --git a/web/modules/paragraphs/src/Tests/Classic/ParagraphsContactTest.php b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsContactTest.php similarity index 85% rename from web/modules/paragraphs/src/Tests/Classic/ParagraphsContactTest.php rename to web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsContactTest.php index 6ed36c0a07..58a26442e3 100644 --- a/web/modules/paragraphs/src/Tests/Classic/ParagraphsContactTest.php +++ b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsContactTest.php @@ -1,6 +1,6 @@ <?php -namespace Drupal\paragraphs\Tests\Classic; +namespace Drupal\Tests\paragraphs\Functional\Classic; use Drupal\contact\Entity\ContactForm; @@ -40,10 +40,10 @@ public function testContactForm() { // Add a paragraph to the contact form. $this->drupalGet('contact/test_contact_form'); - $this->drupalPostAjaxForm(NULL, [], 'paragraphs_paragraphs_contact_add_more'); + $this->drupalPostForm(NULL, [], 'paragraphs_paragraphs_contact_add_more'); // Check that the paragraph is displayed. $this->assertText('paragraphs_contact'); - $this->drupalPostAjaxForm(NULL, [], 'paragraphs_0_remove'); + $this->drupalPostForm(NULL, [], 'paragraphs_0_remove'); $this->assertText('Deleted Paragraph: paragraphs_contact'); } } diff --git a/web/modules/paragraphs/src/Tests/Classic/ParagraphsEditModesTest.php b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsEditModesTest.php similarity index 67% rename from web/modules/paragraphs/src/Tests/Classic/ParagraphsEditModesTest.php rename to web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsEditModesTest.php index 821f02667b..e1529bb1ce 100644 --- a/web/modules/paragraphs/src/Tests/Classic/ParagraphsEditModesTest.php +++ b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsEditModesTest.php @@ -1,8 +1,6 @@ <?php -namespace Drupal\paragraphs\Tests\Classic; - -use Drupal\field_ui\Tests\FieldUiTestTrait; +namespace Drupal\Tests\paragraphs\Functional\Classic; /** * Tests paragraphs edit modes. @@ -11,8 +9,6 @@ */ class ParagraphsEditModesTest extends ParagraphsTestBase { - use FieldUiTestTrait; - /** * Modules to enable. * @@ -42,15 +38,15 @@ public function testCollapsedSummary() { // Set edit mode to closed. $this->drupalGet('admin/structure/types/manage/paragraphed_test/form-display'); - $this->drupalPostAjaxForm(NULL, [], "field_paragraphs_settings_edit"); + $this->drupalPostForm(NULL, [], "field_paragraphs_settings_edit"); $edit = ['fields[field_paragraphs][settings_edit_form][settings][edit_mode]' => 'closed']; $this->drupalPostForm(NULL, $edit, t('Save')); // Add a paragraph. - $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_image_text_paragraph_add_more'); - $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_title_add_more'); + $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_image_text_paragraph_add_more'); + $this->drupalPostForm(NULL, NULL, 'field_paragraphs_title_add_more'); - $files = $this->drupalGetTestFiles('image'); + $files = $this->getTestFiles('image'); $file_system = \Drupal::service('file_system'); // Create a node with an image and text. @@ -64,28 +60,26 @@ public function testCollapsedSummary() { // Assert the summary is correctly generated. $this->clickLink(t('Edit')); - $this->assertRaw('<div class="paragraphs-collapsed-description">' . $files[0]->filename . ', text_summary'); - $this->assertRaw('<div class="paragraphs-collapsed-description">Title example'); + $this->assertRaw('<span class="summary-content">' . $files[0]->filename . '</span>, <span class="summary-content">text_summary</span>'); + $this->assertRaw('<span class="summary-content">Title example'); // Edit and remove alternative text. - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_edit'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit'); $edit = [ 'field_paragraphs[0][subform][field_image][0][alt]' => 'alternative_text_summary', - 'field_paragraphs[0][subform][field_image][0][width]' => 300, - 'field_paragraphs[0][subform][field_image][0][height]' => 300, ]; - $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_0_collapse'); + $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_collapse'); // Assert the summary is correctly generated. - $this->assertRaw('<div class="paragraphs-collapsed-description">alternative_text_summary, text_summary'); + $this->assertRaw('<span class="summary-content">alternative_text_summary</span>, <span class="summary-content">text_summary</span>'); // Remove image. - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_edit'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_subform_field_image_0_remove_button'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_0_subform_field_image_0_remove_button'); $this->drupalPostForm(NULL, [], t('Save')); // Assert the summary is correctly generated. $this->clickLink(t('Edit')); - $this->assertRaw('<div class="paragraphs-collapsed-description">text_summary'); + $this->assertRaw('<span class="summary-content">text_summary'); // Add a Block Paragraphs type. $this->addParagraphsType('block_paragraph'); @@ -93,14 +87,14 @@ public function testCollapsedSummary() { // Test the summary of a Block field. $this->drupalGet('node/add/paragraphed_test'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_block_paragraph_add_more'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_block_paragraph_add_more'); $edit = [ 'title[0][value]' => 'Node with a Block Paragraph', 'field_paragraphs[0][subform][field_block][0][plugin_id]' => 'system_breadcrumb_block', ]; $this->drupalPostForm(NULL, $edit, t('Save')); $this->clickLink(t('Edit')); - $this->assertRaw('<div class="paragraphs-collapsed-description">Breadcrumbs'); + $this->assertRaw('<span class="summary-content">Breadcrumbs'); } } diff --git a/web/modules/paragraphs/src/Tests/Classic/ParagraphsEntityTranslationWithNonTranslatableParagraphs.php b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsEntityTranslationWithNonTranslatableParagraphs.php similarity index 98% rename from web/modules/paragraphs/src/Tests/Classic/ParagraphsEntityTranslationWithNonTranslatableParagraphs.php rename to web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsEntityTranslationWithNonTranslatableParagraphs.php index 91c236a023..778866561c 100644 --- a/web/modules/paragraphs/src/Tests/Classic/ParagraphsEntityTranslationWithNonTranslatableParagraphs.php +++ b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsEntityTranslationWithNonTranslatableParagraphs.php @@ -1,6 +1,6 @@ <?php -namespace Drupal\paragraphs\Tests\Classic; +namespace Drupal\Tests\paragraphs\Functional\Classic; /** * Tests the translation of heavily nested / specialized setup. diff --git a/web/modules/paragraphs/src/Tests/Classic/ParagraphsFieldGroupTest.php b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsFieldGroupTest.php similarity index 90% rename from web/modules/paragraphs/src/Tests/Classic/ParagraphsFieldGroupTest.php rename to web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsFieldGroupTest.php index 2adee34a65..5a564815fb 100644 --- a/web/modules/paragraphs/src/Tests/Classic/ParagraphsFieldGroupTest.php +++ b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsFieldGroupTest.php @@ -1,6 +1,6 @@ <?php -namespace Drupal\paragraphs\Tests\Classic; +namespace Drupal\Tests\paragraphs\Functional\Classic; /** * Tests the field group on node. @@ -48,13 +48,14 @@ public function testFieldGroup() { // Put the text field into the field group. $edit = [ + 'fields[group_field][region]' => 'content', 'fields[field_text][parent]' => 'group_field' ]; $this->drupalPostForm('admin/structure/paragraphs_type/' . $paragraph_type . '/form-display', $edit, t('Save')); // Create a node with a paragraph. $this->drupalGet('node/add/' . $content_type); - $this->drupalPostAjaxForm('node/add/' . $content_type, [], 'field_paragraphs_paragraph_type_test_add_more'); + $this->drupalPostForm('node/add/' . $content_type, [], 'field_paragraphs_paragraph_type_test_add_more'); // Test if the new field group is displayed. $this->assertText('field_group'); diff --git a/web/modules/paragraphs/src/Tests/Classic/ParagraphsInlineEntityFormTest.php b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsInlineEntityFormTest.php similarity index 92% rename from web/modules/paragraphs/src/Tests/Classic/ParagraphsInlineEntityFormTest.php rename to web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsInlineEntityFormTest.php index 433a911421..4f07699de4 100644 --- a/web/modules/paragraphs/src/Tests/Classic/ParagraphsInlineEntityFormTest.php +++ b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsInlineEntityFormTest.php @@ -1,6 +1,6 @@ <?php -namespace Drupal\paragraphs\Tests\Classic; +namespace Drupal\Tests\paragraphs\Functional\Classic; /** * Tests the configuration of paragraphs in relation to ief. @@ -52,7 +52,7 @@ public function testParagraphsIEFPreview() { // Create node with one paragraph. $this->drupalGet('node/add/article'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_simple_add_more'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_simple_add_more'); // Set the values and save. $edit = [ @@ -66,7 +66,7 @@ public function testParagraphsIEFPreview() { $this->drupalGet('node/' . $node->id() . '/edit'); // Try to open the previewed paragraph. - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_edit'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit'); } /** @@ -82,7 +82,6 @@ public function testParagraphsIEFChangeOrder() { $this->addParagraphsType('simple'); $this->addParagraphsType('text'); - // Create a reference to an article. $this->fieldUIAddNewField('admin/structure/paragraphs_type/simple', 'article', 'Article', 'field_ui:entity_reference:node', [ 'settings[target_type]' => 'node', @@ -113,7 +112,7 @@ public function testParagraphsIEFChangeOrder() { // Create node with one paragraph. $this->drupalGet('node/add/article'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_simple_add_more'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_simple_add_more'); // Set the values and save. $edit = [ @@ -128,7 +127,7 @@ public function testParagraphsIEFChangeOrder() { $this->drupalGet('node/' . $node->id() . '/edit'); // Create second paragraph. - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_simple_add_more'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_simple_add_more'); // Set the values of second paragraph and change the order. $edit = [ diff --git a/web/modules/paragraphs/src/Tests/Classic/ParagraphsPreviewTest.php b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsPreviewTest.php similarity index 87% rename from web/modules/paragraphs/src/Tests/Classic/ParagraphsPreviewTest.php rename to web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsPreviewTest.php index b866c6b302..e2c2ec782a 100644 --- a/web/modules/paragraphs/src/Tests/Classic/ParagraphsPreviewTest.php +++ b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsPreviewTest.php @@ -1,8 +1,6 @@ <?php -namespace Drupal\paragraphs\Tests\Classic; - -use Drupal\field_ui\Tests\FieldUiTestTrait; +namespace Drupal\Tests\paragraphs\Functional\Classic; /** * Tests the configuration of paragraphs. @@ -11,8 +9,6 @@ */ class ParagraphsPreviewTest extends ParagraphsTestBase { - use FieldUiTestTrait; - /** * Modules to enable. * @@ -45,7 +41,7 @@ public function testParagraphsPreview() { $test_text_2 = 'dummy_preview_text_2'; // Create node with two paragraphs. $this->drupalGet('node/add/article'); - $this->drupalPostAjaxForm(NULL, array(), 'field_paragraphs_text_add_more'); + $this->drupalPostForm(NULL, array(), 'field_paragraphs_text_add_more'); // Set the value of the paragraphs. $edit = [ 'title[0][value]' => 'Page_title', @@ -64,12 +60,12 @@ public function testParagraphsPreview() { $this->clickLink('Back to content editing'); $paragraph_1 = $this->xpath('//*[@id="edit-field-paragraphs-0-subform-field-text-0-value"]')[0]; - $this->assertEqual($paragraph_1['value'], $test_text_1); + $this->assertEqual($paragraph_1->getValue(), $test_text_1); $this->drupalPostForm(NULL, $edit, t('Save')); $this->clickLink('Edit'); - $this->drupalPostAjaxForm(NULL, array(), 'field_paragraphs_text_add_more'); + $this->drupalPostForm(NULL, array(), 'field_paragraphs_text_add_more'); $edit = [ 'field_paragraphs[1][subform][field_text][0][value]' => $test_text_2, ]; @@ -98,8 +94,8 @@ public function testParagraphsPreview() { $this->clickLink('Back to content editing'); $paragraph_1 = $this->xpath('//*[@id="edit-field-paragraphs-0-subform-field-text-0-value"]')[0]; $paragraph_2 = $this->xpath('//*[@id="edit-field-paragraphs-1-subform-field-text-0-value"]')[0]; - $this->assertEqual($paragraph_1['value'], $test_text_1); - $this->assertEqual($paragraph_2['value'], $new_test_text_2); + $this->assertEqual($paragraph_1->getValue(), $test_text_1); + $this->assertEqual($paragraph_2->getValue(), $new_test_text_2); $this->drupalPostForm(NULL, [], t('Save')); $this->assertRaw($test_text_1); diff --git a/web/modules/paragraphs/src/Tests/Classic/ParagraphsSummaryFormatterTest.php b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsSummaryFormatterTest.php similarity index 88% rename from web/modules/paragraphs/src/Tests/Classic/ParagraphsSummaryFormatterTest.php rename to web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsSummaryFormatterTest.php index 1d53a731ef..3790ca6a11 100644 --- a/web/modules/paragraphs/src/Tests/Classic/ParagraphsSummaryFormatterTest.php +++ b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsSummaryFormatterTest.php @@ -1,8 +1,6 @@ <?php -namespace Drupal\paragraphs\Tests\Classic; - -use Drupal\field_ui\Tests\FieldUiTestTrait; +namespace Drupal\Tests\paragraphs\Functional\Classic; /** * Tests the paragraphs summary formatter. @@ -11,8 +9,6 @@ */ class ParagraphsSummaryFormatterTest extends ParagraphsTestBase { - use FieldUiTestTrait; - /** * Modules to enable. * @@ -48,8 +44,8 @@ public function testParagraphsSummaryFormatter() { $edit = ['fields[field_paragraphs][type]' => 'paragraph_summary']; $this->drupalPostForm(NULL, $edit, t('Save')); // Add a paragraph. - $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_add_more'); - $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_title_add_more'); + $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_add_more'); + $this->drupalPostForm(NULL, NULL, 'field_paragraphs_title_add_more'); // Create a node with a text. $edit = [ diff --git a/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsTestBase.php b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsTestBase.php new file mode 100644 index 0000000000..f053c3d903 --- /dev/null +++ b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsTestBase.php @@ -0,0 +1,208 @@ +<?php + +namespace Drupal\Tests\paragraphs\Functional\Classic; + +use Drupal\Core\Entity\Entity\EntityFormDisplay; +use Drupal\Tests\BrowserTestBase; +use Drupal\Tests\field_ui\Traits\FieldUiTestTrait; +use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait; +use Drupal\Tests\paragraphs\Traits\ParagraphsCoreVersionUiTestTrait; + +/** + * Base class for tests. + */ +abstract class ParagraphsTestBase extends BrowserTestBase { + + use FieldUiTestTrait, ParagraphsCoreVersionUiTestTrait, ParagraphsTestBaseTrait; + + /** + * Drupal user object created by loginAsAdmin(). + * + * @var \Drupal\user\UserInterface + */ + protected $admin_user = NULL; + + /** + * List of permissions used by loginAsAdmin(). + * + * @var array + */ + protected $admin_permissions = []; + + /** + * Modules to enable. + * + * @var array + */ + public static $modules = [ + 'node', + 'paragraphs', + 'field', + 'field_ui', + 'block', + 'paragraphs_test', + ]; + + /** + * {@inheritdoc} + */ + protected $defaultTheme = 'stark'; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + // Place the breadcrumb, tested in fieldUIAddNewField(). + $this->drupalPlaceBlock('system_breadcrumb_block'); + $this->drupalPlaceBlock('local_tasks_block'); + $this->drupalPlaceBlock('local_actions_block'); + $this->drupalPlaceBlock('page_title_block'); + + $this->admin_permissions = [ + 'administer content types', + 'administer node fields', + 'administer paragraphs types', + 'administer node form display', + 'administer paragraph fields', + 'administer paragraph form display', + ]; + } + + /** + * Creates an user with admin permissions and log in. + * + * @param array $additional_permissions + * Additional permissions that will be granted to admin user. + * @param bool $reset_permissions + * Flag to determine if default admin permissions will be replaced by + * $additional_permissions. + * + * @return object + * Newly created and logged in user object. + */ + function loginAsAdmin($additional_permissions = [], $reset_permissions = FALSE) { + $permissions = $this->admin_permissions; + + if ($reset_permissions) { + $permissions = $additional_permissions; + } + elseif (!empty($additional_permissions)) { + $permissions = array_merge($permissions, $additional_permissions); + } + + $this->admin_user = $this->drupalCreateUser($permissions); + $this->drupalLogin($this->admin_user); + return $this->admin_user; + } + + /** + * Sets the Paragraphs widget add mode. + * + * @param string $content_type + * Content type name where to set the widget mode. + * @param string $paragraphs_field + * Paragraphs field to change the mode. + * @param string $mode + * Mode to be set. ('dropdown', 'select' or 'button'). + */ + protected function setAddMode($content_type, $paragraphs_field, $mode) { + $form_display = EntityFormDisplay::load('node.' . $content_type . '.default') + ->setComponent($paragraphs_field, [ + 'type' => 'entity_reference_paragraphs', + 'settings' => ['add_mode' => $mode] + ]); + $form_display->save(); + } + + /** + * Sets the allowed Paragraphs types that can be added. + * + * @param string $content_type + * Content type name that contains the paragraphs field. + * @param array $paragraphs_types + * Array of paragraphs types that will be modified. + * @param bool $selected + * Whether or not the paragraphs types will be enabled. + * @param string $paragraphs_field + * Paragraphs field name that does the reference. + */ + protected function setAllowedParagraphsTypes($content_type, $paragraphs_types, $selected, $paragraphs_field) { + $edit = []; + $this->drupalGet('admin/structure/types/manage/' . $content_type . '/fields/node.' . $content_type . '.' . $paragraphs_field); + foreach ($paragraphs_types as $paragraphs_type) { + $edit['settings[handler_settings][target_bundles_drag_drop][' . $paragraphs_type . '][enabled]'] = $selected; + } + $this->drupalPostForm(NULL, $edit, t('Save settings')); + } + + /** + * Sets the weight of a given Paragraphs type. + * + * @param string $content_type + * Content type name that contains the paragraphs field. + * @param string $paragraphs_type + * ID of Paragraph type that will be modified. + * @param int $weight + * Weight to be set. + * @param string $paragraphs_field + * Paragraphs field name that does the reference. + */ + protected function setParagraphsTypeWeight($content_type, $paragraphs_type, $weight, $paragraphs_field) { + $this->drupalGet('admin/structure/types/manage/' . $content_type . '/fields/node.' . $content_type . '.' . $paragraphs_field); + $edit['settings[handler_settings][target_bundles_drag_drop][' . $paragraphs_type . '][weight]'] = $weight; + $this->drupalPostForm(NULL, $edit, t('Save settings')); + } + + /** + * Sets the default paragraph type. + * + * @param $content_type + * Content type name that contains the paragraphs field. + * @param $paragraphs_name + * Paragraphs name. + * @param $paragraphs_field_name + * Paragraphs field name to be used. + * @param $default_type + * Default paragraph type which should be set. + */ + protected function setDefaultParagraphType($content_type, $paragraphs_name, $paragraphs_field_name, $default_type) { + $this->drupalGet('admin/structure/types/manage/' . $content_type . '/form-display'); + $this->drupalPostForm(NULL, [], $paragraphs_field_name); + $this->drupalPostForm(NULL, ['fields[' . $paragraphs_name . '][settings_edit_form][settings][default_paragraph_type]' => $default_type], t('Update')); + $this->drupalPostForm(NULL, [], t('Save')); + } + + /** + * Removes the default paragraph type. + * + * @param $content_type + * Content type name that contains the paragraphs field. + */ + protected function removeDefaultParagraphType($content_type) { + $this->drupalGet('node/add/' . $content_type); + $this->drupalPostForm(NULL, [], 'Remove'); + $this->drupalPostForm(NULL, [], 'Confirm removal'); + $this->assertNoText('No paragraphs added yet.'); + } + + /** + * Sets the Paragraphs widget display mode. + * + * @param string $content_type + * Content type name where to set the widget mode. + * @param string $paragraphs_field + * Paragraphs field to change the mode. + * @param string $mode + * Mode to be set. ('closed', 'preview' or 'open'). + * 'preview' is only allowed in the classic widget. Use + * setParagraphsWidgetSettings for the experimental widget, instead. + */ + protected function setParagraphsWidgetMode($content_type, $paragraphs_field, $mode) { + $this->drupalGet('admin/structure/types/manage/' . $content_type . '/form-display'); + $this->drupalPostForm(NULL, [], $paragraphs_field . '_settings_edit'); + $this->drupalPostForm(NULL, ['fields[' . $paragraphs_field . '][settings_edit_form][settings][edit_mode]' => $mode], t('Update')); + $this->drupalPostForm(NULL, [], 'Save'); + } + +} diff --git a/web/modules/paragraphs/src/Tests/Classic/ParagraphsTranslationTest.php b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsTranslationTest.php similarity index 96% rename from web/modules/paragraphs/src/Tests/Classic/ParagraphsTranslationTest.php rename to web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsTranslationTest.php index bfddda5fc0..1cd2d009c2 100644 --- a/web/modules/paragraphs/src/Tests/Classic/ParagraphsTranslationTest.php +++ b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsTranslationTest.php @@ -1,6 +1,6 @@ <?php -namespace Drupal\paragraphs\Tests\Classic; +namespace Drupal\Tests\paragraphs\Functional\Classic; use Drupal\Component\Render\FormattableMarkup; use Drupal\Core\Entity\Entity\EntityFormDisplay; @@ -137,8 +137,8 @@ public function testParagraphTranslation() { $this->assertText(t('Example published and unpublished')); $this->clickLink(t('Edit')); - $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_demo_nested_paragraph_add_more'); - $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_demo_1_subform_field_paragraphs_demo_text_add_more'); + $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_nested_paragraph_add_more'); + $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_1_subform_field_paragraphs_demo_text_add_more'); $edit = [ 'field_paragraphs_demo[0][subform][status][value]' => FALSE, 'field_paragraphs_demo[1][subform][field_paragraphs_demo][0][subform][field_text_demo][0][value]' => 'Dummy text' @@ -263,7 +263,7 @@ public function testParagraphTranslation() { $this->drupalPostForm(NULL, $edit, t('Save settings')); // Create a node with an image paragraph, its alt and title text. - $files = $this->drupalGetTestFiles('image'); + $files = $this->getTestFiles('image'); $file_system = \Drupal::service('file_system'); $file_path = $file_system->realpath($file_system->realpath($files[0]->uri)); $this->drupalGet('node/add/paragraphed_content_demo'); @@ -435,7 +435,7 @@ public function testParagraphTranslationMultilingual() { $this->drupalPostForm(NULL, NULL, t('Add images')); $this->assertParagraphsButtons(1); // Upload an image and check the paragraphs buttons are still displayed. - $images = $this->drupalGetTestFiles('image')[0]; + $images = $this->getTestFiles('image')[0]; $edit = [ 'title[0][value]' => 'Title in english', 'files[field_paragraphs_demo_0_subform_field_images_demo_0][]' => $images->uri, @@ -467,7 +467,7 @@ public function testParagraphTranslationMultilingual() { // Edit the french translation and upload a new image. $this->clickLink('Edit'); - $images = $this->drupalGetTestFiles('image')[1]; + $images = $this->getTestFiles('image')[1]; $this->drupalPostForm(NULL, [ 'files[field_paragraphs_demo_0_subform_field_images_demo_1][]' => $images->uri, ], t('Upload')); @@ -499,12 +499,12 @@ public function testParagraphTranslationMultilingual() { $this->assertParagraphsButtons(2); // Add an 'Images' paragraph inside the nested one, check the paragraphs // langcode are still 'en' and the paragraphs buttons are still displayed. - $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_demo_1_subform_field_paragraphs_demo_images_add_more'); + $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_1_subform_field_paragraphs_demo_images_add_more'); $this->assertParagraphsLangcode($node->id()); $this->assertParagraphsButtons(2); // Upload a new image, check the paragraphs langcode are still 'en' and the // paragraphs buttons are displayed. - $images = $this->drupalGetTestFiles('image')[2]; + $images = $this->getTestFiles('image')[2]; $this->drupalPostForm(NULL, [ 'files[field_paragraphs_demo_1_subform_field_paragraphs_demo_0_subform_field_images_demo_0][]' => $images->uri, ], t('Upload')); @@ -548,7 +548,7 @@ public function testParagraphTranslationMultilingual() { $this->assertParagraphsLangcode($node->id(), 'de', 'fr'); $this->assertNoParagraphsButtons(2); // Upload another image. - $images = $this->drupalGetTestFiles('image')[3]; + $images = $this->getTestFiles('image')[3]; $this->drupalPostForm(NULL, [ 'files[field_paragraphs_demo_1_subform_field_paragraphs_demo_0_subform_field_images_demo_1][]' => $images->uri, ], t('Upload')); @@ -577,12 +577,12 @@ public function testParagraphTranslationMultilingual() { 'title[0][value]' => 'Title in english', 'langcode[0][value]' => 'en', ]; - $this->drupalPostForm(NULL, $edit, t('Add images')); + $this->drupalPostForm(NULL, $edit, 'field_paragraphs_demo_images_add_more'); $this->assertParagraphsLangcode($node->id(), 'de'); $this->assertParagraphsButtons(3); // Upload a new image, check the paragraphs langcode are still 'de' and the // paragraphs buttons are displayed. - $images = $this->drupalGetTestFiles('image')[4]; + $images = $this->getTestFiles('image')[4]; $this->drupalPostForm(NULL, [ 'files[field_paragraphs_demo_2_subform_field_images_demo_0][]' => $images->uri, ], t('Upload')); @@ -619,9 +619,9 @@ public function testParagraphsMultilingualWorkflow() { // Check that the paragraphs buttons are displayed and add an 'Images' // paragraph inside the nested paragraph. $this->assertParagraphsButtons(1); - $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_demo_0_subform_field_paragraphs_demo_images_add_more'); + $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_0_subform_field_paragraphs_demo_images_add_more'); // Upload an image and check the paragraphs buttons are still displayed. - $images = $this->drupalGetTestFiles('image')[0]; + $images = $this->getTestFiles('image')[0]; $this->drupalPostForm(NULL, [ 'files[field_paragraphs_demo_0_subform_field_paragraphs_demo_0_subform_field_images_demo_0][]' => $images->uri, ], t('Upload')); @@ -637,7 +637,7 @@ public function testParagraphsMultilingualWorkflow() { $this->assertParagraphsLangcode($node1->id(), 'de'); $this->assertParagraphsButtons(1); // Change the node langcode to 'english' and upload another image. - $images = $this->drupalGetTestFiles('image')[1]; + $images = $this->getTestFiles('image')[1]; $edit = [ 'title[0][value]' => 'Title in german (en)', 'langcode[0][value]' => 'en', @@ -667,9 +667,9 @@ public function testParagraphsMultilingualWorkflow() { // Check that the paragraphs buttons are displayed and add an 'Images' // paragraph inside the nested paragraph. $this->assertParagraphsButtons(1); - $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_demo_0_subform_field_paragraphs_demo_images_add_more'); + $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_0_subform_field_paragraphs_demo_images_add_more'); // Upload an image and check the paragraphs buttons are still displayed. - $images = $this->drupalGetTestFiles('image')[0]; + $images = $this->getTestFiles('image')[0]; $edit = [ 'title[0][value]' => 'Title in english', 'files[field_paragraphs_demo_0_subform_field_paragraphs_demo_0_subform_field_images_demo_0][]' => $images->uri, @@ -691,13 +691,13 @@ public function testParagraphsMultilingualWorkflow() { 'title[0][value]' => 'Title in english (de)', 'langcode[0][value]' => 'de', ]; - $this->drupalPostForm(NULL, $edit, t('Add images')); + $this->drupalPostForm(NULL, $edit, 'field_paragraphs_demo_images_add_more'); // Check the paragraphs langcode are still 'en' and their buttons are shown. $this->assertParagraphsLangcode($node2->id()); $this->assertParagraphsButtons(2); // Upload an image, check the paragraphs langcode are still 'en' and their // buttons are displayed. - $images = $this->drupalGetTestFiles('image')[1]; + $images = $this->getTestFiles('image')[1]; $this->drupalPostForm(NULL, [ 'files[field_paragraphs_demo_1_subform_field_images_demo_0][]' => $images->uri, ], t('Upload')); @@ -731,13 +731,13 @@ public function testParagraphsMultilingualWorkflow() { $this->assertParagraphsLangcode($node2->id()); $this->assertParagraphsButtons(2); // Add another 'Images' paragraph with node langcode as 'english'. - $this->drupalPostForm(NULL, NULL, t('Add images')); + $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_images_add_more'); // Check the paragraph langcode are still 'en' and their buttons are shown. $this->assertParagraphsLangcode($node2->id()); $this->assertParagraphsButtons(3); // Upload an image, check the paragraphs langcode are still 'en' and their // buttons are displayed. - $images = $this->drupalGetTestFiles('image')[2]; + $images = $this->getTestFiles('image')[2]; $this->drupalPostForm(NULL, [ 'files[field_paragraphs_demo_2_subform_field_images_demo_0][]' => $images->uri, ], t('Upload')); @@ -756,13 +756,13 @@ public function testParagraphsMultilingualWorkflow() { 'title[0][value]' => 'Title in english (de)', 'langcode[0][value]' => 'de', ]; - $this->drupalPostForm(NULL, $edit, t('Add images')); + $this->drupalPostForm(NULL, $edit, 'field_paragraphs_demo_images_add_more'); // Check the paragraphs langcode are still 'en' and their buttons are shown. $this->assertParagraphsLangcode($node2->id()); $this->assertParagraphsButtons(4); // Upload an image, check the paragraphs langcode are still 'en' and their // buttons are displayed. - $images = $this->drupalGetTestFiles('image')[3]; + $images = $this->getTestFiles('image')[3]; $this->drupalPostForm(NULL, [ 'files[field_paragraphs_demo_3_subform_field_images_demo_0][]' => $images->uri, ], t('Upload')); diff --git a/web/modules/paragraphs/src/Tests/Classic/ParagraphsTypesTest.php b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsTypesTest.php similarity index 72% rename from web/modules/paragraphs/src/Tests/Classic/ParagraphsTypesTest.php rename to web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsTypesTest.php index 200db0fc5e..ef7d4ec74d 100644 --- a/web/modules/paragraphs/src/Tests/Classic/ParagraphsTypesTest.php +++ b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsTypesTest.php @@ -1,6 +1,6 @@ <?php -namespace Drupal\paragraphs\Tests\Classic; +namespace Drupal\Tests\paragraphs\Functional\Classic; use Drupal\paragraphs\Entity\ParagraphsType; @@ -30,7 +30,7 @@ public function testRemoveTypesWithContent() { // Add a test node with a Paragraph. $this->drupalGet('node/add/paragraphed_test'); - $this->drupalPostAjaxForm(NULL, [], 'paragraphs_paragraph_type_test_add_more'); + $this->drupalPostForm(NULL, [], 'paragraphs_paragraph_type_test_add_more'); $edit = ['title[0][value]' => 'test_node']; $this->drupalPostForm(NULL, $edit, t('Save')); $this->assertText('paragraphed_test test_node has been created.'); @@ -61,7 +61,7 @@ public function testParagraphTypeIcon() { // Add the paragraph type with icon. $this->drupalGet('admin/structure/paragraphs_type/add'); $this->assertText('Paragraph type icon'); - $test_files = $this->drupalGetTestFiles('image'); + $test_files = $this->getTestFiles('image'); $fileSystem = \Drupal::service('file_system'); $edit = [ 'label' => 'Test paragraph type', @@ -90,7 +90,7 @@ public function testParagraphTypeIcon() { // Delete the icon. $this->drupalGet('admin/structure/paragraphs_type/test_paragraph_type_icon'); - $this->drupalPostAjaxForm(NULL, [], 'icon_file_remove_button'); + $this->drupalPostForm(NULL, [], 'icon_file_remove_button'); $this->drupalPostForm(NULL, [], t('Save')); // Check that the icon file usage has been deregistered. @@ -98,6 +98,46 @@ public function testParagraphTypeIcon() { $this->assertEqual($usages, []); } + /** + * Tests the paragraph type default icon settings. + */ + public function testParagraphTypeDefaultIcon() { + /** @var \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository */ + $entity_repository = \Drupal::service('entity.repository'); + + $admin_user = $this->drupalCreateUser([ + 'administer paragraphs types', + 'access files overview', + ]); + $this->drupalLogin($admin_user); + // Add the paragraph type with icon. + $this->drupalGet('admin/structure/paragraphs_type/add'); + $this->assertText('Paragraph type icon'); + $test_files = $this->getTestFiles('image'); + $fileSystem = \Drupal::service('file_system'); + $edit = [ + 'label' => 'Test paragraph type', + 'id' => 'test_paragraph_type_icon', + 'files[icon_file]' => $fileSystem->realpath($test_files[0]->uri), + ]; + $this->drupalPostForm(NULL, $edit, t('Save and manage fields')); + $this->assertText('Saved the Test paragraph type Paragraphs type.'); + + // Check if the icon is created from defaults if not exists. + $paragraph_type = ParagraphsType::load('test_paragraph_type_icon'); + $file = $entity_repository->loadEntityByUuid('file', $paragraph_type->get('icon_uuid')); + $file->delete(); + $this->resetAll(); + $this->drupalGet('admin/structure/paragraphs_type'); + // New default icon name. + $default_icon_name = 'test_paragraph_type_icon-default-icon.png'; + $this->assertRaw($default_icon_name); + $this->clickLink('Edit'); + $this->assertText($default_icon_name); + $file = $entity_repository->loadEntityByUuid('file', $paragraph_type->get('icon_uuid')); + $this->assertTrue($file); + } + /** * Test the paragraph type description settings. */ @@ -123,7 +163,7 @@ public function testParagraphTypeDescription() { $this->assertText('Description'); $this->assertText($description_text); $this->assertRaw($description_markup); - //Check if description is at Description column + // Check if description is at Description column. $header_position = count($this->xpath('//table/thead/tr/th[.="Description"]/preceding-sibling::th')); $row_position = count($this->xpath('//table/tbody/tr/td[.="' . $description_text . '"]/preceding-sibling::td')); $this->assertEqual($header_position, $row_position); diff --git a/web/modules/paragraphs/src/Tests/Classic/ParagraphsUiTest.php b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsUiTest.php similarity index 94% rename from web/modules/paragraphs/src/Tests/Classic/ParagraphsUiTest.php rename to web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsUiTest.php index 3edcddc57c..b4939e237e 100644 --- a/web/modules/paragraphs/src/Tests/Classic/ParagraphsUiTest.php +++ b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsUiTest.php @@ -1,8 +1,7 @@ <?php -namespace Drupal\paragraphs\Tests\Classic; +namespace Drupal\Tests\paragraphs\Functional\Classic; -use Drupal\field_ui\Tests\FieldUiTestTrait; use Drupal\language\Entity\ConfigurableLanguage; /** @@ -12,8 +11,6 @@ */ class ParagraphsUiTest extends ParagraphsTestBase { - use FieldUiTestTrait; - /** * Modules to enable. * @@ -108,8 +105,8 @@ public function testEmptyRequiredField() { // "remove" mode in the required field. $title = 'Remove mode'; $this->drupalGet('node/add/paragraphed_content_demo'); - $this->drupalPostAjaxForm(NULL, [], 'field_content_text_image_add_more'); - $this->drupalPostAjaxForm(NULL, [], 'field_content_0_remove'); + $this->drupalPostForm(NULL, [], 'field_content_text_image_add_more'); + $this->drupalPostForm(NULL, [], 'field_content_0_remove'); $this->assertNoText($field_title . ' field is required'); $this->drupalPostForm(NULL, ['title[0][value]' => $title], t('Save')); $this->assertText($field_title . ' field is required'); diff --git a/web/modules/paragraphs/src/Tests/Classic/ParagraphsWidgetButtonsTest.php b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsWidgetButtonsTest.php similarity index 78% rename from web/modules/paragraphs/src/Tests/Classic/ParagraphsWidgetButtonsTest.php rename to web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsWidgetButtonsTest.php index 6917bdbe9c..aeb7786d38 100644 --- a/web/modules/paragraphs/src/Tests/Classic/ParagraphsWidgetButtonsTest.php +++ b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsWidgetButtonsTest.php @@ -1,8 +1,6 @@ <?php -namespace Drupal\paragraphs\Tests\Classic; - -use Drupal\field_ui\Tests\FieldUiTestTrait; +namespace Drupal\Tests\paragraphs\Functional\Classic; /** * Tests paragraphs widget buttons. @@ -11,8 +9,6 @@ */ class ParagraphsWidgetButtonsTest extends ParagraphsTestBase { - use FieldUiTestTrait; - /** * Tests the widget buttons of paragraphs. */ @@ -27,7 +23,7 @@ public function testWidgetButtons() { // Add a text field to the text_paragraph type. static::fieldUIAddNewField('admin/structure/paragraphs_type/' . $paragraph_type, 'text', 'Text', 'text_long', [], []); - $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_add_more'); + $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_add_more'); // Create a node with a Paragraph. $text = 'recognizable_text'; @@ -35,7 +31,7 @@ public function testWidgetButtons() { 'title[0][value]' => 'paragraphs_mode_test', 'field_paragraphs[0][subform][field_text][0][value]' => $text, ]; - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_text_paragraph_add_more'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_text_paragraph_add_more'); $this->drupalPostForm(NULL, $edit, t('Save')); $node = $this->drupalGetNodeByTitle('paragraphs_mode_test'); @@ -49,18 +45,18 @@ public function testWidgetButtons() { $this->setParagraphsWidgetMode('paragraphed_test', 'field_paragraphs', 'closed'); $this->drupalGet('node/' . $node->id() . '/edit'); // Click "Edit" button. - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_edit'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_1_edit'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_1_edit'); $this->assertFieldByName('field_paragraphs[0][subform][field_text][0][value]', $text); $closed_mode_text = 'closed_mode_text'; // Click "Collapse" button on both paragraphs. $edit = ['field_paragraphs[0][subform][field_text][0][value]' => $closed_mode_text]; - $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_0_collapse'); + $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_collapse'); $edit = ['field_paragraphs[1][subform][field_text][0][value]' => $closed_mode_text]; - $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_1_collapse'); + $this->drupalPostForm(NULL, $edit, 'field_paragraphs_1_collapse'); // Verify that we have warning message for each paragraph. $this->assertNoUniqueText('You have unsaved changes on this Paragraph item.'); - $this->assertRaw('<div class="paragraphs-collapsed-description">' . $closed_mode_text); + $this->assertRaw('<span class="summary-content">' . $closed_mode_text); $this->drupalPostForm(NULL, [], t('Save')); $this->assertText('paragraphed_test ' . $node->label() . ' has been updated.'); $this->assertText($closed_mode_text); @@ -69,12 +65,12 @@ public function testWidgetButtons() { $this->setParagraphsWidgetMode('paragraphed_test', 'field_paragraphs', 'preview'); $this->drupalGet('node/' . $node->id() . '/edit'); // Click "Edit" button. - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_edit'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit'); $this->assertFieldByName('field_paragraphs[0][subform][field_text][0][value]', $closed_mode_text); $preview_mode_text = 'preview_mode_text'; $edit = ['field_paragraphs[0][subform][field_text][0][value]' => $preview_mode_text]; // Click "Collapse" button. - $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_0_collapse'); + $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_collapse'); $this->assertText('You have unsaved changes on this Paragraph item.'); $this->assertText($preview_mode_text); $this->drupalPostForm(NULL, [], t('Save')); @@ -85,10 +81,10 @@ public function testWidgetButtons() { $this->drupalGet('node/' . $node->id() . '/edit'); $this->assertText($preview_mode_text); // Click "Remove" button. - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_remove'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_0_remove'); $this->assertText('Deleted Paragraph: text_paragraph'); // Click "Restore" button. - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_restore'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_0_restore'); $this->assertFieldByName('field_paragraphs[0][subform][field_text][0][value]', $preview_mode_text); $restore_text = 'restore_text'; $edit = ['field_paragraphs[0][subform][field_text][0][value]' => $restore_text]; @@ -100,10 +96,10 @@ public function testWidgetButtons() { $this->drupalGet('node/' . $node->id() . '/edit'); $this->assertText($restore_text); // Click "Remove" button. - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_remove'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_0_remove'); $this->assertText('Deleted Paragraph: text_paragraph'); // Click "Confirm Removal" button. - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_confirm_remove'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_0_confirm_remove'); $this->drupalPostForm(NULL, [], t('Save')); $this->assertText('paragraphed_test ' . $node->label() . ' has been updated.'); $this->assertNoText($restore_text); diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalAccessTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalAccessTest.php similarity index 80% rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalAccessTest.php rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalAccessTest.php index 71ab13c5b3..0d5e062fe2 100644 --- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalAccessTest.php +++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalAccessTest.php @@ -1,11 +1,12 @@ <?php -namespace Drupal\paragraphs\Tests\Experimental; +namespace Drupal\Tests\paragraphs\Functional\Experimental; -use Drupal\field_ui\Tests\FieldUiTestTrait; use Drupal\Core\Entity\Entity\EntityFormDisplay; +use Drupal\filter\Entity\FilterFormat; use Drupal\image\Entity\ImageStyle; use Drupal\language\Entity\ConfigurableLanguage; +use Drupal\Tests\field_ui\Traits\FieldUiTestTrait; use Drupal\user\RoleInterface; use Drupal\user\Entity\Role; @@ -116,21 +117,28 @@ public function testParagraphAccessCheck() { // Add a new Paragraphs images item. $this->drupalPostForm(NULL, NULL, t('Add images')); - $images = $this->drupalGetTestFiles('image'); + $images = $this->getTestFiles('image'); // Create a file, upload it. - file_unmanaged_copy($images[0]->uri, 'temporary://privateImage.jpg'); + $file_system = \Drupal::service('file_system'); + $file_system->copy($images[0]->uri, 'temporary://privateImage.jpg'); $file_path = $this->container->get('file_system') ->realpath('temporary://privateImage.jpg'); // Create a file, upload it. - file_unmanaged_copy($images[1]->uri, 'temporary://privateImage2.jpg'); + $file_system->copy($images[1]->uri, 'temporary://privateImage2.jpg'); $file_path_2 = $this->container->get('file_system') ->realpath('temporary://privateImage2.jpg'); $edit = array( 'title[0][value]' => 'Security test node', - 'files[field_paragraphs_demo_0_subform_field_images_demo_0][]' => [$file_path, $file_path_2], + 'files[field_paragraphs_demo_0_subform_field_images_demo_0][]' => $file_path, + ); + + $this->drupalPostForm(NULL, $edit, t('Upload')); + + $edit = array( + 'files[field_paragraphs_demo_0_subform_field_images_demo_1][]' => $file_path_2, ); $this->drupalPostForm(NULL, $edit, t('Upload')); @@ -181,7 +189,7 @@ public function testParagraphAccessCheck() { // Check the remove button is present. $this->assertNotNull($this->xpath('//*[@name="field_paragraphs_demo_0_remove"]')); // Delete the Paragraph and save. - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_demo_0_remove'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_demo_0_remove'); $this->drupalPostForm(NULL, [], t('Save')); $node = $this->getNodeByTitle('delete_permissions'); $this->assertUrl('node/' . $node->id()); @@ -249,4 +257,47 @@ public function testParagraphAccessCheck() { $this->assertRaw('paragraph--unpublished'); } + /** + * Tests the Paragraph validation with filter access. + */ + public function testParagraphsTextFormatValidation() { + $filtered_html_format = FilterFormat::create([ + 'format' => 'filtered_html', + 'name' => 'Filtered HTML', + ]); + $filtered_html_format->save(); + $permissions = [ + 'create paragraphed_content_demo content', + 'edit any paragraphed_content_demo content', + $filtered_html_format->getPermissionName() + ]; + $this->loginAsAdmin($permissions); + // Create a node with a Text Paragraph using the filtered html format. + $this->drupalGet('node/add/paragraphed_content_demo'); + $this->drupalPostForm(NULL, NULL, t('Add text')); + $this->assertText('Text'); + $edit = [ + 'title[0][value]' => 'access_validation_test', + 'field_paragraphs_demo[0][subform][field_text_demo][0][value]' => 'Test', + ]; + $this->drupalPostForm(NULL, $edit, t('Save')); + $this->assertText('paragraphed_content_demo access_validation_test has been created.'); + $this->drupalLogout(); + // Login as an user without the Text Format permission. + $user = $this->drupalCreateUser([ + 'administer nodes', + 'edit any paragraphed_content_demo content', + ]); + $this->drupalLogin($user); + $node = $this->getNodeByTitle('access_validation_test'); + $this->drupalGet('node/' . $node->id() . '/edit'); + $this->drupalPostForm(NULL, [], t('Save')); + $this->assertText('paragraphed_content_demo access_validation_test has been updated.'); + $this->drupalGet('node/' . $node->id() . '/edit'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_demo_0_collapse'); + $this->drupalPostForm(NULL, [], t('Save')); + $this->assertText('paragraphed_content_demo access_validation_test has been updated.'); + $this->assertNoText('The value you selected is not a valid choice.'); + } + } diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalAddModesTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalAddModesTest.php similarity index 97% rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalAddModesTest.php rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalAddModesTest.php index 2fa86f4aca..d524c644bb 100644 --- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalAddModesTest.php +++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalAddModesTest.php @@ -1,8 +1,7 @@ <?php -namespace Drupal\paragraphs\Tests\Experimental; +namespace Drupal\Tests\paragraphs\Functional\Experimental; -use Drupal\field_ui\Tests\FieldUiTestTrait; use Drupal\paragraphs\Entity\ParagraphsType; /** @@ -12,8 +11,6 @@ */ class ParagraphsExperimentalAddModesTest extends ParagraphsExperimentalTestBase { - use FieldUiTestTrait; - /** * Tests that paragraphs field does not allow default values. */ @@ -121,10 +118,10 @@ public function testSelectMode() { */ protected function assertAddButtons($options) { $this->drupalGet('node/add/paragraphed_test'); - $buttons = $this->xpath('//input[@class="field-add-more-submit button js-form-submit form-submit"]'); + $buttons = $this->xpath('//input[@class="field-add-more-submit paragraphs-add-wrapper button js-form-submit form-submit"]'); // Check if the buttons are in the same order as the given array. foreach ($buttons as $key => $button) { - $this->assertEqual($button['value'], $options[$key]); + $this->assertEqual($button->getValue(), $options[$key]); } $this->assertTrue(count($buttons) == count($options), 'The amount of drop down options matches with the given array'); } @@ -142,7 +139,7 @@ protected function assertSelectOptions($options, $paragraphs_field) { $buttons = $this->xpath('//*[@name="' . $paragraphs_field . '[add_more][add_more_select]"]/option'); // Check if the options are in the same order as the given array. foreach ($buttons as $key => $button) { - $this->assertEqual($button['value'], $options[$key]); + $this->assertEqual($button->getValue(), $options[$key]); } $this->assertTrue(count($buttons) == count($options), 'The amount of select options matches with the given array'); $this->assertNotEqual($this->xpath('//*[@name="' . $paragraphs_field .'_add_more"]'), [], 'The add button is displayed'); diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalAdministrationTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalAdministrationTest.php similarity index 84% rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalAdministrationTest.php rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalAdministrationTest.php index 18bbc64531..8c3189703b 100644 --- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalAdministrationTest.php +++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalAdministrationTest.php @@ -1,8 +1,7 @@ <?php -namespace Drupal\paragraphs\Tests\Experimental; +namespace Drupal\Tests\paragraphs\Functional\Experimental; -use Drupal\field_ui\Tests\FieldUiTestTrait; use Drupal\paragraphs\Entity\Paragraph; use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait; @@ -13,7 +12,6 @@ */ class ParagraphsExperimentalAdministrationTest extends ParagraphsExperimentalTestBase { - use FieldUiTestTrait; use ParagraphsTestBaseTrait; /** @@ -68,8 +66,8 @@ public function testParagraphsRevisions() { // Create node with our paragraphs. $this->drupalGet('node/add/paragraphs'); - $this->drupalPostAjaxForm(NULL, array(), 'field_paragraphs_text_add_more'); - $this->drupalPostAjaxForm(NULL, array(), 'field_paragraphs_text_add_more'); + $this->drupalPostForm(NULL, array(), 'field_paragraphs_text_add_more'); + $this->drupalPostForm(NULL, array(), 'field_paragraphs_text_add_more'); $edit = [ 'title[0][value]' => 'TEST TITEL', 'field_paragraphs[0][subform][field_text][0][value]' => 'Test text 1', @@ -146,7 +144,7 @@ public function testParagraphsCreation() { // Assert suggested 'Add a paragraph type' link when there is no type yet. $this->drupalGet('admin/structure/paragraphs_type'); - $this->assertText('There are no paragraphs type entities yet.'); + $this->assertText('There are no Paragraphs types yet.'); $this->drupalGet('admin/structure/types/manage/paragraphs/fields/add-field'); $edit = [ 'new_storage_type' => 'field_ui:entity_reference_revisions:paragraph', @@ -182,7 +180,7 @@ public function testParagraphsCreation() { // Change the add more button to select mode. $this->clickLink(t('Manage form display')); - $this->drupalPostAjaxForm(NULL, ['fields[field_paragraphs][type]' => 'paragraphs'], 'field_paragraphs_settings_edit'); + $this->drupalPostForm(NULL, ['fields[field_paragraphs][type]' => 'paragraphs'], 'field_paragraphs_settings_edit'); $this->drupalPostForm(NULL, ['fields[field_paragraphs][settings_edit_form][settings][add_mode]' => 'select'], t('Update')); $this->drupalPostForm(NULL, [], t('Save')); @@ -211,7 +209,7 @@ public function testParagraphsCreation() { $field_name = 'field_paragraphs'; // Click on the widget settings button to open the widget settings form. - $this->drupalPostAjaxForm(NULL, ['fields[field_paragraphs][type]' => 'paragraphs'], $field_name . "_settings_edit"); + $this->drupalPostForm(NULL, ['fields[field_paragraphs][type]' => 'paragraphs'], $field_name . "_settings_edit"); // Enable setting. $edit = array('fields[' . $field_name . '][settings_edit_form][settings][add_mode]' => 'button'); @@ -221,17 +219,17 @@ public function testParagraphsCreation() { $this->drupalGet('admin/structure/types/manage/article/form-display'); $this->assertText('Add mode: Buttons', 'Checking the settings value.'); - $this->drupalPostAjaxForm(NULL, array(), $field_name . "_settings_edit"); + $this->drupalPostForm(NULL, array(), $field_name . "_settings_edit"); // Assert the 'Buttons' option is selected. $this->assertOptionSelected('edit-fields-field-paragraphs-settings-edit-form-settings-add-mode', 'button', 'Updated value is correct!.'); // Add two Text + Image paragraphs in article. $this->drupalGet('node/add/article'); - $this->drupalPostAjaxForm(NULL, array(), 'field_paragraphs_text_image_add_more'); - $this->drupalPostAjaxForm(NULL, array(), 'field_paragraphs_text_image_add_more'); + $this->drupalPostForm(NULL, array(), 'field_paragraphs_text_image_add_more'); + $this->drupalPostForm(NULL, array(), 'field_paragraphs_text_image_add_more'); // Upload some images. - $files = $this->drupalGetTestFiles('image'); + $files = $this->getTestFiles('image'); $file_system = \Drupal::service('file_system'); $edit = array( @@ -262,25 +260,25 @@ public function testParagraphsCreation() { // Test for closed setting. $this->drupalGet('admin/structure/types/manage/article/form-display'); // Click on the widget settings button to open the widget settings form. - $this->drupalPostAjaxForm(NULL, array(), "field_paragraphs_settings_edit"); + $this->drupalPostForm(NULL, array(), "field_paragraphs_settings_edit"); // Enable setting. $edit = array('fields[field_paragraphs][settings_edit_form][settings][edit_mode]' => 'closed'); $this->drupalPostForm(NULL, $edit, t('Save')); // Check if the setting is stored. $this->assertText('Edit mode: Closed', 'Checking the settings value.'); - $this->drupalPostAjaxForm(NULL, array(), "field_paragraphs_settings_edit"); + $this->drupalPostForm(NULL, array(), "field_paragraphs_settings_edit"); // Assert the 'Closed' option is selected. $this->assertOptionSelected('edit-fields-field-paragraphs-settings-edit-form-settings-edit-mode', 'closed', 'Updated value correctly.'); $this->drupalGet('node/1/edit'); // The textareas for paragraphs should not be visible. $this->assertNoRaw('field_paragraphs[0][subform][field_text][0][value]'); $this->assertNoRaw('field_paragraphs[1][subform][field_text][0][value]'); - $this->assertRaw('<div class="paragraphs-collapsed-description">Test text 1, ' . $files[0]->filename); - $this->assertRaw('<div class="paragraphs-collapsed-description">Test text 2, ' . $files[1]->filename); + $this->assertRaw('<span class="summary-content">Test text 1</span>, <span class="summary-content">' . $files[0]->filename); + $this->assertRaw('<span class="summary-content">Test text 2</span>, <span class="summary-content">' . $files[1]->filename); // Test for preview option. $this->drupalGet('admin/structure/types/manage/article/form-display'); - $this->drupalPostAjaxForm(NULL, array(), "field_paragraphs_settings_edit"); + $this->drupalPostForm(NULL, array(), "field_paragraphs_settings_edit"); $edit = [ 'fields[field_paragraphs][settings_edit_form][settings][edit_mode]' => 'closed', 'fields[field_paragraphs][settings_edit_form][settings][closed_mode]' => 'preview', @@ -297,7 +295,7 @@ public function testParagraphsCreation() { // Test for open option. $this->drupalGet('admin/structure/types/manage/article/form-display'); - $this->drupalPostAjaxForm(NULL, array(), "field_paragraphs_settings_edit"); + $this->drupalPostForm(NULL, array(), "field_paragraphs_settings_edit"); // Assert the "Closed" and "Preview" options are selected. $this->assertOptionSelected('edit-fields-field-paragraphs-settings-edit-form-settings-edit-mode', 'closed', 'Correctly updated the "Edit mode" value.'); $this->assertOptionSelected('edit-fields-field-paragraphs-settings-edit-form-settings-closed-mode', 'preview', 'Correctly updated the "Closed mode" value.'); @@ -320,19 +318,17 @@ public function testParagraphsCreation() { $this->assertFieldByName('field_paragraphs[1][subform][field_text][0][value]', 'Test text 2'); $this->assertRaw('<a href="' . $img2_url . '" type="' . $img2_mime . '; length=' . $img2_size . '">' . $files[1]->filename . '</a>'); // Remove 2nd paragraph. - $this->drupalPostForm(NULL, NULL, t('Remove')); + $this->getSession()->getPage()->find('css', '[name="field_paragraphs_1_remove"]')->press(); $this->assertNoField('field_paragraphs[1][subform][field_text][0][value]'); $this->assertNoRaw('<a href="' . $img2_url . '" type="' . $img2_mime . '; length=' . $img2_size . '">' . $files[1]->filename . '</a>'); // Assert the paragraph is not deleted unless the user saves the node. $this->drupalGet('node/' . $node->id() . '/edit'); $this->assertRaw('<a href="' . $img2_url . '" type="' . $img2_mime . '; length=' . $img2_size . '">' . $files[1]->filename . '</a>'); // Remove the second paragraph. - $this->drupalPostForm(NULL, [], t('Remove')); + $this->getSession()->getPage()->find('css', '[name="field_paragraphs_1_remove"]')->press(); $this->assertNoRaw('<a href="' . $img2_url . '" type="' . $img2_mime . '; length=' . $img2_size . '">' . $files[1]->filename . '</a>'); $edit = [ 'field_paragraphs[0][subform][field_image][0][alt]' => 'test_alt', - 'field_paragraphs[0][subform][field_image][0][width]' => 300, - 'field_paragraphs[0][subform][field_image][0][height]' => 300, ]; $this->drupalPostForm(NULL, $edit, t('Save')); // Assert the paragraph is deleted after the user saves the node. @@ -378,7 +374,7 @@ public function testParagraphsCreation() { // Add a new article. $this->drupalGet('node/add/article'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_nested_test_add_more'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_nested_test_add_more'); // Ensure that nested header actions do not add a visible weight field. $this->assertNoFieldByName('field_paragraphs[0][subform][field_paragraphs][header_actions][_weight]'); @@ -386,7 +382,7 @@ public function testParagraphsCreation() { $edit = [ 'field_paragraphs[0][subform][field_paragraphs][add_more][add_more_select]' => 'image', ]; - $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_0_subform_field_paragraphs_add_more'); + $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_subform_field_paragraphs_add_more'); // Test the new field is displayed. $this->assertFieldByName('files[field_paragraphs_0_subform_field_paragraphs_0_subform_field_image_only_0]'); @@ -406,7 +402,7 @@ public function testParagraphsCreation() { // Test that unsupported widgets are not displayed. $this->drupalGet('admin/structure/types/manage/article/form-display'); $select = $this->xpath('//*[@id="edit-fields-field-paragraphs-type"]')[0]; - $this->assertEqual(count($select->option), 2); + $this->assertCount(2, $select->findAll('css', 'option')); $this->assertRaw('value="paragraphs" selected="selected"'); // Check that Paragraphs is not displayed as an entity_reference field @@ -432,12 +428,12 @@ public function testParagraphsCreation() { ), array()); $this->clickLink(t('Manage form display')); $this->drupalPostForm(NULL, [], 'Save'); - $this->drupalPostAjaxForm('node/add/article', [], 'field_paragraphs_nested_test_add_more'); + $this->drupalPostForm('node/add/article', [], 'field_paragraphs_nested_test_add_more'); $edit = [ 'field_paragraphs[0][subform][field_paragraphs][add_more][add_more_select]' => 'nested_double_test', ]; - $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_0_subform_field_paragraphs_add_more'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_subform_field_paragraphs_0_subform_field_paragraphs_image_add_more'); + $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_subform_field_paragraphs_add_more'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_0_subform_field_paragraphs_0_subform_field_paragraphs_image_add_more'); $edit = array( 'title[0][value]' => 'Nested twins', ); @@ -471,7 +467,7 @@ public function testParagraphsCreation() { $node = $this->drupalGetNodeByTitle('Nested twins'); // Create a node with a reference in a Paragraph. - $this->drupalPostAjaxForm('node/add/article', [], 'field_paragraphs_node_test_add_more'); + $this->drupalPostForm('node/add/article', [], 'field_paragraphs_node_test_add_more'); \Drupal::service('entity_field.manager')->clearCachedFieldDefinitions(); $edit = [ 'field_paragraphs[0][subform][field_entity_reference][0][target_id]' => $node->label() . ' (' . $node->id() . ')', @@ -485,21 +481,19 @@ public function testParagraphsCreation() { // Adding another required paragraph and deleting that again should not // validate closed paragraphs but trying to save the node should. - $this->drupalPostAjaxForm(NULL, array(), 'field_paragraphs_node_test_add_more'); + $this->drupalPostForm(NULL, array(), 'field_paragraphs_node_test_add_more'); $this->assertNoText('The referenced entity (node: ' . $node->id() . ') does not exist.'); $this->assertFieldByName('field_paragraphs[1][subform][field_entity_reference][0][target_id]'); - $this->drupalPostAjaxForm(NULL, array(), 'field_paragraphs_1_remove'); + $this->drupalPostForm(NULL, array(), 'field_paragraphs_1_remove'); $this->assertNoText('The referenced entity (node: ' . $node->id() . ') does not exist.'); $this->assertNoFieldByName('field_paragraphs[1][subform][field_entity_reference][0][target_id]'); $this->drupalPostForm(NULL, [], t('Save')); - $this->assertText('The referenced entity (node: ' . $node->id() . ') does not exist.'); + $this->assertText('Validation error on collapsed paragraph field_entity_reference.0.target_id: The referenced entity (node: ' . $node->id() . ') does not exist.'); // Attempt to edit the Paragraph. - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_edit'); - // Validate that the reference is removed. - $this->assertNoErrorsLogged(); + $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit'); // Try to collapse with an invalid reference. - $this->drupalPostAjaxForm(NULL, ['field_paragraphs[0][subform][field_entity_reference][0][target_id]' => 'foo'], 'field_paragraphs_0_collapse'); + $this->drupalPostForm(NULL, ['field_paragraphs[0][subform][field_entity_reference][0][target_id]' => 'foo'], 'field_paragraphs_0_collapse'); // Paragraph should be still in edit mode. $this->assertFieldByName('field_paragraphs[0][subform][field_entity_reference][0][target_id]'); $this->assertFieldByName('field_paragraphs[0][subform][field_entity_reference][1][target_id]'); @@ -525,13 +519,13 @@ public function testParagraphsCreation() { // Attempt to edit the Paragraph. $this->drupalGet('node/' . $node->id() . '/edit'); // Attempt to edit the Paragraph. - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_edit'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit'); // Try to save with an invalid reference. $edit = ['field_paragraphs[0][subform][field_entity_reference][0][target_id]' => 'foo']; $this->drupalPostForm(NULL, $edit, t('Save')); $this->assertText('There are no entities matching "foo".'); // Remove the Paragraph and save the node. - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_remove'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_0_remove'); $this->drupalPostForm(NULL, [], t('Save')); $this->assertText('choke test has been updated.'); @@ -550,34 +544,7 @@ public function testParagraphsCreation() { $this->drupalGet('admin/content/files'); $this->clickLink('1 place'); $label = $this->xpath('//tbody/tr/td[1]'); - $this->assertEqual(trim(htmlspecialchars_decode(strip_tags($label[0]->asXML()))), 'test required > field_paragraphs > Paragraphs'); - } - - /** - * Asserts that a select option in the current page is checked. - * - * @param string $id - * ID of select field to assert. - * @param string $option - * Option to assert. - * @param string $message - * (optional) A message to display with the assertion. Do not translate - * messages: use format_string() to embed variables in the message text, not - * t(). If left blank, a default message will be displayed. - * @param string $group - * (optional) The group this message is in, which is displayed in a column - * in test output. Use 'Debug' to indicate this is debugging output. Do not - * translate this string. Defaults to 'Browser'; most tests do not override - * this default. - * - * @return bool - * TRUE on pass, FALSE on fail. - * - * @todo Remove function once core issue is resolved: https://www.drupal.org/node/2530092 - */ - protected function assertOptionSelected($id, $option, $message = '', $group = 'Browser') { - $elements = $this->xpath('//select[contains(@id, :id)]//option[@value=:option]', array(':id' => $id, ':option' => $option)); - return $this->assertTrue(isset($elements[0]) && !empty($elements[0]['selected']), $message ? $message : SafeMarkup::format('Option @option for field @id is selected.', array('@option' => $option, '@id' => $id)), $group); + $this->assertEqual(trim(htmlspecialchars_decode(strip_tags($label[0]->getText()))), 'test required > field_paragraphs > Paragraphs'); } /** diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalAlterByTypeTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalAlterByTypeTest.php similarity index 95% rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalAlterByTypeTest.php rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalAlterByTypeTest.php index b39a865d62..ceaa62f3c4 100644 --- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalAlterByTypeTest.php +++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalAlterByTypeTest.php @@ -1,6 +1,6 @@ <?php -namespace Drupal\paragraphs\Tests\Experimental; +namespace Drupal\Tests\paragraphs\Functional\Experimental; /** * Tests paragraphs experimental alter widget by type. diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalBehaviorsTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalBehaviorsTest.php similarity index 86% rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalBehaviorsTest.php rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalBehaviorsTest.php index 7a6f4dd9ad..207a5eb581 100644 --- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalBehaviorsTest.php +++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalBehaviorsTest.php @@ -1,9 +1,6 @@ <?php -namespace Drupal\paragraphs\Tests\Experimental; - -use Drupal\field_ui\Tests\FieldUiTestTrait; -use Drupal\paragraphs\Entity\Paragraph; +namespace Drupal\Tests\paragraphs\Functional\Experimental; /** * Tests paragraphs behavior plugins. @@ -12,8 +9,6 @@ */ class ParagraphsExperimentalBehaviorsTest extends ParagraphsExperimentalTestBase { - use FieldUiTestTrait; - /** * Modules to enable. * @@ -172,7 +167,7 @@ public function testBehaviorPluginsFields() { 'behavior_plugins[test_text_color][enabled]' => TRUE, ]; $this->drupalPostForm('admin/structure/paragraphs_type/' . $paragraph_type, $edit, t('Save')); - $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_test_add_more'); + $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_test_add_more'); $edit = [ 'title[0][value]' => 'paragraph with no fields', 'field_paragraphs[0][subform][field_text_test][0][value]' => 'my behavior plugin does not have any field', @@ -185,25 +180,14 @@ public function testBehaviorPluginsFields() { $this->drupalPostForm('admin/structure/paragraphs_type/fieldless', ['behavior_plugins[test_dummy_behavior][enabled]' => TRUE], t('Save')); $this->drupalGet('node/add/paragraphed_test'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_fieldless_add_more'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_fieldless_add_more'); $edit = ['title[0][value]' => t('Fieldless')]; $this->drupalPostForm(NULL, $edit, t('Save')); $this->assertResponse(200); - $field_definition = \Drupal::service('entity_field.manager')->getFieldDefinitions('paragraph', $paragraph_type)['uid']; - $field_definition->getConfig($paragraph_type)->save(); - - // Enable the test field selection plugin. - $edit = [ - 'behavior_plugins[test_field_selection][enabled]' => TRUE, - ]; - $this->drupalPostForm('admin/structure/paragraphs_type/' . $paragraph_type, $edit, t('Save')); - // Assert that the uid field is not shown as an option for the select. - $this->drupalGet('admin/structure/paragraphs_type/' . $paragraph_type); - $this->assertNoOption('edit-behavior-plugins-test-field-selection-settings-field-selection', 'uid'); // Add a paragraphed content. - $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_test_add_more'); + $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_test_add_more'); $edit = [ 'title[0][value]' => 'field_override_test', 'field_paragraphs[0][subform][field_text_test][0][value]' => 'This is a test', @@ -211,8 +195,8 @@ public function testBehaviorPluginsFields() { $this->drupalPostForm(NULL, $edit, 'Save'); // Check that the summary does not have the user displayed. $node = $this->getNodeByTitle('field_override_test'); - $this->drupalPostAjaxForm('node/' . $node->id() . '/edit', [], 'field_paragraphs_0_collapse'); - $this->assertRaw('paragraphs-collapsed-description">This is a test'); + $this->drupalPostForm('node/' . $node->id() . '/edit', [], 'field_paragraphs_0_collapse'); + $this->assertRaw('class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">This is a test'); } /** @@ -249,8 +233,8 @@ public function testCollapsedSummary() { $this->drupalPostForm('admin/structure/paragraphs_type/' . $paragraph_type, $edit, t('Save')); // Add a node and enabled plugins. - $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_nested_paragraph_add_more'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_1_subform_paragraphs_text_paragraph_add_more'); + $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_nested_paragraph_add_more'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_1_subform_paragraphs_text_paragraph_add_more'); $this->assertField('field_paragraphs[0][behavior_plugins][test_bold_text][bold_text]'); $this->assertField('field_paragraphs[1][behavior_plugins][test_bold_text][bold_text]'); @@ -272,11 +256,11 @@ public function testCollapsedSummary() { $this->assertFieldByXPath('//*[@id="edit-field-paragraphs-1-top-icons"]/span[@class="paragraphs-icon paragraphs-icon-bold"]'); // Assert that the summary includes the text of the behavior plugins. - $this->assertRaw('class="paragraphs-collapsed-description">first_paragraph, Bold: Yes, Text color: blue'); - $this->assertRaw('class="paragraphs-collapsed-description">nested_paragraph, Bold: No, Text color: blue, Bold: Yes'); + $this->assertRaw('first_paragraph</span></div><div class="paragraphs-plugin-wrapper"><span class="summary-plugin"><span class="summary-plugin-label">Bold</span>Yes</span><span class="summary-plugin"><span class="summary-plugin-label">Text color</span>blue</span>'); + $this->assertRaw('nested_paragraph</span></div><div class="paragraphs-plugin-wrapper"><span class="summary-plugin"><span class="summary-plugin-label">Bold</span>Yes</span></div></div>'); // Add an empty nested paragraph. - $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_nested_paragraph_add_more'); + $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_nested_paragraph_add_more'); $edit = [ 'title[0][value]' => 'collapsed_test', ]; @@ -284,7 +268,7 @@ public function testCollapsedSummary() { // Check an empty nested paragraph summary. $this->clickLink('Edit'); - $this->assertRaw('class="paragraphs-collapsed-description">'); + $this->assertRaw('class="paragraphs-description paragraphs-collapsed-description">'); } @@ -324,9 +308,9 @@ public function testBehaviorSubform() { $this->drupalPostForm('admin/structure/paragraphs_type/' . $paragraph_type, $edit, t('Save')); // Add a node and enabled plugins. - $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_nested_paragraph_add_more'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_text_paragraph_add_more'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_subform_field_nested_text_paragraph_add_more'); + $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_nested_paragraph_add_more'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_text_paragraph_add_more'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_0_subform_field_nested_text_paragraph_add_more'); $edit = [ 'title[0][value]' => 'collapsed_test', 'field_paragraphs[0][subform][field_nested][0][subform][field_text][0][value]' => 'nested text paragraph', @@ -344,7 +328,6 @@ public function testBehaviorSubform() { 'field_paragraphs[1][_weight]' => 0, ]; $this->drupalPostForm(NULL, $edit, t('Save')); - $this->assertNoErrorsLogged(); $this->clickLink('Edit'); $this->assertFieldByName('field_paragraphs[0][behavior_plugins][test_text_color][text_color]', 'red'); diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalConfigTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalConfigTest.php similarity index 98% rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalConfigTest.php rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalConfigTest.php index 728136208d..252b63923c 100644 --- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalConfigTest.php +++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalConfigTest.php @@ -1,6 +1,6 @@ <?php -namespace Drupal\paragraphs\Tests\Experimental; +namespace Drupal\Tests\paragraphs\Functional\Experimental; use Drupal\language\Entity\ConfigurableLanguage; use Drupal\node\Entity\NodeType; @@ -52,7 +52,7 @@ public function testFieldTranslationDisabled() { $this->drupalPostForm('admin/config/regional/content-language', $edit, t('Save configuration')); // Create a node with a paragraph. - $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_paragraph_type_test_add_more'); + $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_paragraph_type_test_add_more'); $edit = ['title[0][value]' => 'paragraphed_title']; $this->drupalPostForm(NULL, $edit, t('Save')); diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalContactTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalContactTest.php similarity index 87% rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalContactTest.php rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalContactTest.php index 4bf2e28894..9b84214317 100644 --- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalContactTest.php +++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalContactTest.php @@ -1,6 +1,6 @@ <?php -namespace Drupal\paragraphs\Tests\Experimental; +namespace Drupal\Tests\paragraphs\Functional\Experimental; use Drupal\contact\Entity\ContactForm; @@ -39,10 +39,10 @@ public function testContactForm() { $this->addParagraphsField($contact_form->id(), 'paragraphs', 'contact_message'); // Add a paragraph to the contact form. $this->drupalGet('contact/test_contact_form'); - $this->drupalPostAjaxForm(NULL, [], 'paragraphs_paragraphs_contact_add_more'); + $this->drupalPostForm(NULL, [], 'paragraphs_paragraphs_contact_add_more'); // Check that the paragraph is displayed. $this->assertText('paragraphs_contact'); - $this->drupalPostAjaxForm(NULL, [], 'paragraphs_0_remove'); + $this->drupalPostForm(NULL, [], 'paragraphs_0_remove'); $elements = $this->xpath('//table[starts-with(@id, :id)]/tbody', [':id' => 'paragraphs-values']); $header = $this->xpath('//table[starts-with(@id, :id)]/thead', [':id' => 'paragraphs-values']); $this->assertEqual($elements, []); diff --git a/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalContentModerationTranslationsTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalContentModerationTranslationsTest.php similarity index 98% rename from web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalContentModerationTranslationsTest.php rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalContentModerationTranslationsTest.php index 113b5b1c50..d734de56f9 100644 --- a/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalContentModerationTranslationsTest.php +++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalContentModerationTranslationsTest.php @@ -1,13 +1,8 @@ <?php -namespace Drupal\Tests\paragraphs\Functional; +namespace Drupal\Tests\paragraphs\Functional\Experimental; -use Drupal\field_ui\Tests\FieldUiTestTrait; -use Drupal\paragraphs\Tests\Classic\ParagraphsCoreVersionUiTestTrait; use Drupal\language\Entity\ConfigurableLanguage; -use Drupal\Tests\BrowserTestBase; -use Drupal\Tests\paragraphs\FunctionalJavascript\LoginAdminTrait; -use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait; use Drupal\Tests\paragraphs\Traits\ParagraphsLastEntityQueryTrait; /** @@ -15,12 +10,8 @@ * * @group paragraphs */ -class ParagraphsExperimentalContentModerationTranslationsTest extends BrowserTestBase { +class ParagraphsExperimentalContentModerationTranslationsTest extends ParagraphsExperimentalTestBase { - use LoginAdminTrait; - use FieldUiTestTrait; - use ParagraphsTestBaseTrait; - use ParagraphsCoreVersionUiTestTrait; use ParagraphsLastEntityQueryTrait; /** diff --git a/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalDragAndDropModeTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalDragAndDropModeTest.php similarity index 98% rename from web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalDragAndDropModeTest.php rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalDragAndDropModeTest.php index 8cd041303d..c99d382fc9 100644 --- a/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalDragAndDropModeTest.php +++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalDragAndDropModeTest.php @@ -1,21 +1,17 @@ <?php -namespace Drupal\Tests\paragraphs\Functional; +namespace Drupal\Tests\paragraphs\Functional\Experimental; use Drupal\Core\Entity\Entity\EntityFormDisplay; use Drupal\node\Entity\Node; use Drupal\paragraphs\Entity\Paragraph; -use Drupal\Tests\BrowserTestBase; -use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait; /** * Tests the drag and drop mode of paragraphs. * * @group paragraphs */ -class ParagraphsExperimentalDragAndDropModeTest extends BrowserTestBase { - - use ParagraphsTestBaseTrait; +class ParagraphsExperimentalDragAndDropModeTest extends ParagraphsExperimentalTestBase { /** * Modules to be enabled. @@ -44,7 +40,6 @@ public function setUp() { 'region' => 'content', 'settings' => [ 'edit_mode' => 'closed', - 'add_mode' => 'modal', 'form_display_mode' => 'default', ], ]; @@ -879,4 +874,23 @@ public function testChangeParagraphMoveAllFromNestedContainer() { $this->assertEquals($container->id(), $text_paragraph_2->get('parent_id')->value); } + /** + * Tests enabling and saving drag and drop with an empty node title. + */ + public function testEmptyNodeTitle() { + + // Create node. + $this->drupalGet('/node/add/paragraphed_test'); + $this->getSession()->getPage()->pressButton('Add text'); + + // Enable drag and drop. + $this->drupalPostForm(NULL, [], 'Drag & drop'); + + // Complete drag and drop. + $this->drupalPostForm(NULL, [], 'Complete drag & drop'); + $this->assertSession()->fieldExists('field_paragraphs[0][subform][field_text][0][value]'); + $this->assertSession()->pageTextNotContains('Title field is required.'); + + } + } diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalDuplicateFeatureTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalDuplicateFeatureTest.php similarity index 88% rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalDuplicateFeatureTest.php rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalDuplicateFeatureTest.php index cd18ca97a9..ef93e2fc67 100644 --- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalDuplicateFeatureTest.php +++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalDuplicateFeatureTest.php @@ -1,6 +1,6 @@ <?php -namespace Drupal\paragraphs\Tests\Experimental; +namespace Drupal\Tests\paragraphs\Functional\Experimental; /** * Tests paragraphs duplicate feature. @@ -31,8 +31,8 @@ public function testDuplicateButton() { // Add a text field to the text_paragraph type. static::fieldUIAddNewField('admin/structure/paragraphs_type/' . $paragraph_type, 'text', 'Text', 'text_long', [], []); - $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_add_more'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_text_paragraph_add_more'); + $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_add_more'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_text_paragraph_add_more'); // Create a node with a Paragraph. $text_01 = 'recognizable_text_01'; @@ -50,7 +50,7 @@ public function testDuplicateButton() { // Click "Duplicate" button on A and move C to the first position. $edit = ['field_paragraphs[2][_weight]' => -1]; - $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_0_duplicate'); + $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_duplicate'); $this->assertFieldByName('field_paragraphs[0][subform][field_text][0][value]', 'A'); $this->assertFieldByName('field_paragraphs[0][_weight]', 1); $this->assertFieldByName('field_paragraphs[1][subform][field_text][0][value]', 'B'); @@ -77,8 +77,8 @@ public function testDuplicateButton() { $this->assertFieldByName('field_paragraphs[3][subform][field_text][0][value]', 'B'); // Delete the second A, then duplicate C. - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_1_remove'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_2_duplicate'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_1_remove'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_2_duplicate'); $this->drupalPostForm(NULL, [], t('Save')); $this->drupalGet('node/' . $node->id() . '/edit'); @@ -92,7 +92,7 @@ public function testDuplicateButton() { // Disable show duplicate action. $this->drupalGet('admin/structure/types/manage/paragraphed_test/form-display'); $this->assertText('Features: Duplicate, Collapse / Edit all'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_settings_edit'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_settings_edit'); $this->drupalPostForm(NULL, ['fields[field_paragraphs][settings_edit_form][settings][features][duplicate]' => FALSE], t('Update')); $this->assertText('Features: Collapse / Edit all'); $this->drupalPostForm(NULL, [], 'Save'); @@ -104,7 +104,7 @@ public function testDuplicateButton() { // Enable show duplicate action. $this->drupalGet('admin/structure/types/manage/paragraphed_test/form-display'); $this->assertText('Features: Collapse / Edit all'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_settings_edit'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_settings_edit'); $this->drupalPostForm(NULL, ['fields[field_paragraphs][settings_edit_form][settings][features][duplicate]' => TRUE], t('Update')); $this->assertText('Features: Duplicate, Collapse / Edit all'); $this->drupalPostForm(NULL, [], 'Save'); @@ -136,7 +136,7 @@ public function testDuplicateButtonWithNesting() { 'settings[target_type]' => 'paragraph', 'cardinality' => '-1', ], []); - $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_nested_paragraph_add_more'); + $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_nested_paragraph_add_more'); // Create a node with a Paragraph. $edit = [ @@ -147,7 +147,7 @@ public function testDuplicateButtonWithNesting() { // Add a text field to nested paragraph. $text = 'recognizable_text'; - $this->drupalPostAjaxForm('node/' . $node->id() . '/edit', [], 'field_paragraphs_0_subform_field_nested_text_add_more'); + $this->drupalPostForm('node/' . $node->id() . '/edit', [], 'field_paragraphs_0_subform_field_nested_text_add_more'); $edit = [ 'field_paragraphs[0][subform][field_nested][0][subform][field_text][0][value]' => $text, ]; @@ -158,8 +158,8 @@ public function testDuplicateButtonWithNesting() { $this->drupalGet('node/' . $node->id() . '/edit'); // Click "Duplicate" button. - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_duplicate'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_edit'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_0_duplicate'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit'); $this->assertFieldByName('field_paragraphs[0][subform][field_nested][0][subform][field_text][0][value]', $text); $this->assertFieldByName('field_paragraphs[1][subform][field_nested][0][subform][field_text][0][value]', $text); diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalEditModesTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalEditModesTest.php similarity index 62% rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalEditModesTest.php rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalEditModesTest.php index c6a5d31523..590d27dc6b 100644 --- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalEditModesTest.php +++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalEditModesTest.php @@ -1,8 +1,8 @@ <?php -namespace Drupal\paragraphs\Tests\Experimental; +namespace Drupal\Tests\paragraphs\Functional\Experimental; -use Drupal\field_ui\Tests\FieldUiTestTrait; +use Drupal\block_content\Entity\BlockContent; /** * Tests paragraphs edit modes. @@ -11,8 +11,6 @@ */ class ParagraphsExperimentalEditModesTest extends ParagraphsExperimentalTestBase { - use FieldUiTestTrait; - /** * Modules to enable. * @@ -21,6 +19,7 @@ class ParagraphsExperimentalEditModesTest extends ParagraphsExperimentalTestBase public static $modules = [ 'image', 'block_field', + 'block_content', 'link', 'field_ui' ]; @@ -49,14 +48,14 @@ public function testCollapsedSummary() { // Set edit mode to closed. $this->drupalGet('admin/structure/types/manage/paragraphed_test/form-display'); - $this->drupalPostAjaxForm(NULL, [], "field_paragraphs_settings_edit"); + $this->drupalPostForm(NULL, [], "field_paragraphs_settings_edit"); $edit = ['fields[field_paragraphs][settings_edit_form][settings][edit_mode]' => 'closed']; $this->drupalPostForm(NULL, $edit, t('Save')); // Add a paragraph. - $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_image_text_paragraph_add_more'); - $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_title_add_more'); + $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_image_text_paragraph_add_more'); + $this->drupalPostForm(NULL, NULL, 'field_paragraphs_title_add_more'); - $files = $this->drupalGetTestFiles('image'); + $files = $this->getTestFiles('image'); $file_system = \Drupal::service('file_system'); // Create a node with an image and text. @@ -76,29 +75,27 @@ public function testCollapsedSummary() { // Assert the summary is correctly generated. $this->clickLink(t('Edit')); - $this->assertRaw('<div class="paragraphs-collapsed-description">' . $files[0]->filename . ', text_summary'); - $this->assertRaw('<div class="paragraphs-collapsed-description">' . $this->admin_user->label()); - $this->assertRaw('<div class="paragraphs-collapsed-description">Title example'); + $this->assertRaw('<span class="summary-content">' . $files[0]->filename . '</span>, <span class="summary-content">text_summary</span>'); + $this->assertRaw('<span class="summary-content">' . $this->admin_user->label()); + $this->assertRaw('<span class="summary-content">Title example'); // Edit and remove alternative text. - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_edit'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit'); $edit = [ 'field_paragraphs[0][subform][field_image][0][alt]' => 'alternative_text_summary', - 'field_paragraphs[0][subform][field_image][0][width]' => 300, - 'field_paragraphs[0][subform][field_image][0][height]' => 300, ]; - $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_0_collapse'); + $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_collapse'); // Assert the summary is correctly generated. - $this->assertRaw('<div class="paragraphs-collapsed-description">alternative_text_summary, text_summary'); + $this->assertRaw('<span class="summary-content">alternative_text_summary</span>, <span class="summary-content">text_summary</span>'); // Remove image. - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_edit'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_subform_field_image_0_remove_button'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_0_subform_field_image_0_remove_button'); $this->drupalPostForm(NULL, [], t('Save')); // Assert the summary is correctly generated. $this->clickLink(t('Edit')); - $this->assertRaw('<div class="paragraphs-collapsed-description">text_summary'); + $this->assertRaw('<span class="summary-content">text_summary'); $this->addParagraphsType('nested_paragraph'); static::fieldUIAddNewField('admin/structure/paragraphs_type/nested_paragraph', 'nested_content', 'Nested Content', 'entity_reference_revisions', ['settings[target_type]' => 'paragraph'], []); @@ -109,7 +106,7 @@ public function testCollapsedSummary() { $this->drupalGet('node/add/paragraphed_test'); $this->drupalPostForm(NULL, NULL, t('Add nested_paragraph')); - $this->drupalPostAjaxForm(NULL, NULL, t('field_paragraphs_0_subform_field_nested_content_user_paragraph_add_more')); + $this->drupalPostForm(NULL, NULL, t('field_paragraphs_0_subform_field_nested_content_user_paragraph_add_more')); $edit = [ 'title[0][value]' => 'Node title', 'field_paragraphs[0][subform][field_nested_content][0][subform][field_user][0][target_id]' => $test_user->label() . ' (' . $test_user->id() . ')', @@ -121,8 +118,8 @@ public function testCollapsedSummary() { $nodes = \Drupal::entityTypeManager()->getStorage('node')->loadByProperties(['title' => 'Node title']); $this->drupalGet('node/' . current($nodes)->id() . '/edit'); - $this->drupalPostAjaxForm(NULL, [], t('field_paragraphs_0_edit')); - $this->drupalPostAjaxForm(NULL, [], t('field_paragraphs_0_collapse')); + $this->drupalPostForm(NULL, [], t('field_paragraphs_0_edit')); + $this->drupalPostForm(NULL, [], t('field_paragraphs_0_collapse')); $this->assertResponse(200); // Add a Block Paragraphs type. @@ -130,20 +127,36 @@ public function testCollapsedSummary() { $this->addFieldtoParagraphType('block_paragraph', 'field_block', 'block_field'); // Test the summary of a Block field. + $after_block2 = BlockContent::create([ + 'info' => 'Llama custom block', + 'type' => 'basic_block', + ]); + $after_block2->save(); + + $this->placeBlock($after_block2->id()); + $this->drupalGet('node/add/paragraphed_test'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_block_paragraph_add_more'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_block_paragraph_add_more'); $edit = [ - 'field_paragraphs[0][subform][field_block][0][plugin_id]' => 'system_breadcrumb_block', + 'field_paragraphs[0][subform][field_block][0][plugin_id]' => 'block_content:' . $after_block2->uuid(), ]; - $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_0_collapse'); - $this->assertRaw('<div class="paragraphs-collapsed-description">Breadcrumbs'); + $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_collapse'); + $this->assertRaw('<span class="summary-content">Llama custom block'); + $edit = ['title[0][value]' => 'Test llama block']; + $this->drupalPostForm(NULL, $edit, t('Save')); + // Delete the block. + $after_block2->delete(); + // Attempt to edit the node when the node is deleted. + $node = $this->getNodeByTitle('Test llama block'); + $this->drupalGet('node/' . $node->id() . '/edit'); + $this->assertResponse(200); // Test the summary of a Block field. $paragraph_type = 'link_paragraph'; $this->addParagraphsType($paragraph_type); static::fieldUIAddNewField('admin/structure/paragraphs_type/' . $paragraph_type, 'link', 'Link', 'link', [], []); // Create a node with a link paragraph. - $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_link_paragraph_add_more'); + $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_link_paragraph_add_more'); $edit = [ 'title[0][value]' => 'Test link', 'field_paragraphs[0][subform][field_link][0][uri]' => 'http://www.google.com', @@ -151,16 +164,16 @@ public function testCollapsedSummary() { $this->drupalPostForm(NULL, $edit, t('Save')); // Check the summary when no link title is provided. $this->clickLink(t('Edit')); - $this->assertRaw('<div class="paragraphs-collapsed-description">http://www.google.com'); + $this->assertRaw('<span class="summary-content">http://www.google.com'); // Set a link title. - $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_0_edit'); + $this->drupalPostForm(NULL, NULL, 'field_paragraphs_0_edit'); $edit = [ 'field_paragraphs[0][subform][field_link][0][title]' => 'Link title', ]; $this->drupalPostForm(NULL, $edit, t('Save')); // Check the summary when the link title is set. $this->clickLink(t('Edit')); - $this->assertRaw('<div class="paragraphs-collapsed-description">Link title'); + $this->assertRaw('<span class="summary-content">Link title'); // Allow the user to select if the paragraphs is published or not. $edit = [ @@ -176,7 +189,7 @@ public function testCollapsedSummary() { $this->drupalPostForm('admin/structure/paragraphs_type/nested_paragraph/form-display', $edit, 'Save'); // Add a unpublished text paragraph and check its summary when unpublished. - $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_title_add_more'); + $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_title_add_more'); $edit = [ 'title[0][value]' => 'Access summary test', 'field_paragraphs[0][subform][field_title][0][value]' => 'memorable_summary_title', @@ -186,10 +199,11 @@ public function testCollapsedSummary() { $this->assertNoText('memorable_summary_title'); $node = $this->getNodeByTitle('Access summary test'); $this->drupalGet('node/' . $node->id() . '/edit'); - $this->assertRaw('<div class="paragraphs-collapsed-description">memorable_summary_title'); + $this->assertRaw('<span class="summary-content">memorable_summary_title'); + $this->assertEqual(1, count($this->xpath("//*[contains(@class, 'paragraphs-icon-view')]"))); - $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_nested_paragraph_add_more'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_subform_field_nested_content_title_add_more'); + $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_nested_paragraph_add_more'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_0_subform_field_nested_content_title_add_more'); // Add a nested paragraph and with the parent unpublished, check the // summary. @@ -203,10 +217,25 @@ public function testCollapsedSummary() { $this->assertNoText('memorable_nested_summary_title'); $node = $this->getNodeByTitle('Access nested summary test'); $this->drupalGet('node/' . $node->id() . '/edit'); - $this->assertRaw('<div class="paragraphs-collapsed-description">memorable_nested_summary_title'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_edit'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_subform_field_nested_content_0_collapse'); - $this->assertRaw('<div class="paragraphs-collapsed-description">memorable_nested_summary_title'); + $this->assertRaw('<span class="summary-content">memorable_nested_summary_title'); + $this->assertEqual(1, count($this->xpath("//*[contains(@class, 'paragraphs-icon-view')]"))); + $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_0_subform_field_nested_content_0_collapse'); + $this->assertRaw('<span class="summary-content">memorable_nested_summary_title'); + $this->assertEqual(1, count($this->xpath("//*[contains(@class, 'paragraphs-icon-view')]"))); + + // Assert the unpublished icon. + $permissions = [ + 'edit any paragraphed_test content', + ]; + $this->loginAsAdmin($permissions); + $this->drupalGet('node/' . $node->id() . '/edit'); + $this->assertRaw('<span class="summary-content">memorable_nested_summary_title'); + $this->assertEqual(1, count($this->xpath("//*[contains(@class, 'paragraphs-icon-view')]"))); + $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_0_subform_field_nested_content_0_collapse'); + $this->assertRaw('<span class="summary-content">memorable_nested_summary_title'); + $this->assertEqual(1, count($this->xpath("//*[contains(@class, 'paragraphs-icon-view')]"))); } } diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalEntityTranslationWithNonTranslatableParagraphs.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalEntityTranslationWithNonTranslatableParagraphs.php similarity index 98% rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalEntityTranslationWithNonTranslatableParagraphs.php rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalEntityTranslationWithNonTranslatableParagraphs.php index 247ebf9e8d..7465b193b8 100644 --- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalEntityTranslationWithNonTranslatableParagraphs.php +++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalEntityTranslationWithNonTranslatableParagraphs.php @@ -1,6 +1,6 @@ <?php -namespace Drupal\paragraphs\Tests\Experimental; +namespace Drupal\Tests\paragraphs\Functional\Experimental; /** * Tests the translation of heavily nested / specialized setup. diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalFieldGroupTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalFieldGroupTest.php similarity index 90% rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalFieldGroupTest.php rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalFieldGroupTest.php index 111f5782f8..26c9131019 100644 --- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalFieldGroupTest.php +++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalFieldGroupTest.php @@ -1,6 +1,6 @@ <?php -namespace Drupal\paragraphs\Tests\Experimental; +namespace Drupal\Tests\paragraphs\Functional\Experimental; /** * Tests the field group on node. @@ -49,13 +49,14 @@ public function testFieldGroup() { // Put the text field into the field group. $edit = [ + 'fields[group_field][region]' => 'content', 'fields[field_text][parent]' => 'group_field' ]; $this->drupalPostForm('admin/structure/paragraphs_type/' . $paragraph_type . '/form-display', $edit, t('Save')); // Create a node with a paragraph. $this->drupalGet('node/add/' . $content_type); - $this->drupalPostAjaxForm('node/add/' . $content_type, [], 'field_paragraphs_paragraph_type_test_add_more'); + $this->drupalPostForm('node/add/' . $content_type, [], 'field_paragraphs_paragraph_type_test_add_more'); // Test if the new field group is displayed. $this->assertText('field_group'); diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalHeaderActionsTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalHeaderActionsTest.php similarity index 87% rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalHeaderActionsTest.php rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalHeaderActionsTest.php index cce11d7286..9e6d0b7444 100644 --- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalHeaderActionsTest.php +++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalHeaderActionsTest.php @@ -1,6 +1,6 @@ <?php -namespace Drupal\paragraphs\Tests\Experimental; +namespace Drupal\Tests\paragraphs\Functional\Experimental; use Drupal\language\Entity\ConfigurableLanguage; use Symfony\Component\CssSelector\CssSelectorConverter; @@ -62,7 +62,7 @@ public function testHeaderActions() { $this->assertEqual(1, count($table_rows)); // Add second paragraph and check for Collapse/Edit all button. - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_text_paragraph_add_more'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_text_paragraph_add_more'); $this->assertRaw('field_paragraphs_collapse_all'); $this->assertRaw('field_paragraphs_edit_all'); @@ -77,7 +77,7 @@ public function testHeaderActions() { $this->assertRaw('field_paragraphs_1_edit'); // Test Edit all button. - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_edit_all'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_edit_all'); $this->assertRaw('field_paragraphs_0_collapse'); $this->assertRaw('field_paragraphs_1_collapse'); @@ -93,22 +93,22 @@ public function testHeaderActions() { $this->assertNoText('No Paragraph added yet.'); // Add and remove another paragraph. - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_text_paragraph_add_more'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_text_paragraph_add_more'); $edit = [ 'field_paragraphs[2][subform][field_text][0][value]' => 'Third text', ]; - $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_2_remove'); + $this->drupalPostForm(NULL, $edit, 'field_paragraphs_2_remove'); // Check that pressing "Collapse all" does not restore the removed // paragraph. - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_edit_all'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_edit_all'); $this->assertText('First text'); $this->assertText('Second text'); $this->assertNoText('Third text'); // Check that pressing "Edit all" does not restore the removed paragraph, // either. - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_collapse_all'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_collapse_all'); $this->assertText('First text'); $this->assertText('Second text'); $this->assertNoText('Third text'); @@ -120,12 +120,12 @@ public function testHeaderActions() { // and that it is not shown when the paragraph is deleted. $this->drupalGet('node/add/paragraphed_test'); $this->assertRaw('name="field_paragraphs_dragdrop_mode"'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_remove'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_0_remove'); $this->assertNoRaw('name="field_paragraphs_dragdrop_mode"'); // Disable show multiple actions. $this->drupalGet('admin/structure/types/manage/paragraphed_test/form-display'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_settings_edit'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_settings_edit'); $this->drupalPostForm(NULL, ['fields[field_paragraphs][settings_edit_form][settings][features][collapse_edit_all]' => FALSE], t('Update')); $this->drupalPostForm(NULL, [], 'Save'); $this->drupalGet('node/' . $node->id() . '/edit'); @@ -136,7 +136,7 @@ public function testHeaderActions() { // Enable show "Collapse / Edit all" actions. $this->drupalGet('admin/structure/types/manage/paragraphed_test/form-display'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_settings_edit'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_settings_edit'); $this->drupalPostForm(NULL, ['fields[field_paragraphs][settings_edit_form][settings][features][collapse_edit_all]' => TRUE], t('Update')); $this->drupalPostForm(NULL, [], 'Save'); $this->drupalGet('node/' . $node->id() . '/edit'); @@ -191,13 +191,13 @@ public function testHeaderActionsWithNesting() { // Checks that Collapse/Edit all button is presented. $this->drupalGet('node/add/paragraphed_test'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_nested_paragraph_add_more'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_text_add_more'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_nested_paragraph_add_more'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_text_add_more'); $this->assertRaw('field_paragraphs_collapse_all'); $this->assertRaw('field_paragraphs_edit_all'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_text_add_more'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_subform_field_nested_text_add_more'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_text_add_more'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_0_subform_field_nested_text_add_more'); $this->assertNoRaw('field_paragraphs_0_collapse_all'); $this->assertNoRaw('field_paragraphs_0_edit_all'); $edit = [ @@ -207,7 +207,7 @@ public function testHeaderActionsWithNesting() { $this->drupalPostForm(NULL, $edit, 'Collapse all'); $this->assertRaw('field-paragraphs-0-edit'); $this->assertFieldByXPath((new CssSelectorConverter())->toXPath('[name="field_paragraphs_1_edit"] + .paragraphs-dropdown')); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_edit_all'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_edit_all'); $this->assertRaw('field-paragraphs-0-collapse'); $edit = [ @@ -221,12 +221,12 @@ public function testHeaderActionsWithNesting() { $this->clickLink('Edit'); $this->assertNoText('No Paragraph added yet.'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_subform_field_nested_text_add_more'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_0_subform_field_nested_text_add_more'); $edit = [ 'field_paragraphs[0][subform][field_nested][1][subform][field_text][0][value]' => 'Second nested text', ]; - $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_0_collapse'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_edit'); + $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_collapse'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit'); $this->assertRaw('field_paragraphs_0_subform_field_nested_collapse_all'); $this->assertRaw('field_paragraphs_0_subform_field_nested_edit_all'); } @@ -271,8 +271,8 @@ public function testHeaderActionsWithMultiFields() { ); $this->drupalGet('node/add/paragraphed_test'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_text_paragraph_add_more'); - $this->drupalPostAjaxForm(NULL, [], 'field_second_text_paragraph_add_more'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_text_paragraph_add_more'); + $this->drupalPostForm(NULL, [], 'field_second_text_paragraph_add_more'); // Checks that we have Collapse\Edit all for each field. $this->assertRaw('field_paragraphs_collapse_all'); @@ -283,17 +283,17 @@ public function testHeaderActionsWithMultiFields() { $edit = [ 'field_second[0][subform][field_text][0][value]' => 'Second field', ]; - $this->drupalPostAjaxForm(NULL, $edit, 'field_second_collapse_all'); + $this->drupalPostForm(NULL, $edit, 'field_second_collapse_all'); // Checks that we collapsed only children from second field. $this->assertNoRaw('field_paragraphs_0_edit'); $this->assertRaw('field_second_0_edit'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_collapse_all'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_collapse_all'); $this->assertRaw('field_paragraphs_0_edit'); $this->assertRaw('field_second_0_edit'); - $this->drupalPostAjaxForm(NULL, [], 'field_second_edit_all'); + $this->drupalPostForm(NULL, [], 'field_second_edit_all'); $this->assertRaw('field_second_0_collapse'); $edit = [ diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalInlineEntityFormTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalInlineEntityFormTest.php similarity index 92% rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalInlineEntityFormTest.php rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalInlineEntityFormTest.php index 1ddd6189bb..236253ea95 100644 --- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalInlineEntityFormTest.php +++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalInlineEntityFormTest.php @@ -1,6 +1,6 @@ <?php -namespace Drupal\paragraphs\Tests\Experimental; +namespace Drupal\Tests\paragraphs\Functional\Experimental; use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait; @@ -61,7 +61,7 @@ public function testParagraphsIEFPreview() { // Create node with one paragraph. $this->drupalGet('node/add/article'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_simple_add_more'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_simple_add_more'); // Set the values and save. $edit = [ @@ -75,7 +75,7 @@ public function testParagraphsIEFPreview() { $this->drupalGet('node/' . $node->id() . '/edit'); // Try to open the previewed paragraph. - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_edit'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit'); } /** @@ -90,7 +90,6 @@ public function testParagraphsIEFChangeOrder() { $this->addParagraphsType('simple'); $this->addParagraphsType('text'); - // Create a reference to an article. $this->fieldUIAddNewField('admin/structure/paragraphs_type/simple', 'article', 'Article', 'field_ui:entity_reference:node', [ 'settings[target_type]' => 'node', @@ -121,7 +120,7 @@ public function testParagraphsIEFChangeOrder() { // Create node with one paragraph. $this->drupalGet('node/add/article'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_simple_add_more'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_simple_add_more'); // Set the values and save. $edit = [ @@ -136,7 +135,7 @@ public function testParagraphsIEFChangeOrder() { $this->drupalGet('node/' . $node->id() . '/edit'); // Create second paragraph. - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_simple_add_more'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_simple_add_more'); // Set the values of second paragraph. $edit = [ diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalPreviewTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalPreviewTest.php similarity index 86% rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalPreviewTest.php rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalPreviewTest.php index 8824207350..4e80a4a51c 100644 --- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalPreviewTest.php +++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalPreviewTest.php @@ -1,9 +1,6 @@ <?php -namespace Drupal\paragraphs\Tests\Experimental; - -use Drupal\Core\Entity\Entity\EntityFormDisplay; -use Drupal\field_ui\Tests\FieldUiTestTrait; +namespace Drupal\Tests\paragraphs\Functional\Experimental; /** * Tests the configuration of paragraphs. @@ -12,8 +9,6 @@ */ class ParagraphsExperimentalPreviewTest extends ParagraphsExperimentalTestBase { - use FieldUiTestTrait; - /** * Modules to enable. * @@ -49,7 +44,7 @@ public function testParagraphsPreview() { $test_text_2 = 'dummy_preview_text_2'; // Create node with two paragraphs. $this->drupalGet('node/add/article'); - $this->drupalPostAjaxForm(NULL, array(), 'field_paragraphs_text_add_more'); + $this->drupalPostForm(NULL, array(), 'field_paragraphs_text_add_more'); // Set the value of the paragraphs. $edit = [ 'title[0][value]' => 'Page_title', @@ -68,12 +63,12 @@ public function testParagraphsPreview() { $this->clickLink('Back to content editing'); $paragraph_1 = $this->xpath('//*[@id="edit-field-paragraphs-0-subform-field-text-0-value"]')[0]; - $this->assertEqual($paragraph_1['value'], $test_text_1); + $this->assertEqual($paragraph_1->getValue(), $test_text_1); $this->drupalPostForm(NULL, $edit, t('Save')); $this->clickLink('Edit'); - $this->drupalPostAjaxForm(NULL, array(), 'field_paragraphs_text_add_more'); + $this->drupalPostForm(NULL, array(), 'field_paragraphs_text_add_more'); $edit = [ 'field_paragraphs[1][subform][field_text][0][value]' => $test_text_2, ]; @@ -102,8 +97,8 @@ public function testParagraphsPreview() { $this->clickLink('Back to content editing'); $paragraph_1 = $this->xpath('//*[@id="edit-field-paragraphs-0-subform-field-text-0-value"]')[0]; $paragraph_2 = $this->xpath('//*[@id="edit-field-paragraphs-1-subform-field-text-0-value"]')[0]; - $this->assertEqual($paragraph_1['value'], $test_text_1); - $this->assertEqual($paragraph_2['value'], $new_test_text_2); + $this->assertEqual($paragraph_1->getValue(), $test_text_1); + $this->assertEqual($paragraph_2->getValue(), $new_test_text_2); $this->drupalPostForm(NULL, [], t('Save')); $this->assertRaw($test_text_1); diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalReplicateEnableTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalReplicateEnableTest.php similarity index 79% rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalReplicateEnableTest.php rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalReplicateEnableTest.php index b81d73330f..775b3cc47a 100644 --- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalReplicateEnableTest.php +++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalReplicateEnableTest.php @@ -1,6 +1,6 @@ <?php -namespace Drupal\paragraphs\Tests\Experimental; +namespace Drupal\Tests\paragraphs\Functional\Experimental; /** * Enables replicate module. diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalSummaryFormatterTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalSummaryFormatterTest.php similarity index 88% rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalSummaryFormatterTest.php rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalSummaryFormatterTest.php index 87a0e2963e..c02b7c805d 100644 --- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalSummaryFormatterTest.php +++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalSummaryFormatterTest.php @@ -1,8 +1,6 @@ <?php -namespace Drupal\paragraphs\Tests\Experimental; - -use Drupal\field_ui\Tests\FieldUiTestTrait; +namespace Drupal\Tests\paragraphs\Functional\Experimental; /** * Tests the paragraphs summary formatter. @@ -11,8 +9,6 @@ */ class ParagraphsExperimentalSummaryFormatterTest extends ParagraphsExperimentalTestBase { - use FieldUiTestTrait; - /** * Modules to enable. * @@ -47,8 +43,8 @@ public function testParagraphsSummaryFormatter() { $edit = ['fields[field_paragraphs][type]' => 'paragraph_summary']; $this->drupalPostForm(NULL, $edit, t('Save')); // Add a paragraph. - $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_add_more'); - $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_title_add_more'); + $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_add_more'); + $this->drupalPostForm(NULL, NULL, 'field_paragraphs_title_add_more'); // Create a node with a text. $edit = [ diff --git a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalTestBase.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalTestBase.php new file mode 100644 index 0000000000..389d461b72 --- /dev/null +++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalTestBase.php @@ -0,0 +1,47 @@ +<?php + +namespace Drupal\Tests\paragraphs\Functional\Experimental; + +use Drupal\Core\Entity\Entity\EntityFormDisplay; +use Drupal\Tests\paragraphs\Functional\Classic\ParagraphsTestBase; +use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait; + +/** + * Base class for tests. + */ +abstract class ParagraphsExperimentalTestBase extends ParagraphsTestBase { + + use ParagraphsTestBaseTrait; + + /** + * Sets the Paragraphs widget add mode. + * + * @param string $content_type + * Content type name where to set the widget mode. + * @param string $paragraphs_field + * Paragraphs field to change the mode. + * @param string $mode + * Mode to be set. ('dropdown', 'select' or 'button'). + */ + protected function setAddMode($content_type, $paragraphs_field, $mode) { + $form_display = EntityFormDisplay::load('node.' . $content_type . '.default') + ->setComponent($paragraphs_field, [ + 'type' => 'paragraphs', + 'settings' => ['add_mode' => $mode] + ]); + $form_display->save(); + } + + /** + * Removes the default paragraph type. + * + * @param $content_type + * Content type name that contains the paragraphs field. + */ + protected function removeDefaultParagraphType($content_type) { + $this->drupalGet('node/add/' . $content_type); + $this->drupalPostForm(NULL, [], 'Remove'); + $this->assertNoText('No paragraphs added yet.'); + } + +} diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalTranslationTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalTranslationTest.php similarity index 95% rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalTranslationTest.php rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalTranslationTest.php index 6689979231..5b0bbd6cc8 100644 --- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalTranslationTest.php +++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalTranslationTest.php @@ -1,6 +1,6 @@ <?php -namespace Drupal\paragraphs\Tests\Experimental; +namespace Drupal\Tests\paragraphs\Functional\Experimental; use Drupal\Component\Render\FormattableMarkup; use Drupal\Core\Entity\Entity\EntityFormDisplay; @@ -134,8 +134,8 @@ public function testParagraphTranslation() { $this->assertText(t('Example published and unpublished')); $this->clickLink(t('Edit')); - $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_demo_nested_paragraph_add_more'); - $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_demo_1_subform_field_paragraphs_demo_text_add_more'); + $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_nested_paragraph_add_more'); + $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_1_subform_field_paragraphs_demo_text_add_more'); $edit = [ 'field_paragraphs_demo[0][subform][status][value]' => FALSE, 'field_paragraphs_demo[1][subform][field_paragraphs_demo][0][subform][field_text_demo][0][value]' => 'Dummy text' @@ -260,7 +260,7 @@ public function testParagraphTranslation() { $this->drupalPostForm(NULL, $edit, t('Save settings')); // Create a node with an image paragraph, its alt and title text. - $files = $this->drupalGetTestFiles('image'); + $files = $this->getTestFiles('image'); $file_system = \Drupal::service('file_system'); $file_path = $file_system->realpath($file_system->realpath($files[0]->uri)); $this->drupalGet('node/add/paragraphed_content_demo'); @@ -422,7 +422,7 @@ public function testParagraphTranslation() { $this->drupalGet('node/add/paragraphed_content_demo'); $this->drupalPostForm(NULL, NULL, t('Add text')); $this->drupalPostForm(NULL, NULL, t('Add nested_paragraph')); - $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_demo_1_subform_field_paragraphs_demo_text_add_more'); + $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_1_subform_field_paragraphs_demo_text_add_more'); $edit = [ 'title[0][value]' => 'EN llama', 'langcode[0][value]' => 'en', @@ -434,7 +434,7 @@ public function testParagraphTranslation() { // Create a german translation. $node = $this->drupalGetNodeByTitle('EN llama'); $this->drupalGet('node/' . $node->id() . '/translations/add/en/de'); - $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_demo_edit_all'); + $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_edit_all'); $edit = [ 'title[0][value]' => 'DE llama', 'field_paragraphs_demo[0][subform][field_text_demo][0][value]' => 'DE text llama', @@ -444,8 +444,8 @@ public function testParagraphTranslation() { // Assert that the summary is displayed in the current language. $this->drupalGet('de/node/' . $node->id() . '/edit'); $this->assertFieldByName('title[0][value]', 'DE llama'); - $this->assertRaw('<div class="paragraphs-collapsed-description">DE text llama'); - $this->assertRaw('<div class="paragraphs-collapsed-description">DE nested text llama'); + $this->assertRaw('<span class="summary-content">DE text llama</span></div></div>'); + $this->assertRaw('<span class="summary-content">DE nested text llama</span></div></div>'); // Case 2: Referenced entities. $this->addParagraphsType('node_reference'); @@ -473,7 +473,7 @@ public function testParagraphTranslation() { $this->drupalPostForm(NULL, $edit, t('Save (this translation)')); // Edit the node again and check the paragraph summary. $this->drupalGet('de/node/' . $referencing_node->id() . '/edit'); - $this->assertRaw('<div class="paragraphs-collapsed-description">DE llama'); + $this->assertRaw('<span class="summary-content">DE llama</span></div></div>'); } /** @@ -504,7 +504,7 @@ public function testParagraphTranslationMultilingual() { $this->drupalPostForm(NULL, NULL, t('Add images')); $this->assertParagraphsButtons(1); // Upload an image and check the paragraphs buttons are still displayed. - $images = $this->drupalGetTestFiles('image')[0]; + $images = $this->getTestFiles('image')[0]; $edit = [ 'title[0][value]' => 'Title in english', 'files[field_paragraphs_demo_0_subform_field_images_demo_0][]' => $images->uri, @@ -536,7 +536,7 @@ public function testParagraphTranslationMultilingual() { // Edit the french translation and upload a new image. $this->clickLink('Edit'); - $images = $this->drupalGetTestFiles('image')[1]; + $images = $this->getTestFiles('image')[1]; $this->drupalPostForm(NULL, [ 'files[field_paragraphs_demo_0_subform_field_images_demo_1][]' => $images->uri, ], t('Upload')); @@ -568,12 +568,12 @@ public function testParagraphTranslationMultilingual() { $this->assertParagraphsButtons(2); // Add an 'Images' paragraph inside the nested one, check the paragraphs // langcode are still 'en' and the paragraphs buttons are still displayed. - $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_demo_1_subform_field_paragraphs_demo_images_add_more'); + $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_1_subform_field_paragraphs_demo_images_add_more'); $this->assertParagraphsLangcode($node->id()); $this->assertParagraphsButtons(2); // Upload a new image, check the paragraphs langcode are still 'en' and the // paragraphs buttons are displayed. - $images = $this->drupalGetTestFiles('image')[2]; + $images = $this->getTestFiles('image')[2]; $this->drupalPostForm(NULL, [ 'files[field_paragraphs_demo_1_subform_field_paragraphs_demo_0_subform_field_images_demo_0][]' => $images->uri, ], t('Upload')); @@ -617,7 +617,7 @@ public function testParagraphTranslationMultilingual() { $this->assertParagraphsLangcode($node->id(), 'de', 'fr'); $this->assertNoParagraphsButtons(2); // Upload another image. - $images = $this->drupalGetTestFiles('image')[3]; + $images = $this->getTestFiles('image')[3]; $this->drupalPostForm(NULL, [ 'files[field_paragraphs_demo_1_subform_field_paragraphs_demo_0_subform_field_images_demo_1][]' => $images->uri, ], t('Upload')); @@ -646,12 +646,12 @@ public function testParagraphTranslationMultilingual() { 'title[0][value]' => 'Title in english', 'langcode[0][value]' => 'en', ]; - $this->drupalPostForm(NULL, $edit, t('Add images')); + $this->drupalPostForm(NULL, $edit, 'field_paragraphs_demo_images_add_more'); $this->assertParagraphsLangcode($node->id(), 'de'); - $this->assertParagraphsButtons(3); + $this->assertParagraphsButtons(3); // Upload a new image, check the paragraphs langcode are still 'de' and the // paragraphs buttons are displayed. - $images = $this->drupalGetTestFiles('image')[4]; + $images = $this->getTestFiles('image')[4]; $this->drupalPostForm(NULL, [ 'files[field_paragraphs_demo_2_subform_field_images_demo_0][]' => $images->uri, ], t('Upload')); @@ -698,9 +698,9 @@ public function testParagraphsMultilingualWorkflow() { // Check that the paragraphs buttons are displayed and add an 'Images' // paragraph inside the nested paragraph. $this->assertParagraphsButtons(1); - $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_demo_0_subform_field_paragraphs_demo_images_add_more'); + $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_0_subform_field_paragraphs_demo_images_add_more'); // Upload an image and check the paragraphs buttons are still displayed. - $images = $this->drupalGetTestFiles('image')[0]; + $images = $this->getTestFiles('image')[0]; $this->drupalPostForm(NULL, [ 'files[field_paragraphs_demo_0_subform_field_paragraphs_demo_0_subform_field_images_demo_0][]' => $images->uri, ], t('Upload')); @@ -716,7 +716,7 @@ public function testParagraphsMultilingualWorkflow() { $this->assertParagraphsLangcode($node1->id(), 'de'); $this->assertParagraphsButtons(1); // Change the node langcode to 'english' and upload another image. - $images = $this->drupalGetTestFiles('image')[1]; + $images = $this->getTestFiles('image')[1]; $edit = [ 'title[0][value]' => 'Title in german (en)', 'langcode[0][value]' => 'en', @@ -746,9 +746,9 @@ public function testParagraphsMultilingualWorkflow() { // Check that the paragraphs buttons are displayed and add an 'Images' // paragraph inside the nested paragraph. $this->assertParagraphsButtons(1); - $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_demo_0_subform_field_paragraphs_demo_images_add_more'); + $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_0_subform_field_paragraphs_demo_images_add_more'); // Upload an image and check the paragraphs buttons are still displayed. - $images = $this->drupalGetTestFiles('image')[0]; + $images = $this->getTestFiles('image')[0]; $edit = [ 'title[0][value]' => 'Title in english', 'files[field_paragraphs_demo_0_subform_field_paragraphs_demo_0_subform_field_images_demo_0][]' => $images->uri, @@ -770,13 +770,13 @@ public function testParagraphsMultilingualWorkflow() { 'title[0][value]' => 'Title in english (de)', 'langcode[0][value]' => 'de', ]; - $this->drupalPostForm(NULL, $edit, t('Add images')); + $this->drupalPostForm(NULL, $edit, 'field_paragraphs_demo_images_add_more'); // Check the paragraphs langcode are still 'en' and their buttons are shown. $this->assertParagraphsLangcode($node2->id()); $this->assertParagraphsButtons(2); // Upload an image, check the paragraphs langcode are still 'en' and their // buttons are displayed. - $images = $this->drupalGetTestFiles('image')[1]; + $images = $this->getTestFiles('image')[1]; $this->drupalPostForm(NULL, [ 'files[field_paragraphs_demo_1_subform_field_images_demo_0][]' => $images->uri, ], t('Upload')); @@ -810,13 +810,13 @@ public function testParagraphsMultilingualWorkflow() { $this->assertParagraphsLangcode($node2->id()); $this->assertParagraphsButtons(2); // Add another 'Images' paragraph with node langcode as 'english'. - $this->drupalPostForm(NULL, NULL, t('Add images')); + $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_images_add_more'); // Check the paragraph langcode are still 'en' and their buttons are shown. $this->assertParagraphsLangcode($node2->id()); $this->assertParagraphsButtons(3); // Upload an image, check the paragraphs langcode are still 'en' and their // buttons are displayed. - $images = $this->drupalGetTestFiles('image')[2]; + $images = $this->getTestFiles('image')[2]; $this->drupalPostForm(NULL, [ 'files[field_paragraphs_demo_2_subform_field_images_demo_0][]' => $images->uri, ], t('Upload')); @@ -835,13 +835,13 @@ public function testParagraphsMultilingualWorkflow() { 'title[0][value]' => 'Title in english (de)', 'langcode[0][value]' => 'de', ]; - $this->drupalPostForm(NULL, $edit, t('Add images')); + $this->drupalPostForm(NULL, $edit, 'field_paragraphs_demo_images_add_more'); // Check the paragraphs langcode are still 'en' and their buttons are shown. $this->assertParagraphsLangcode($node2->id()); $this->assertParagraphsButtons(4); // Upload an image, check the paragraphs langcode are still 'en' and their // buttons are displayed. - $images = $this->drupalGetTestFiles('image')[3]; + $images = $this->getTestFiles('image')[3]; $this->drupalPostForm(NULL, [ 'files[field_paragraphs_demo_3_subform_field_images_demo_0][]' => $images->uri, ], t('Upload')); diff --git a/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalTranslationsTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalTranslationsTest.php similarity index 77% rename from web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalTranslationsTest.php rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalTranslationsTest.php index 8257a1a79e..13a6774296 100644 --- a/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalTranslationsTest.php +++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalTranslationsTest.php @@ -1,13 +1,8 @@ <?php -namespace Drupal\Tests\paragraphs\Functional; +namespace Drupal\Tests\paragraphs\Functional\Experimental; -use Drupal\field_ui\Tests\FieldUiTestTrait; -use Drupal\paragraphs\Tests\Classic\ParagraphsCoreVersionUiTestTrait; use Drupal\language\Entity\ConfigurableLanguage; -use Drupal\Tests\BrowserTestBase; -use Drupal\Tests\paragraphs\FunctionalJavascript\LoginAdminTrait; -use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait; use Drupal\Tests\paragraphs\Traits\ParagraphsLastEntityQueryTrait; /** @@ -15,12 +10,8 @@ * * @group paragraphs */ -class ParagraphsExperimentalTranslationsTest extends BrowserTestBase { +class ParagraphsExperimentalTranslationsTest extends ParagraphsExperimentalTestBase { - use LoginAdminTrait; - use FieldUiTestTrait; - use ParagraphsTestBaseTrait; - use ParagraphsCoreVersionUiTestTrait; use ParagraphsLastEntityQueryTrait; /** @@ -151,13 +142,13 @@ public function testUntranslatableAutoCollapse() { $assert_session->fieldNotExists('field_paragraphs[2][subform][field_text_untranslatable_hide][0][value]'); $assert_session->buttonNotExists('field_paragraphs_2_collapse'); $assert_session->buttonNotExists('field_paragraphs_2_edit'); - $assert_session->responseContains('<div class="paragraphs-collapsed-description">Do not translate me CLOSED EN'); + $assert_session->responseContains('class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">Do not translate me CLOSED EN'); $assert_session->buttonExists('field_paragraphs_1_collapse'); $assert_session->fieldExists('field_paragraphs[1][subform][field_text_untranslatable][0][value]'); $page->pressButton('field_paragraphs_1_collapse'); $assert_session->fieldNotExists('field_paragraphs[1][subform][field_text_untranslatable][0][value]'); - $assert_session->responseContains('<div class="paragraphs-collapsed-description">Do not translate me EN'); + $assert_session->responseContains('class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">Do not translate me EN'); $assert_session->buttonExists('field_paragraphs_1_edit'); $assert_session->buttonExists('field_paragraphs_3_collapse'); @@ -178,17 +169,17 @@ public function testUntranslatableAutoCollapse() { $this->drupalGet("/de/node/{$host_node_id}/translations/add/en/de"); $assert_session->fieldExists('field_paragraphs[0][subform][field_text_translatable][0][value]'); $assert_session->fieldExists('field_paragraphs[1][subform][field_text_untranslatable][0][value]'); - $assert_session->responseContains('<div class="paragraphs-collapsed-description">Do not translate me CLOSED EN'); + $assert_session->responseContains('class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">Do not translate me CLOSED EN'); $assert_session->fieldExists('field_paragraphs[3][subform][field_paragraphs][0][subform][field_text_translatable][0][value]'); // Translate the content of the translatable fields. $page->fillField('field_paragraphs[0][subform][field_text_translatable][0][value]', 'Translate me DE'); $page->fillField('field_paragraphs[3][subform][field_paragraphs][0][subform][field_text_translatable][0][value]', 'Nested translate me DE'); // Close all Paragraphs with the new values. $page->pressButton('field_paragraphs_collapse_all'); - $assert_session->responseContains('<div class="paragraphs-collapsed-description">Translate me DE'); - $assert_session->responseContains('<div class="paragraphs-collapsed-description">Do not translate me EN'); - $assert_session->responseContains('<div class="paragraphs-collapsed-description">Do not translate me CLOSED EN'); - $assert_session->responseContains('<div class="paragraphs-collapsed-description">Nested translate me DE'); + $assert_session->responseContains('class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">Translate me DE'); + $assert_session->responseContains('class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">Do not translate me EN'); + $assert_session->responseContains('class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">Do not translate me CLOSED EN'); + $assert_session->responseContains('class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">Nested translate me DE'); // Edit the first Paragraph and update its value. $page->pressButton('field_paragraphs_0_edit'); $page->fillField('field_paragraphs[0][subform][field_text_translatable][0][value]', 'Translate me UPDATE DE'); @@ -200,16 +191,16 @@ public function testUntranslatableAutoCollapse() { // Edit the translation, assert that the Paragraphs are closed by default. $this->drupalGet('de/node/' . $host_node_id . '/edit'); - $assert_session->responseContains('<div class="paragraphs-collapsed-description">Translate me UPDATE DE'); - $assert_session->responseContains('<div class="paragraphs-collapsed-description">Do not translate me EN'); - $assert_session->responseContains('<div class="paragraphs-collapsed-description">Do not translate me CLOSED EN'); - $assert_session->responseContains('<div class="paragraphs-collapsed-description">Nested translate me DE'); + $assert_session->responseContains('class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">Translate me UPDATE DE'); + $assert_session->responseContains('class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">Do not translate me EN'); + $assert_session->responseContains('class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">Do not translate me CLOSED EN'); + $assert_session->responseContains('class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">Nested translate me DE'); // Open all paragraphs. $page->pressButton('field_paragraphs_edit_all'); $assert_session->fieldExists('field_paragraphs[0][subform][field_text_translatable][0][value]'); $assert_session->fieldExists('field_paragraphs[1][subform][field_text_untranslatable][0][value]'); - $assert_session->responseContains('<div class="paragraphs-collapsed-description">Do not translate me CLOSED EN'); - $assert_session->responseContains('<div class="paragraphs-collapsed-description">Nested translate me DE'); + $assert_session->responseContains('class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">Do not translate me CLOSED EN'); + $assert_session->responseContains('class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">Nested translate me DE'); $assert_session->fieldNotExists('field_paragraphs[3][subform][field_paragraphs][0][subform][field_text_translatable][0][value]'); // When editing a nested container, all children should follow the widget // settings when editing the translation. diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalTypesTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalTypesTest.php similarity index 92% rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalTypesTest.php rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalTypesTest.php index 6695ff848c..1a66f4f828 100644 --- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalTypesTest.php +++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalTypesTest.php @@ -1,6 +1,6 @@ <?php -namespace Drupal\paragraphs\Tests\Experimental; +namespace Drupal\Tests\paragraphs\Functional\Experimental; /** * Tests paragraphs types. @@ -28,7 +28,7 @@ public function testRemoveTypesWithContent() { // Add a test node with a Paragraph. $this->drupalGet('node/add/paragraphed_test'); - $this->drupalPostAjaxForm(NULL, [], 'paragraphs_paragraph_type_test_add_more'); + $this->drupalPostForm(NULL, [], 'paragraphs_paragraph_type_test_add_more'); $edit = ['title[0][value]' => 'test_node']; $table_rows = $this->xpath('//table[contains(@class, :class)]/tbody/tr', [':class' => 'field-multiple-table']); $this->assertEqual(1, count($table_rows)); @@ -53,8 +53,8 @@ public function testRemoveTypesWithContent() { $this->drupalGet('node/' . $node->id() . '/edit'); // Add two different Paragraphs to the node. - $this->drupalPostAjaxForm(NULL, [], 'paragraphs_paragraph_type_test_add_more'); - $this->drupalPostAjaxForm(NULL, [], 'paragraphs_text_add_more'); + $this->drupalPostForm(NULL, [], 'paragraphs_paragraph_type_test_add_more'); + $this->drupalPostForm(NULL, [], 'paragraphs_text_add_more'); $table_rows = $this->xpath('//table[contains(@class, :class)]/tbody/tr', [':class' => 'field-multiple-table']); $this->assertEqual(2, count($table_rows)); $this->drupalPostForm(NULL, [], t('Save')); @@ -89,7 +89,6 @@ public function testCreateParagraphType() { 'id' => 'test_name_with_more_than_32_characters' ]; $this->drupalPostForm(NULL, $edit, 'Save and manage fields'); - $this->assertNoErrorsLogged(); $this->assertText('Machine-readable name cannot be longer than 32 characters but is currently 38 characters long.'); $edit['id'] = 'new_test_id'; $this->drupalPostForm(NULL, $edit, 'Save and manage fields'); diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalUiTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalUiTest.php similarity index 90% rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalUiTest.php rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalUiTest.php index 536550fc9e..1b32d292eb 100644 --- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalUiTest.php +++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalUiTest.php @@ -1,8 +1,7 @@ <?php -namespace Drupal\paragraphs\Tests\Experimental; +namespace Drupal\Tests\paragraphs\Functional\Experimental; -use Drupal\field_ui\Tests\FieldUiTestTrait; use Drupal\language\Entity\ConfigurableLanguage; /** @@ -12,8 +11,6 @@ */ class ParagraphsExperimentalUiTest extends ParagraphsExperimentalTestBase { - use FieldUiTestTrait; - /** * {@inheritdoc} */ @@ -105,8 +102,8 @@ public function testEmptyRequiredField() { // "remove" mode in the required field. $title = 'Remove all items'; $this->drupalGet('node/add/paragraphed_content_demo'); - $this->drupalPostAjaxForm(NULL, [], 'field_content_text_image_add_more'); - $this->drupalPostAjaxForm(NULL, [], 'field_content_0_remove'); + $this->drupalPostForm(NULL, [], 'field_content_text_image_add_more'); + $this->drupalPostForm(NULL, [], 'field_content_0_remove'); $this->assertNoText($field_title . ' field is required'); $this->drupalPostForm(NULL, ['title[0][value]' => $title], t('Save')); $this->assertText($field_title . ' field is required'); @@ -115,9 +112,9 @@ public function testEmptyRequiredField() { // removed paragraph. $title = 'Valid Removal'; $this->drupalGet('node/add/paragraphed_content_demo'); - $this->drupalPostAjaxForm(NULL, [], 'field_content_text_image_add_more'); - $this->drupalPostAjaxForm(NULL, [], 'field_content_text_image_add_more'); - $this->drupalPostAjaxForm(NULL, [], 'field_content_1_remove'); + $this->drupalPostForm(NULL, [], 'field_content_text_image_add_more'); + $this->drupalPostForm(NULL, [], 'field_content_text_image_add_more'); + $this->drupalPostForm(NULL, [], 'field_content_1_remove'); $this->assertNoText($field_title . ' field is required'); $this->drupalPostForm(NULL, ['title[0][value]' => $title], t('Save')); $this->assertNoText($field_title . ' field is required'); diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalWidgetButtonsTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalWidgetButtonsTest.php similarity index 89% rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalWidgetButtonsTest.php rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalWidgetButtonsTest.php index 45ec337e60..ef7df522bb 100644 --- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalWidgetButtonsTest.php +++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalWidgetButtonsTest.php @@ -1,8 +1,7 @@ <?php -namespace Drupal\paragraphs\Tests\Experimental; +namespace Drupal\Tests\paragraphs\Functional\Experimental; -use Drupal\field_ui\Tests\FieldUiTestTrait; use Drupal\language\Entity\ConfigurableLanguage; use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait; use Drupal\field\Entity\FieldConfig; @@ -16,7 +15,6 @@ */ class ParagraphsExperimentalWidgetButtonsTest extends ParagraphsExperimentalTestBase { - use FieldUiTestTrait; use ParagraphsTestBaseTrait; /** @@ -48,7 +46,7 @@ public function testWidgetButtons() { 'fields[field_paragraphs][type]' => 'paragraphs', ]; $this->drupalPostForm('admin/structure/types/manage/paragraphed_test/form-display', $edit, t('Save')); - $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_add_more'); + $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_add_more'); // Create a node with a Paragraph. $text = 'recognizable_text'; @@ -56,7 +54,7 @@ public function testWidgetButtons() { 'title[0][value]' => 'paragraphs_mode_test', 'field_paragraphs[0][subform][field_text][0][value]' => $text, ]; - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_text_paragraph_add_more'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_text_paragraph_add_more'); $this->drupalPostForm(NULL, $edit, t('Save')); $node = $this->drupalGetNodeByTitle('paragraphs_mode_test'); @@ -70,18 +68,18 @@ public function testWidgetButtons() { $this->setParagraphsWidgetMode('paragraphed_test', 'field_paragraphs', 'closed'); $this->drupalGet('node/' . $node->id() . '/edit'); // Click "Edit" button. - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_edit'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_1_edit'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_1_edit'); $this->assertFieldByName('field_paragraphs[0][subform][field_text][0][value]', $text); $closed_mode_text = 'closed_mode_text'; // Click "Collapse" button on both paragraphs. $edit = ['field_paragraphs[0][subform][field_text][0][value]' => $closed_mode_text]; - $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_0_collapse'); + $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_collapse'); $edit = ['field_paragraphs[1][subform][field_text][0][value]' => $closed_mode_text]; - $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_1_collapse'); + $this->drupalPostForm(NULL, $edit, 'field_paragraphs_1_collapse'); // Verify that we have warning message for each paragraph. $this->assertEqual(2, count($this->xpath("//*[contains(@class, 'paragraphs-icon-changed')]"))); - $this->assertRaw('<div class="paragraphs-collapsed-description">' . $closed_mode_text); + $this->assertRaw('<span class="summary-content">' . $closed_mode_text); $this->drupalPostForm(NULL, [], t('Save')); $this->assertText('paragraphed_test ' . $node->label() . ' has been updated.'); $this->assertText($closed_mode_text); @@ -90,12 +88,12 @@ public function testWidgetButtons() { $this->setParagraphsWidgetSettings('paragraphed_test', 'field_paragraphs', ['closed_mode' => 'preview']); $this->drupalGet('node/' . $node->id() . '/edit'); // Click "Edit" button. - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_edit'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit'); $this->assertFieldByName('field_paragraphs[0][subform][field_text][0][value]', $closed_mode_text); $preview_mode_text = 'preview_mode_text'; $edit = ['field_paragraphs[0][subform][field_text][0][value]' => $preview_mode_text]; // Click "Collapse" button. - $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_0_collapse'); + $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_collapse'); $this->assertText('You have unsaved changes on this Paragraph item.'); $this->assertEqual(1, count($this->xpath("//*[contains(@class, 'paragraphs-icon-changed')]"))); $this->assertText($preview_mode_text); @@ -106,7 +104,7 @@ public function testWidgetButtons() { // Test the remove function. $this->drupalGet('node/' . $node->id() . '/edit'); // Click "Remove" button. - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_remove'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_0_remove'); $this->drupalPostForm(NULL, [], t('Save')); $this->assertText('paragraphed_test ' . $node->label() . ' has been updated.'); $this->assertNoText($preview_mode_text); @@ -137,7 +135,7 @@ public function testButtonsVisibility() { 'fields[field_paragraphs][type]' => 'paragraphs', ]; $this->drupalPostForm('admin/structure/types/manage/paragraphed_test/form-display', $edit, t('Save')); - $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_add_more'); + $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_add_more'); // Create a node with a Paragraph. $text = 'recognizable_text'; @@ -145,7 +143,7 @@ public function testButtonsVisibility() { 'title[0][value]' => 'paragraphs_mode_test', 'field_paragraphs[0][subform][field_text][0][value]' => $text, ]; - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_text_paragraph_add_more'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_text_paragraph_add_more'); $this->drupalPostForm(NULL, $edit, t('Save')); $node = $this->drupalGetNodeByTitle('paragraphs_mode_test'); @@ -181,8 +179,8 @@ public function testButtonsVisibility() { ]; $this->drupalPostForm(NULL, $edit, t('Save')); $this->drupalGet('node/' . $node->id() . '/edit'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_nested_paragraph_add_more'); - $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_2_subform_field_nested_nested_paragraph_add_more'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_nested_paragraph_add_more'); + $this->drupalPostForm(NULL, [], 'field_paragraphs_2_subform_field_nested_nested_paragraph_add_more'); // Collapse is present on each nesting level. $this->assertFieldByName('field_paragraphs_2_collapse'); $this->assertFieldByName('field_paragraphs_2_subform_field_nested_0_collapse'); diff --git a/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalBehaviorsTest.php b/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalBehaviorsTest.php index 1c3b43b010..1a769a6b69 100644 --- a/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalBehaviorsTest.php +++ b/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalBehaviorsTest.php @@ -2,19 +2,14 @@ namespace Drupal\Tests\paragraphs\Functional; -use Drupal\paragraphs\Tests\Classic\ParagraphsCoreVersionUiTestTrait; -use Drupal\Tests\BrowserTestBase; -use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait; +use Drupal\Tests\paragraphs\Functional\Experimental\ParagraphsExperimentalTestBase; /** * Tests support for Paragraphs behavior plugins. * * @group paragraphs */ -class ParagraphsExperimentalBehaviorsTest extends BrowserTestBase { - - use ParagraphsCoreVersionUiTestTrait; - use ParagraphsTestBaseTrait; +class ParagraphsExperimentalBehaviorsTest extends ParagraphsExperimentalTestBase { /** * Modules to enable. diff --git a/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalUiTest.php b/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalUiTest.php index 9310fdd2b4..45f0ba9d86 100644 --- a/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalUiTest.php +++ b/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalUiTest.php @@ -2,19 +2,14 @@ namespace Drupal\Tests\paragraphs\Functional; -use Drupal\Tests\BrowserTestBase; -use Drupal\Tests\paragraphs\FunctionalJavascript\LoginAdminTrait; -use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait; +use Drupal\Tests\paragraphs\Functional\Experimental\ParagraphsExperimentalTestBase; /** * Tests the Paragraphs user interface. * * @group paragraphs */ -class ParagraphsExperimentalUiTest extends BrowserTestBase { - - use LoginAdminTrait; - use ParagraphsTestBaseTrait; +class ParagraphsExperimentalUiTest extends ParagraphsExperimentalTestBase { /** * Modules to enable. @@ -46,6 +41,8 @@ public function testParagraphTypeClass() { $this->assertSession()->responseContains('paragraph-type--test-paragraph'); $this->getSession()->getPage()->findButton('paragraphs_text_add_more')->press(); $this->assertSession()->responseContains('paragraph-type--text'); + $this->getSession()->getPage()->findButton('paragraphs_0_remove')->press(); + $this->assertSession()->responseContains('paragraph-type--text'); } /** @@ -74,6 +71,26 @@ public function testSummary() { $node = $this->getNodeByTitle('Llama test'); $this->drupalGet('node/' . $node->id() . '/edit'); $this->assertSession()->pageTextContains('<iframe src="https://www.llamatest.neck'); + $this->assertSession()->responseContains('class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content"><iframe src='); + // Assert that the summary keeps showing html even with longer html. + $this->getSession()->getPage()->pressButton('paragraphs_0_edit'); + $edit = [ + 'paragraphs[0][subform][field_text_demo][0][value]' => '<iframe src="https://www.llamatest.neck" class="this-is-a-pretty-long-class-that-needs-to-be-really-long-for-testing-purposes-so-we-have-a-better-summary-test-and-it-has-exactly-144-characters"></iframe>', + ]; + $this->drupalPostForm(NULL, $edit, 'Save'); + $this->assertSession()->pageTextContains('paragraphed_test Llama test has been updated.'); + $this->drupalGet('node/' . $node->id() . '/edit'); + $this->assertSession()->pageTextContains('<iframe src="https://www.llamatest.neck" class="this-is-a-pretty-long-class-that-needs-to-be-really-long-for-testing-purposes-so-we-'); + $this->assertSession()->responseContains('class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content"><iframe src='); + // Asset that the summary does not display markup even when we have long + // html. + $this->getSession()->getPage()->pressButton('paragraphs_0_edit'); + $edit = [ + 'paragraphs[0][subform][field_text_demo][0][value]' => '<iframe src="https://www.llamatest.neck" class="this-is-a-pretty-long-class-that-needs-to-be-really-long-for-testing-purposes-so-we-have-a-better-summary-test-and-it-has-exactly-144-characters"></iframe><h1>This is a title</h1>', + ]; + $this->drupalPostForm(NULL, $edit, 'Save'); + $this->drupalGet('node/' . $node->id() . '/edit'); + $this->assertSession()->responseContains('class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">This is a title'); } } diff --git a/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalWidgetButtonsTest.php b/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalWidgetButtonsTest.php index 538f100299..3af2a108d6 100644 --- a/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalWidgetButtonsTest.php +++ b/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalWidgetButtonsTest.php @@ -2,10 +2,7 @@ namespace Drupal\Tests\paragraphs\Functional; -use Drupal\paragraphs\Tests\Classic\ParagraphsCoreVersionUiTestTrait; -use Drupal\Tests\BrowserTestBase; -use Drupal\Tests\paragraphs\FunctionalJavascript\LoginAdminTrait; -use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait; +use Drupal\Tests\paragraphs\Functional\Experimental\ParagraphsExperimentalTestBase; use Drupal\paragraphs\Entity\Paragraph; use Drupal\node\Entity\Node; @@ -14,11 +11,7 @@ * * @group paragraphs */ -class ParagraphsExperimentalWidgetButtonsTest extends BrowserTestBase { - - use LoginAdminTrait; - use ParagraphsCoreVersionUiTestTrait; - use ParagraphsTestBaseTrait; +class ParagraphsExperimentalWidgetButtonsTest extends ParagraphsExperimentalTestBase { /** * Modules to enable. @@ -476,6 +469,42 @@ public function testClosedModeThreshold() { $this->checkParagraphInMode('field_paragraphs_1', 'edit'); } + /** + * Tests 'Select list' add mode logic. + */ + public function testAddModeSelect() { + $this->loginAsAdmin(); + $this->addParagraphedContentType('paragraphed_test', 'paragraphs'); + + $this->addParagraphsType('test_paragraph'); + $this->addParagraphsType('text'); + $this->addFieldtoParagraphType('text', 'field_text_demo', 'text'); + $settings = [ + 'add_mode' => 'select', + 'edit_mode' => 'closed', + 'closed_mode' => 'summary', + ]; + $this->setParagraphsWidgetSettings('paragraphed_test', 'paragraphs', $settings, 'paragraphs'); + $this->drupalGet('node/add/paragraphed_test'); + $this->assertSession()->selectExists('paragraphs[add_more][add_more_select]'); + + $edit = [ + 'settings[handler_settings][negate]' => 0, + 'settings[handler_settings][target_bundles_drag_drop][text][enabled]' => 1, + ]; + $this->drupalPostForm('admin/structure/types/manage/paragraphed_test/fields/node.paragraphed_test.paragraphs', $edit, 'Save settings'); + + $this->drupalGet('node/add/paragraphed_test'); + $this->assertSession()->fieldNotExists('paragraphs[add_more][add_more_select]'); + $this->getSession()->getPage()->findButton('paragraphs_add_more')->press(); + $edit = [ + 'title[0][value]' => 'Demo text title', + 'paragraphs[0][subform][field_text_demo][0][value]' => 'Demo text for the detail page', + ]; + $this->drupalPostForm(NULL, $edit, 'Save'); + $this->assertSession()->pageTextContains('Demo text for the detail page'); + } + /** * Asserts that a paragraph is in a particular mode. * diff --git a/web/modules/paragraphs/src/Tests/ParagraphsUninstallTest.php b/web/modules/paragraphs/tests/src/Functional/ParagraphsUninstallTest.php similarity index 76% rename from web/modules/paragraphs/src/Tests/ParagraphsUninstallTest.php rename to web/modules/paragraphs/tests/src/Functional/ParagraphsUninstallTest.php index c60b0cb51b..b09f181360 100644 --- a/web/modules/paragraphs/src/Tests/ParagraphsUninstallTest.php +++ b/web/modules/paragraphs/tests/src/Functional/ParagraphsUninstallTest.php @@ -1,15 +1,15 @@ <?php -namespace Drupal\paragraphs\Tests; +namespace Drupal\Tests\paragraphs\Functional; -use Drupal\simpletest\WebTestBase; +use Drupal\Tests\BrowserTestBase; /** * Tests that Paragraphs module can be uninstalled. * * @group paragraphs */ -class ParagraphsUninstallTest extends WebTestBase { +class ParagraphsUninstallTest extends BrowserTestBase { /** * Modules to enable. @@ -18,6 +18,11 @@ class ParagraphsUninstallTest extends WebTestBase { */ public static $modules = array('paragraphs_demo'); + /** + * {@inheritdoc} + */ + protected $defaultTheme = 'stark'; + /** * {@inheritdoc} */ @@ -41,16 +46,16 @@ public function testUninstall() { $this->drupalPostForm(NULL, [], t('Uninstall')); // Delete library data. - $this->clickLink('Remove paragraphs library item entities'); - $this->drupalPostForm(NULL, [], t('Delete all paragraphs library item entities')); + $this->clickLink('Remove Paragraphs library items'); + $this->drupalPostForm(NULL, [], t('Delete all Paragraphs library items')); // Uninstall the library module. $this->drupalPostForm('admin/modules/uninstall', ['uninstall[paragraphs_library]' => TRUE], t('Uninstall')); $this->drupalPostForm(NULL, [], t('Uninstall')); // Delete paragraphs data. - $this->clickLink('Remove paragraph entities'); - $this->drupalPostForm(NULL, [], t('Delete all paragraph entities')); + $this->clickLink('Remove Paragraphs'); + $this->drupalPostForm(NULL, [], t('Delete all Paragraphs')); // Uninstall the module paragraphs. $this->drupalPostForm('admin/modules/uninstall', ['uninstall[paragraphs]' => TRUE], t('Uninstall')); diff --git a/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalAddWidgetTest.php b/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalAddWidgetTest.php index ac1c2e62e0..1d508adb94 100644 --- a/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalAddWidgetTest.php +++ b/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalAddWidgetTest.php @@ -3,16 +3,16 @@ namespace Drupal\Tests\paragraphs\FunctionalJavascript; use Drupal\Core\Entity\Entity\EntityFormDisplay; -use Drupal\field_ui\Tests\FieldUiTestTrait; -use Drupal\FunctionalJavascriptTests\JavascriptTestBase; -use Drupal\paragraphs\Tests\Classic\ParagraphsCoreVersionUiTestTrait; +use Drupal\FunctionalJavascriptTests\WebDriverTestBase; +use Drupal\Tests\field_ui\Traits\FieldUiTestTrait; +use Drupal\Tests\paragraphs\Traits\ParagraphsCoreVersionUiTestTrait; /** * Test paragraphs user interface. * * @group paragraphs */ -class ParagraphsExperimentalAddWidgetTest extends JavascriptTestBase { +class ParagraphsExperimentalAddWidgetTest extends WebDriverTestBase { use LoginAdminTrait; use FieldUiTestTrait; @@ -34,6 +34,11 @@ class ParagraphsExperimentalAddWidgetTest extends JavascriptTestBase { 'link', ]; + /** + * {@inheritdoc} + */ + protected $defaultTheme = 'stark'; + /** * {@inheritdoc} */ @@ -83,15 +88,24 @@ public function testAddWidgetButton() { $icon_two = $this->addParagraphsTypeIcon('text'); // Add a text field to the text_paragraph type. - static::fieldUIAddNewField('admin/structure/paragraphs_type/' . $paragraph_type, 'text', 'Text', 'text_long', [], []); + $this->drupalGet('admin/structure/paragraphs_type/' . $paragraph_type . '/fields/add-field'); + $page->selectFieldOption('new_storage_type', 'text_long'); + $page->fillField('label', 'Text'); + $this->assertSession()->waitForElementVisible('css', '#edit-name-machine-name-suffix .link'); + $page->pressButton('Edit'); + $page->fillField('field_name', 'text'); + $page->pressButton('Save and continue'); // Create paragraph type Nested test. $this->addParagraphsType('nested_test'); - static::fieldUIAddNewField('admin/structure/paragraphs_type/nested_test', 'paragraphs', 'Paragraphs', 'entity_reference_revisions', [ - 'settings[target_type]' => 'paragraph', - 'cardinality' => '-1', - ], []); + $this->drupalGet('/admin/structure/paragraphs_type/nested_test/fields/add-field'); + $page->selectFieldOption('new_storage_type', 'field_ui:entity_reference_revisions:paragraph'); + $page->fillField('label', 'Paragraphs'); + $this->assertSession()->waitForElementVisible('css', '#edit-name-machine-name-suffix .link'); + $page->pressButton('Edit'); + $page->fillField('field_name', 'paragraphs'); + $page->pressButton('Save and continue'); // Set the settings for the field in the nested paragraph. $component = [ @@ -112,7 +126,8 @@ public function testAddWidgetButton() { $page->pressButton('Add Paragraph'); $this->assertSession()->assertWaitOnAjaxRequest(); $this->assertSession()->elementTextContains('css', '.ui-dialog-title', 'Add Paragraph'); - $page->pressButton('nested_test'); + $paragraphs_dialog = $this->assertSession()->waitForElementVisible('css', 'div.ui-dialog'); + $paragraphs_dialog->pressButton('nested_test'); $this->assertSession()->assertWaitOnAjaxRequest(); // Verify that the paragraphs type icons are being displayed. @@ -136,11 +151,10 @@ public function testAddWidgetButton() { ]; $this->drupalPostForm(NULL, $edit, t('Save')); - // Check the created paragraphed test. - $this->assertText('paragraphed_test Example title has been created.'); - $this->assertRaw('paragraph--type--nested-test'); - $this->assertRaw('paragraph--type--text'); + $this->assertSession()->pageTextContainsOnce('paragraphed_test Example title has been created.'); + $this->assertSession()->elementTextContains('css', '.paragraph--type--nested-test', 'Paragraphs'); + $this->assertSession()->elementTextContains('css', '.paragraph--type--text', ''); // Add a paragraphs field with another paragraphs widget title to the // paragraphed_test content type. @@ -198,16 +212,40 @@ public function testModalAddWidgetDelta() { $this->addParagraphsType('test_3'); // Add a text field to the text_paragraph type. - static::fieldUIAddNewField('admin/structure/paragraphs_type/test_1', 'text_1', 'Text', 'text_long', [], []); - static::fieldUIAddNewField('admin/structure/paragraphs_type/test_2', 'text_2', 'Text', 'text_long', [], []); - static::fieldUIAddNewField('admin/structure/paragraphs_type/test_3', 'text_3', 'Text', 'text_long', [], []); + $this->drupalGet('admin/structure/paragraphs_type/test_1/fields/add-field'); + $page->selectFieldOption('new_storage_type', 'text_long'); + $page->fillField('label', 'Text'); + $this->assertSession()->waitForElementVisible('css', '#edit-name-machine-name-suffix .link'); + $page->pressButton('Edit'); + $page->fillField('field_name', 'text_1'); + $page->pressButton('Save and continue'); + + $this->drupalGet('admin/structure/paragraphs_type/test_2/fields/add-field'); + $page->selectFieldOption('new_storage_type', 'text_long'); + $page->fillField('label', 'Text'); + $this->assertSession()->waitForElementVisible('css', '#edit-name-machine-name-suffix .link'); + $page->pressButton('Edit'); + $page->fillField('field_name', 'text_2'); + $page->pressButton('Save and continue'); + + $this->drupalGet('admin/structure/paragraphs_type/test_3/fields/add-field'); + $page->selectFieldOption('new_storage_type', 'text_long'); + $page->fillField('label', 'Text'); + $this->assertSession()->waitForElementVisible('css', '#edit-name-machine-name-suffix .link'); + $page->pressButton('Edit'); + $page->fillField('field_name', 'test_3'); + $page->pressButton('Save and continue'); // Create paragraph type Nested test. $this->addParagraphsType('test_nested'); - static::fieldUIAddNewField('admin/structure/paragraphs_type/test_nested', 'paragraphs', 'Paragraphs', 'entity_reference_revisions', [ - 'settings[target_type]' => 'paragraph', - 'cardinality' => '-1', - ], []); + + $this->drupalGet('/admin/structure/paragraphs_type/test_nested/fields/add-field'); + $page->selectFieldOption('new_storage_type', 'field_ui:entity_reference_revisions:paragraph'); + $page->fillField('label', 'Paragraphs'); + $this->assertSession()->waitForElementVisible('css', '#edit-name-machine-name-suffix .link'); + $page->pressButton('Edit'); + $page->fillField('field_name', 'paragraphs'); + $page->pressButton('Save and continue'); // Set the settings for the field in the nested paragraph. $component = [ @@ -387,20 +425,19 @@ public function testModalAddWidgetDelta() { $this->drupalGet('node/add/test_modal_delta'); // Add a new Paragraph. $page->find('xpath', '//*[@name="button_add_modal"]')->click(); - $this->assertSession()->assertWaitOnAjaxRequest(); - $page->find('xpath', '//*[contains(@class, "paragraphs-add-dialog") and contains(@class, "ui-dialog-content")]//*[contains(@name, "test_1")]')->click(); + $paragraphs_dialog = $this->assertSession()->waitForElementVisible('css', 'div.ui-dialog'); + $paragraphs_dialog->find('xpath', '//*[contains(@class, "paragraphs-add-dialog") and contains(@class, "ui-dialog-content")]//*[contains(@name, "test_1")]')->press(); $this->assertSession()->assertWaitOnAjaxRequest(); // Attempt to add a new Paragraph above and cancel. $page->find('xpath', '//*[@name="button_add_modal"]')->click(); - $this->assertSession()->assertWaitOnAjaxRequest(); $this->getSession()->executeScript("jQuery('input.paragraph-type-add-modal-delta').first().val(0)"); $this->assertSession()->elementExists('css', '.ui-dialog-titlebar-close')->press(); $delta = $this->getSession()->evaluateScript("jQuery('paragraph-type-add-modal-delta').val()"); $this->assertEquals($delta, ''); // Add a new Paragraph with the Add button at the bottom. $page->find('xpath', '//*[@name="button_add_modal"]')->click(); - $this->assertSession()->assertWaitOnAjaxRequest(); - $page->find('xpath', '//*[contains(@class, "paragraphs-add-dialog") and contains(@class, "ui-dialog-content")]//*[contains(@name, "test_2")]')->click(); + $paragraphs_dialog = $this->assertSession()->waitForElementVisible('css', 'div.ui-dialog'); + $paragraphs_dialog->find('xpath', '//*[contains(@class, "paragraphs-add-dialog") and contains(@class, "ui-dialog-content")]//*[contains(@name, "test_2")]')->press(); $this->assertSession()->assertWaitOnAjaxRequest(); // The position of it should be below the first added Paragraph. $base_paragraphs = $page->findAll('xpath', '//*[contains(@class, "paragraph-type-label") and not(ancestor::div[contains(@class, "paragraphs-nested")])]'); diff --git a/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalClientsideButtonsTest.php b/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalClientsideButtonsTest.php index cf14f6628d..cdfd77a050 100644 --- a/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalClientsideButtonsTest.php +++ b/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalClientsideButtonsTest.php @@ -2,9 +2,9 @@ namespace Drupal\Tests\paragraphs\FunctionalJavascript; -use Drupal\field_ui\Tests\FieldUiTestTrait; -use Drupal\FunctionalJavascriptTests\JavascriptTestBase; -use Drupal\paragraphs\Tests\Classic\ParagraphsCoreVersionUiTestTrait; +use Drupal\FunctionalJavascriptTests\WebDriverTestBase; +use Drupal\Tests\field_ui\Traits\FieldUiTestTrait; +use Drupal\Tests\paragraphs\Traits\ParagraphsCoreVersionUiTestTrait; use Drupal\Tests\paragraphs\Traits\ParagraphsLastEntityQueryTrait; /** @@ -12,7 +12,7 @@ * * @group paragraphs */ -class ParagraphsExperimentalClientsideButtonsTest extends JavascriptTestBase { +class ParagraphsExperimentalClientsideButtonsTest extends WebDriverTestBase { use LoginAdminTrait; use FieldUiTestTrait; @@ -33,6 +33,11 @@ class ParagraphsExperimentalClientsideButtonsTest extends JavascriptTestBase { 'link', ]; + /** + * {@inheritdoc} + */ + protected $defaultTheme = 'stark'; + /** * {@inheritdoc} */ @@ -86,10 +91,15 @@ public function testAddParagraphAboveButton() { // Add a Paragraph type. $this->addParagraphsType('text'); // Add a text field to the text_paragraph type. - static::fieldUIAddNewField('admin/structure/paragraphs_type/text', 'text', 'Text', 'string', [], []); + $this->drupalGet('admin/structure/paragraphs_type/text/fields/add-field'); + $page->selectFieldOption('new_storage_type', 'string'); + $page->fillField('label', 'Text'); + $this->assertSession()->waitForElementVisible('css', '#edit-name-machine-name-suffix .link'); + $page->pressButton('Edit'); + $page->fillField('field_name', 'text'); + $page->pressButton('Save and continue'); // Add a paragraphed test. $this->drupalGet('node/add/paragraphed_test'); - // Add 3 paragraphs. $page->pressButton('Add Paragraph'); $assert_session->assertWaitOnAjaxRequest(); @@ -159,6 +169,15 @@ public function testAddParagraphAboveButton() { $dialog = $page->find('xpath', '//div[contains(@class, "ui-dialog")]'); $dialog->pressButton('text'); $assert_session->assertWaitOnAjaxRequest(); + $page->fillField('field_paragraphs[3][subform][field_text][0][value]', 'Paragraph added above'); + + // Add a new paragraph in order to test that the new paragraph is added at the bottom. + $page->pressButton('Add Paragraph'); + $assert_session->assertWaitOnAjaxRequest(); + $dialog = $page->find('xpath', '//div[contains(@class, "ui-dialog")]'); + $dialog->pressButton('text'); + $assert_session->assertWaitOnAjaxRequest(); + $page->fillField('field_paragraphs[4][subform][field_text][0][value]', 'New paragraph'); // First row after insertion. $first_row = $assert_session->elementExists('css', '#field-paragraphs-add-more-wrapper tr.draggable:nth-of-type(1)'); @@ -169,7 +188,7 @@ public function testAddParagraphAboveButton() { // Second row after insertion. $second_row = $assert_session->elementExists('css', '#field-paragraphs-add-more-wrapper tr.draggable:nth-of-type(2)'); $text_input_second_row = $assert_session->elementExists('css', 'input.form-text', $second_row); - $this->assertEquals('', $text_input_second_row->getValue()); + $this->assertEquals('Paragraph added above', $text_input_second_row->getValue()); $delta_paragraph2 = $assert_session->elementExists('css', 'td.delta-order select', $second_row)->getValue(); $this->assertEquals(1, $delta_paragraph2); // Third row after insertion. @@ -184,6 +203,11 @@ public function testAddParagraphAboveButton() { $this->assertEquals('Third text', $text_input_fourth_row->getValue()); $delta_paragraph4 = $assert_session->elementExists('css', 'td.delta-order select', $fourth_row)->getValue(); $this->assertEquals(3, $delta_paragraph4); + $fifth_row = $assert_session->elementExists('css', '#field-paragraphs-add-more-wrapper tr.draggable:nth-of-type(5)'); + $text_input_fifth_row = $assert_session->elementExists('css', 'input.form-text', $fifth_row); + $this->assertEquals('New paragraph', $text_input_fifth_row->getValue()); + $delta_paragraph5 = $assert_session->elementExists('css', 'td.delta-order select', $fifth_row)->getValue(); + $this->assertEquals(4, $delta_paragraph5); // Let's have more fun with some nested paragraphs. $this->addParagraphsType('rich_paragraph'); diff --git a/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalEditPerspectivesUiTest.php b/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalEditPerspectivesUiTest.php index adfdb81551..99fa178914 100644 --- a/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalEditPerspectivesUiTest.php +++ b/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalEditPerspectivesUiTest.php @@ -3,16 +3,15 @@ namespace Drupal\Tests\paragraphs\FunctionalJavascript; use Drupal\Core\Entity\Entity\EntityFormDisplay; -use Drupal\field\Entity\FieldConfig; -use Drupal\field\Entity\FieldStorageConfig; -use Drupal\FunctionalJavascriptTests\JavascriptTestBase; +use Drupal\FunctionalJavascriptTests\WebDriverTestBase; +use Drupal\paragraphs\Entity\ParagraphsType; /** * Test paragraphs user interface. * * @group paragraphs */ -class ParagraphsExperimentalEditPerspectivesUiTest extends JavascriptTestBase { +class ParagraphsExperimentalEditPerspectivesUiTest extends WebDriverTestBase { use LoginAdminTrait; use ParagraphsTestBaseTrait; @@ -33,6 +32,11 @@ class ParagraphsExperimentalEditPerspectivesUiTest extends JavascriptTestBase { 'text', ]; + /** + * {@inheritdoc} + */ + protected $defaultTheme = 'stark'; + /** * {@inheritdoc} */ @@ -41,54 +45,75 @@ protected function setUp() { } /** - * Test paragraphs user interface. + * Tests visibility of elements when switching perspectives. */ public function testEditPerspectives() { - $this->loginAsAdmin([ - 'access content overview', 'edit behavior plugin settings' ]); $page = $this->getSession()->getPage(); $this->drupalGet('admin/structure/paragraphs_type/add'); - $edit = [ - 'label' => 'TestPlugin', - 'id' => 'testplugin', - 'behavior_plugins[test_text_color][enabled]' => TRUE, - ]; - $this->drupalPostForm(NULL, $edit, t('Save and manage fields')); - $this->drupalGet('admin/structure/types/add'); - $edit = [ - 'name' => 'TestContent', - 'type' => 'testcontent', - ]; - $this->drupalPostForm(NULL, $edit, t('Save and manage fields')); - $this->drupalGet('admin/structure/types/manage/testcontent/fields/add-field'); - $edit = [ - 'new_storage_type' => 'field_ui:entity_reference_revisions:paragraph', - 'label' => 'testparagraphfield', - 'field_name' => 'testparagraphfield', - ]; - $this->drupalPostForm(NULL, $edit, t('Save and continue')); - $edit = [ - 'settings[target_type]' => 'paragraph', - ]; - $this->drupalPostForm(NULL, $edit, t('Save field settings')); - $edit = [ - 'settings[handler_settings][target_bundles_drag_drop][testplugin][enabled]' => TRUE, - ]; - $this->drupalPostForm(NULL, $edit, t('Save settings')); - $this->drupalGet('admin/structure/types/manage/testcontent/form-display'); - $page->selectFieldOption('fields[field_testparagraphfield][type]', 'paragraphs'); - $this->assertSession()->assertWaitOnAjaxRequest(); - $this->drupalPostForm(NULL, [], t('Save')); + $page->fillField('label', 'TestPlugin'); + $this->assertSession()->waitForElementVisible('css', '#edit-name-machine-name-suffix .link'); + $page->pressButton('Edit'); + $page->fillField('id', 'testplugin'); + $page->checkField('behavior_plugins[test_text_color][enabled]'); + $page->pressButton('Save and manage fields'); + + $this->addParagraphedContentType('testcontent', 'field_testparagraphfield'); + $this->addFieldtoParagraphType('testplugin', 'body', 'string_long'); + $this->drupalGet('node/add/testcontent'); + $add_wrapper = $page->find('css', '.paragraphs-add-wrapper'); + $this->assertTrue($add_wrapper->isVisible()); $this->clickLink('Behavior'); + $this->assertFalse($add_wrapper->isVisible()); $style_selector = $page->find('css', '.form-item-field-testparagraphfield-0-behavior-plugins-test-text-color-text-color'); $this->assertTrue($style_selector->isVisible()); $this->clickLink('Content'); $this->assertFalse($style_selector->isVisible()); + + // Assert scroll position when switching tabs. + $this->getSession()->resizeWindow(800, 500); + $this->drupalGet('node/add/testcontent'); + $button = $this->getSession ()->getPage()->findButton('Add TestPlugin'); + $button->press(); + $this->assertSession()->assertWaitOnAjaxRequest(); + $button->press(); + $this->assertSession()->assertWaitOnAjaxRequest(); + $button->press(); + $this->assertSession()->assertWaitOnAjaxRequest(); + + // First move to the last paragraph, assert that the tabs are + // still visible, then move back up to the second. + $this->getSession()->getPage()->find('css', '.field--widget-paragraphs tbody > tr:nth-child(4)')->mouseOver(); + $this->assertSession()->assertVisibleInViewport('css', '.paragraphs-tabs'); + $this->getSession()->getPage()->find('css', '.field--widget-paragraphs tbody > tr:nth-child(2)')->mouseOver(); + $this->getSession()->evaluateScript('window.scrollBy(0, -10);'); + + // As a result, only paragraph 2 and 3 are fully visible on the content tab. + $this->assertSession()->assertNotVisibleInViewport('css', '.field--widget-paragraphs tbody > tr:first-child'); + $this->assertSession()->assertVisibleInViewport('css', '.field--widget-paragraphs tbody > tr:nth-child(2)'); + $this->assertSession()->assertVisibleInViewport('css', '.field--widget-paragraphs tbody > tr:nth-child(3)'); + $this->assertSession()->assertNotVisibleInViewport('css', '.field--widget-paragraphs tbody > tr:nth-child(4)'); + $this->assertSession()->assertNotVisibleInViewport('css', '.field-add-more-submit'); + + // When clicking the Behavior tab, paragraph 2, 3 and 4 are in the viewport + // because the behavior settings take less space. + $this->clickLink('Behavior'); + $this->assertSession()->assertVisibleInViewport('css', '.field--widget-paragraphs tbody > tr:nth-child(2)'); + $this->assertSession()->assertVisibleInViewport('css', '.field--widget-paragraphs tbody > tr:nth-child(3)'); + $this->assertSession()->assertVisibleInViewport('css', '.field--widget-paragraphs tbody > tr:nth-child(4)'); + + // When we switch back to the Content tab, we should stay on the same + // scroll position as before. + $this->clickLink('Content'); + $this->assertSession()->assertNotVisibleInViewport('css', '.field--widget-paragraphs tbody > tr:first-child'); + $this->assertSession()->assertVisibleInViewport('css', '.field--widget-paragraphs tbody > tr:nth-child(2)'); + $this->assertSession()->assertVisibleInViewport('css', '.field--widget-paragraphs tbody > tr:nth-child(3)'); + $this->assertSession()->assertNotVisibleInViewport('css', '.field--widget-paragraphs tbody > tr:nth-child(4)'); + $this->assertSession()->assertNotVisibleInViewport('css', '.field-add-more-submit'); } /** @@ -101,24 +126,27 @@ public function testTabsVisibility() { $page = $this->getSession()->getPage(); $this->drupalGet('admin/structure/paragraphs_type/add'); - $edit = [ - 'label' => 'TestPlugin', - 'id' => 'testplugin', - ]; - $this->drupalPostForm(NULL, $edit, t('Save and manage fields')); + $page->fillField('label', 'TestPlugin'); + $this->assertSession()->waitForElementVisible('css', '#edit-name-machine-name-suffix .link'); + $page->pressButton('Edit'); + $page->fillField('id', 'testplugin'); + $page->pressButton('Save and manage fields'); + $this->drupalGet('admin/structure/types/add'); - $edit = [ - 'name' => 'TestContent', - 'type' => 'testcontent', - ]; - $this->drupalPostForm(NULL, $edit, t('Save and manage fields')); + $page->fillField('name', 'TestContent'); + $this->assertSession()->waitForElementVisible('css', '#edit-name-machine-name-suffix .link'); + $page->pressButton('Edit'); + $page->fillField('type', 'testcontent'); + $page->pressButton('Save and manage fields'); + $this->drupalGet('admin/structure/types/manage/testcontent/fields/add-field'); - $edit = [ - 'new_storage_type' => 'field_ui:entity_reference_revisions:paragraph', - 'label' => 'testparagraphfield', - 'field_name' => 'testparagraphfield', - ]; - $this->drupalPostForm(NULL, $edit, t('Save and continue')); + $page->selectFieldOption('new_storage_type', 'field_ui:entity_reference_revisions:paragraph'); + $page->fillField('label', 'testparagraphfield'); + $this->assertSession()->waitForElementVisible('css', '#edit-name-machine-name-suffix .link'); + $page->pressButton('Edit'); + $page->fillField('field_name', 'testparagraphfield'); + $page->pressButton('Save and continue'); + $edit = [ 'settings[target_type]' => 'paragraph', ]; diff --git a/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalWidgetElementsTest.php b/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalWidgetElementsTest.php index e734cb2dbf..1e46df361a 100644 --- a/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalWidgetElementsTest.php +++ b/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalWidgetElementsTest.php @@ -2,7 +2,7 @@ namespace Drupal\Tests\paragraphs\FunctionalJavascript; -use Drupal\FunctionalJavascriptTests\JavascriptTestBase; +use Drupal\FunctionalJavascriptTests\WebDriverTestBase; use Drupal\language\Entity\ConfigurableLanguage; /** @@ -10,7 +10,7 @@ * * @group paragraphs */ -class ParagraphsExperimentalWidgetElementsTest extends JavascriptTestBase { +class ParagraphsExperimentalWidgetElementsTest extends WebDriverTestBase { use LoginAdminTrait; use ParagraphsTestBaseTrait; @@ -31,6 +31,11 @@ class ParagraphsExperimentalWidgetElementsTest extends JavascriptTestBase { 'content_translation', ]; + /** + * {@inheritdoc} + */ + protected $defaultTheme = 'stark'; + /** * Test paragraphs drag handler during translation. */ @@ -66,8 +71,8 @@ public function testDragHandler() { $page = $this->getSession()->getPage(); $this->drupalGet('node/add/paragraphed_content_demo'); $page->pressButton('Add Paragraph'); - $this->assertSession()->assertWaitOnAjaxRequest(); - $page->pressButton('text'); + $paragraphs_dialog = $this->assertSession()->waitForElementVisible('css', 'div.ui-dialog'); + $paragraphs_dialog->pressButton('text'); $this->assertSession()->assertWaitOnAjaxRequest(); // Assert the draghandle is visible. $style_selector = $page->find('css', '.tabledrag-handle'); diff --git a/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsTestBaseTrait.php b/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsTestBaseTrait.php index c317b2f717..201df18ab1 100644 --- a/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsTestBaseTrait.php +++ b/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsTestBaseTrait.php @@ -126,7 +126,9 @@ protected function addParagraphsTypeIcon($paragraphs_type) { // Create a copy of the image, so that multiple file entities don't // reference the same file. - $copy_uri = file_unmanaged_copy($uri); + /** @var \Drupal\Core\File\FileSystemInterface $file_system */ + $file_system = \Drupal::service('file_system'); + $copy_uri = $file_system->copy($uri, 'public://' . $file_system->basename($uri)); // Create a new file entity. $file_entity = File::create([ diff --git a/web/modules/paragraphs/tests/src/Kernel/ParagraphsAccessTest.php b/web/modules/paragraphs/tests/src/Kernel/ParagraphsAccessTest.php index ba1baa486c..9dc7e00163 100644 --- a/web/modules/paragraphs/tests/src/Kernel/ParagraphsAccessTest.php +++ b/web/modules/paragraphs/tests/src/Kernel/ParagraphsAccessTest.php @@ -5,7 +5,7 @@ use Drupal\Core\Access\AccessResult; use Drupal\Core\Cache\Context\CacheContextsManager; use Drupal\Core\DependencyInjection\ContainerBuilder; -use Drupal\Tests\token\Kernel\KernelTestBase; +use Drupal\KernelTests\KernelTestBase; use Symfony\Component\HttpFoundation\Request; /** diff --git a/web/modules/paragraphs/tests/src/Kernel/ParagraphsBehaviorPluginsTest.php b/web/modules/paragraphs/tests/src/Kernel/ParagraphsBehaviorPluginsTest.php index 7916deb46e..7d2508c9c1 100644 --- a/web/modules/paragraphs/tests/src/Kernel/ParagraphsBehaviorPluginsTest.php +++ b/web/modules/paragraphs/tests/src/Kernel/ParagraphsBehaviorPluginsTest.php @@ -73,7 +73,7 @@ public function testBehaviorSettings() { // Check the text color plugin settings summary. $plugin = $paragraph->getParagraphType()->getBehaviorPlugins()->getEnabled(); - $this->assertEquals($plugin['test_text_color']->settingsSummary($paragraph)[0], 'Text color: red'); + $this->assertEquals($plugin['test_text_color']->settingsSummary($paragraph)[0], ['label' => 'Text color', 'value' => 'red']); // Update the value of an specific plugin. $paragraph->setBehaviorSettings('test_text_color', ['text_color' => 'blue']); @@ -85,8 +85,41 @@ public function testBehaviorSettings() { // Check the text color plugin settings summary. $plugin = $paragraph->getParagraphType()->getBehaviorPlugins()->getEnabled(); - $this->assertEquals($plugin['test_text_color']->settingsSummary($paragraph)[0], 'Text color: blue'); + $this->assertEquals($plugin['test_text_color']->settingsSummary($paragraph)[0], ['label' => 'Text color', 'value' => 'blue']); } + /** + * Tests uninstalling a behavior plugin providing module. + * + * @throws \Drupal\Core\Entity\EntityStorageException + */ + public function testBehaviorUninstall() { + // Create a paragraph type. + $paragraph_type = ParagraphsType::create([ + 'label' => 'test_text', + 'id' => 'test_text', + 'behavior_plugins' => [ + 'test_text_color' => [ + 'enabled' => TRUE, + ], + ], + ]); + $paragraph_type->save(); + $dependencies = $paragraph_type->getDependencies(); + $plugins = $paragraph_type->getBehaviorPlugins()->getInstanceIds(); + $this->assertSame(['module' => ['paragraphs_test']], $dependencies); + $this->assertSame(['test_text_color' => 'test_text_color'], $plugins); + + // Uninstall plugin providing module. + $this->container->get('config.manager')->uninstall('module', 'paragraphs_test'); + + $paragraph_type = ParagraphsType::load('test_text'); + $this->assertNotNull($paragraph_type); + $dependencies = $paragraph_type->getDependencies(); + $plugins = $paragraph_type->getBehaviorPlugins()->getInstanceIds(); + $this->assertSame([], $dependencies); + $this->assertSame([], $plugins); + } + } diff --git a/web/modules/paragraphs/tests/src/Kernel/ParagraphsCollapsedSummaryTest.php b/web/modules/paragraphs/tests/src/Kernel/ParagraphsCollapsedSummaryTest.php index 6eb25db379..93be4840af 100644 --- a/web/modules/paragraphs/tests/src/Kernel/ParagraphsCollapsedSummaryTest.php +++ b/web/modules/paragraphs/tests/src/Kernel/ParagraphsCollapsedSummaryTest.php @@ -3,11 +3,14 @@ namespace Drupal\Tests\paragraphs\Kernel; use Drupal\Core\Entity\Entity\EntityFormDisplay; +use Drupal\Core\Field\FieldStorageDefinitionInterface; use Drupal\field\Entity\FieldConfig; use Drupal\field\Entity\FieldStorageConfig; use Drupal\paragraphs\Entity\Paragraph; use Drupal\paragraphs\Entity\ParagraphsType; use Drupal\KernelTests\KernelTestBase; +use Drupal\Tests\field\Traits\EntityReferenceTestTrait; +use Drupal\Tests\user\Traits\UserCreationTrait; /** * Tests the collapsed summary options. @@ -16,6 +19,9 @@ */ class ParagraphsCollapsedSummaryTest extends KernelTestBase { + use EntityReferenceTestTrait; + use UserCreationTrait; + /** * Modules to enable. * @@ -26,6 +32,7 @@ class ParagraphsCollapsedSummaryTest extends KernelTestBase { 'user', 'system', 'field', + 'entity_reference', 'entity_reference_revisions', 'paragraphs_test', 'file', @@ -95,7 +102,7 @@ public function testCollapsedSummaryOptions() { // Load the paragraph and assert its stored feature settings. $paragraph = Paragraph::load($paragraph->id()); $this->assertEquals($paragraph->getAllBehaviorSettings(), $feature_settings); - $this->assertEquals($paragraph->getSummary(), 'Example text for a text paragraph, Text color: red'); + $this->assertEquals($paragraph->getSummary(), '<div class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">Example text for a text paragraph</span></div><div class="paragraphs-plugin-wrapper"><span class="summary-plugin"><span class="summary-plugin-label">Text color</span>red</span></div></div>'); // Check the summary and the additional options. $paragraph_1 = Paragraph::create([ @@ -103,8 +110,9 @@ public function testCollapsedSummaryOptions() { 'nested_paragraph_field' => [$paragraph], ]); $paragraph_1->save(); - $this->assertEquals($paragraph_1->getSummary(), 'Example text for a text paragraph, Text color: red'); - $this->assertEquals($paragraph_1->getSummary(['show_behavior_summary' => FALSE]), 'Example text for a text paragraph'); + // We do not include behavior summaries of nested children in the parent + // summary. + $this->assertEquals($paragraph_1->getSummary(), '<div class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">Example text for a text paragraph</span></div></div>'); $info = $paragraph_1->getIcons(); $this->assertEquals($info['count']['#prefix'], '<span class="paragraphs-badge" title="1 child">'); $this->assertEquals($info['count']['#suffix'], '</span>'); @@ -143,13 +151,40 @@ public function testNestedParagraphSummary() { 'nested_paragraph_field' => [$paragraph_text_2, $paragraph_nested_1], ]); $paragraph_nested_2->save(); - $this->assertEquals($paragraph_nested_2->getSummary(['show_behavior_summary' => FALSE]), 'Text paragraph on top level'); - $this->assertEquals($paragraph_nested_2->getSummary(['show_behavior_summary' => FALSE, 'depth_limit' => 2]), 'Text paragraph on top level, Text paragraph on nested level'); + $this->assertEquals($paragraph_nested_2->getSummary(['show_behavior_summary' => FALSE]), '<div class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">Text paragraph on top level</span></div></div>'); + $this->assertEquals($paragraph_nested_2->getSummary(['show_behavior_summary' => FALSE, 'depth_limit' => 2]), '<div class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">Text paragraph on top level</span>, <span class="summary-content">Text paragraph on nested level</span></div></div>'); $info = $paragraph_nested_2->getIcons(); $this->assertEquals($info['count']['#prefix'], '<span class="paragraphs-badge" title="2 children">'); $this->assertEquals($info['count']['#suffix'], '</span>'); } + /** + * Tests multiple entity references are visible in the paragraph summary. + */ + public function testMultipleEntityReferences() { + $user1 = $this->createUser([], 'bob'); + $user2 = $this->createUser([], 'pete'); + $paragraphs_type = ParagraphsType::create([ + 'label' => 'Multiple entity references', + 'id' => 'multiple_entity_references', + ]); + $paragraphs_type->save(); + $this->createEntityReferenceField('paragraph', 'multiple_entity_references', 'field_user_references', 'Users', 'user', 'default', [], FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED); + EntityFormDisplay::create([ + 'targetEntityType' => 'paragraph', + 'bundle' => 'multiple_entity_references', + 'mode' => 'default', + 'status' => TRUE, + ])->setComponent('field_user_references', ['type' => 'options_select'])->save(); + $paragraph_with_multiple_entity_references = Paragraph::create([ + 'type' => 'multiple_entity_references', + ]); + $paragraph_with_multiple_entity_references->get('field_user_references')->appendItem($user1->id()); + $paragraph_with_multiple_entity_references->get('field_user_references')->appendItem($user2->id()); + $paragraph_with_multiple_entity_references->save(); + $this->assertEquals('<div class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">bob</span>, <span class="summary-content">pete</span></div></div>', $paragraph_with_multiple_entity_references->getSummary()); + } + /** * Adds a field to a given paragraph type. * diff --git a/web/modules/paragraphs/tests/src/Kernel/ParagraphsCompositeRelationshipTest.php b/web/modules/paragraphs/tests/src/Kernel/ParagraphsCompositeRelationshipTest.php index c63d894616..4be7c37a80 100644 --- a/web/modules/paragraphs/tests/src/Kernel/ParagraphsCompositeRelationshipTest.php +++ b/web/modules/paragraphs/tests/src/Kernel/ParagraphsCompositeRelationshipTest.php @@ -2,7 +2,6 @@ namespace Drupal\Tests\paragraphs\Kernel; -use Drupal\Core\Entity\Entity; use Drupal\Core\Site\Settings; use Drupal\field\Entity\FieldConfig; use Drupal\field\Entity\FieldStorageConfig; diff --git a/web/modules/paragraphs/tests/src/Kernel/ParagraphsEntityMethodsTest.php b/web/modules/paragraphs/tests/src/Kernel/ParagraphsEntityMethodsTest.php new file mode 100644 index 0000000000..c4b7805737 --- /dev/null +++ b/web/modules/paragraphs/tests/src/Kernel/ParagraphsEntityMethodsTest.php @@ -0,0 +1,117 @@ +<?php + +namespace Drupal\Tests\paragraphs\Kernel; + +use Drupal\field\Entity\FieldStorageConfig; +use Drupal\KernelTests\KernelTestBase; +use Drupal\node\Entity\Node; +use Drupal\paragraphs\Entity\Paragraph; +use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait; +use Drupal\Tests\paragraphs\Traits\ParagraphsLastEntityQueryTrait; + +/** + * Tests some methods from the Paragraph entity. + * + * @group paragraphs + */ +class ParagraphsEntityMethodsTest extends KernelTestBase { + + use ParagraphsTestBaseTrait; + + /** + * Modules to enable. + * + * @var string[] + */ + public static $modules = [ + 'paragraphs', + 'node', + 'user', + 'system', + 'field', + 'entity_reference_revisions', + 'file', + ]; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + $this->installEntitySchema('user'); + $this->installEntitySchema('node'); + $this->installEntitySchema('paragraph'); + $this->installSchema('system', ['sequences']); + $this->installSchema('node', ['node_access']); + \Drupal::moduleHandler()->loadInclude('paragraphs', 'install'); + } + + /** + * Tests the ::label() behavior on the paragraph entity. + */ + public function testParagraphLabel() { + $this->addParagraphedContentType('paragraphed_test'); + $paragraph_type = 'text_paragraph'; + $this->addParagraphsType($paragraph_type); + $this->addFieldtoParagraphType($paragraph_type, 'field_text', 'string'); + + // Create a node with a paragraph. + $paragraph = Paragraph::create([ + 'type' => 'text_paragraph', + 'field_text' => 'Example text that is very long and needs to be shortened.', + ]); + $paragraph->save(); + $node = Node::create([ + 'title' => 'Test Node', + 'type' => 'paragraphed_test', + 'field_paragraphs' => [ + $paragraph, + ], + ]); + $node->save(); + + $storage = \Drupal::entityTypeManager()->getStorage('paragraph'); + + // By this point the label should include the parent entity's label and the + // field label. + $paragraph = $storage->loadUnchanged($paragraph->id()); + $this->assertEquals('Test Node > field_paragraphs', $paragraph->label()); + + // Create a new revision without the paragraph and verify the label on the + // paragraph entity reflects that. + /** @var \Drupal\node\NodeInterface $node */ + $node->set('field_paragraphs', []); + $node->setNewRevision(TRUE); + $node->save(); + $paragraph = $storage->loadUnchanged($paragraph->id()); + $this->assertEquals('Test Node > field_paragraphs (previous revision)', $paragraph->label()); + + // Delete the node and check if the label reflects that. + $node->delete(); + $paragraph = $storage->loadUnchanged($paragraph->id()); + $this->assertEquals('Orphaned text_paragraph: Example text that is very long and needs to be sh…', $paragraph->label()); + + $paragraph3 = Paragraph::create([ + 'type' => 'text_paragraph', + 'field_text' => 'Example text3', + ]); + $paragraph3->save(); + $node3 = Node::create([ + 'title' => 'Test Node 3', + 'type' => 'paragraphed_test', + 'field_paragraphs' => [ + $paragraph3, + ], + ]); + $node3->save(); + $paragraph3 = $storage->loadUnchanged($paragraph3->id()); + $this->assertEquals('Test Node 3 > field_paragraphs', $paragraph3->label()); + + // If we delete the field on the node type, the paragraph becomes orphan. + FieldStorageConfig::load('node.field_paragraphs')->delete(); + \Drupal::service('entity.memory_cache')->deleteAll(); + $paragraph3 = $storage->loadUnchanged($paragraph3->id()); + $this->assertEquals('Orphaned text_paragraph: Example text3', $paragraph3->label()); + } + +} diff --git a/web/modules/paragraphs/tests/src/Kernel/ParagraphsIsChangedTest.php b/web/modules/paragraphs/tests/src/Kernel/ParagraphsIsChangedTest.php index de98760a05..b8a9e21ae2 100644 --- a/web/modules/paragraphs/tests/src/Kernel/ParagraphsIsChangedTest.php +++ b/web/modules/paragraphs/tests/src/Kernel/ParagraphsIsChangedTest.php @@ -62,11 +62,6 @@ public function testIsChanged() { $paragraph->save(); $this->assertFalse($paragraph->isChanged(), 'Paragraph::isChanged() found no changes after the entity has been saved.'); - // Update the revision author field, which should be skipped from checking - // for changes in Paragraph::isChanged(). - $paragraph->setRevisionAuthorId(3); - $this->assertFalse($paragraph->isChanged(), 'Paragraph::isChanged() found no changes after updating revision_uid field.'); - $paragraph->set('text', 'New text'); $this->assertTrue($paragraph->isChanged(), 'Paragraph::isChanged() found changes after updating text field.'); } diff --git a/web/modules/paragraphs/tests/src/Kernel/ParagraphsReplicateTest.php b/web/modules/paragraphs/tests/src/Kernel/ParagraphsReplicateTest.php index a7b294fb61..2d2b68a03b 100644 --- a/web/modules/paragraphs/tests/src/Kernel/ParagraphsReplicateTest.php +++ b/web/modules/paragraphs/tests/src/Kernel/ParagraphsReplicateTest.php @@ -3,7 +3,6 @@ namespace Drupal\Tests\paragraphs\Kernel; use Drupal\Core\Entity\Entity; -use Drupal\Core\Site\Settings; use Drupal\field\Entity\FieldConfig; use Drupal\field\Entity\FieldStorageConfig; use Drupal\node\Entity\Node; @@ -11,7 +10,6 @@ use Drupal\paragraphs\Entity\Paragraph; use Drupal\paragraphs\Entity\ParagraphsType; use Drupal\KernelTests\KernelTestBase; -use Drupal\user\Entity\User; /** * Tests the replication functionality provided by Replicate module. diff --git a/web/modules/paragraphs/tests/src/Traits/ParagraphsCoreVersionUiTestTrait.php b/web/modules/paragraphs/tests/src/Traits/ParagraphsCoreVersionUiTestTrait.php new file mode 100644 index 0000000000..f08040b271 --- /dev/null +++ b/web/modules/paragraphs/tests/src/Traits/ParagraphsCoreVersionUiTestTrait.php @@ -0,0 +1,58 @@ +<?php + +namespace Drupal\Tests\paragraphs\Traits; + +/** + * Provides helper methods for Drupal 8.3.x and 8.4.x versions. + */ +trait ParagraphsCoreVersionUiTestTrait { + + /** + * An adapter for 8.3 > 8.4 Save (and (un)publish) node button change. + * + * Arguments are the same as WebTestBase::drupalPostForm. + * + * @see \Drupal\simpletest\WebTestBase::drupalPostForm + * @see https://www.drupal.org/node/2847274 + * + * @param \Drupal\Core\Url|string $path + * Location of the post form. + * @param array $edit + * Field data in an associative array. + * @param mixed $submit + * Value of the submit button whose click is to be emulated. For example, + * @param array $options + * (optional) Options to be forwarded to the url generator. + * @param array $headers + * (optional) An array containing additional HTTP request headers. + * @param string $form_html_id + * (optional) HTML ID of the form to be submitted. + * @param string $extra_post + * (optional) A string of additional data to append to the POST submission. + */ + protected function paragraphsPostNodeForm($path, $edit, $submit, array $options = [], array $headers = [], $form_html_id = NULL, $extra_post = NULL) { + $drupal_version = (float) substr(\Drupal::VERSION, 0, 3); + if ($drupal_version > 8.3) { + switch ($submit) { + case t('Save and unpublish'): + $submit = t('Save'); + $edit['status[value]'] = FALSE; + break; + + case t('Save and publish'): + $submit = t('Save'); + $edit['status[value]'] = TRUE; + break; + + case t('Save and keep published (this translation)'): + $submit = t('Save (this translation)'); + break; + + default: + $submit = t('Save'); + } + } + parent::drupalPostForm($path, $edit, $submit, $options, $headers, $form_html_id, $extra_post); + } + +} -- GitLab