diff --git a/composer.json b/composer.json index 6c97470805a9f510515b34904fef1177d817ae36..97007233277cd3e14e8060bd726e706f47b4fdb0 100644 --- a/composer.json +++ b/composer.json @@ -112,7 +112,7 @@ "drupal/ctools": "3.4", "drupal/devel": "2.0", "drupal/draggableviews": "1.0", - "drupal/dropzonejs": "2.3", + "drupal/dropzonejs": "2.4", "drupal/editor_advanced_link": "1.8", "drupal/embed": "1.4", "drupal/entity": "1.0-beta1", @@ -132,13 +132,13 @@ "drupal/honeypot": "1.30", "drupal/image_popup": "1.1", "drupal/inline_entity_form": "1.0-rc8", - "drupal/libraries": "3.0.0-alpha6", + "drupal/libraries": "3.0-beta1", "drupal/link_attributes": "1.11", "drupal/linkit": "5.0-beta12", "drupal/magnific_popup": "1.3", "drupal/mathjax": "2.7", "drupal/media_entity_browser": "2.0-alpha3", - "drupal/media_entity_twitter": "2.4", + "drupal/media_entity_twitter": "2.6", "drupal/menu_block": "1.6", "drupal/menu_block_title": "1.1", "drupal/menu_breadcrumb": "1.14", @@ -151,7 +151,7 @@ "drupal/mobile_device_detection": "3.2", "drupal/module_filter": "3.1", "drupal/multiple_fields_remove_button": "^1.0@alpha", - "drupal/pantheon_advanced_page_cache": "1.1", + "drupal/pantheon_advanced_page_cache": "1.2", "drupal/paragraphs": "1.12", "drupal/pathauto": "1.8", "drupal/realname": "1.0.0-rc2", @@ -183,7 +183,7 @@ "drupal/views_ajax_history": "1.5", "drupal/views_autocomplete_filters": "1.3", "drupal/views_bootstrap": "3.1", - "drupal/views_bulk_operations": "3.9", + "drupal/views_bulk_operations": "3.10", "drupal/views_fieldsets": "3.3", "drupal/views_infinite_scroll": "1.7", "drupal/views_slideshow": "4.4", diff --git a/composer.lock b/composer.lock index 3cfc95e1442f4d01d0d312a43b43aba26138161d..3f5bcca64b133e977bdca278117bcf288ceda350 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": "483958ad644d5bd3351af88c32212e2b", + "content-hash": "cf9dbe7bb1771287f68ffec2f43f12ce", "packages": [ { "name": "alchemy/zippy", @@ -4069,17 +4069,17 @@ }, { "name": "drupal/dropzonejs", - "version": "2.3.0", + "version": "2.4.0", "source": { "type": "git", "url": "https://git.drupalcode.org/project/dropzonejs.git", - "reference": "8.x-2.3" + "reference": "8.x-2.4" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/dropzonejs-8.x-2.3.zip", - "reference": "8.x-2.3", - "shasum": "c145f2560ed31de32ea8938b0c0378765f70e36a" + "url": "https://ftp.drupal.org/files/projects/dropzonejs-8.x-2.4.zip", + "reference": "8.x-2.4", + "shasum": "182e41163753bac785ad56d7d157cbe50706d706" }, "require": { "drupal/core": "^8.8 || ^9" @@ -4093,8 +4093,8 @@ "type": "drupal-module", "extra": { "drupal": { - "version": "8.x-2.3", - "datestamp": "1600311980", + "version": "8.x-2.4", + "datestamp": "1610726518", "security-coverage": { "status": "covered", "message": "Covered by Drupal's security advisory policy" @@ -5476,17 +5476,17 @@ }, { "name": "drupal/libraries", - "version": "3.0.0-alpha6", + "version": "3.0.0-beta1", "source": { "type": "git", "url": "https://git.drupalcode.org/project/libraries.git", - "reference": "8.x-3.0-alpha6" + "reference": "8.x-3.0-beta1" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/libraries-8.x-3.0-alpha6.zip", - "reference": "8.x-3.0-alpha6", - "shasum": "d2aaf7f0968a1864457a7741b7e38ab11ef83e2c" + "url": "https://ftp.drupal.org/files/projects/libraries-8.x-3.0-beta1.zip", + "reference": "8.x-3.0-beta1", + "shasum": "7843870c52251cc5290e1cdca94524f71edbf016" }, "require": { "drupal/core": "^8 || ^9" @@ -5494,17 +5494,17 @@ "type": "drupal-module", "extra": { "drupal": { - "version": "8.x-3.0-alpha6", - "datestamp": "1608099124", + "version": "8.x-3.0-beta1", + "datestamp": "1609758293", "security-coverage": { "status": "not-covered", - "message": "Alpha releases are not covered by Drupal security advisories." + "message": "Beta releases are not covered by Drupal security advisories." } } }, "notification-url": "https://packages.drupal.org/8/downloads", "license": [ - "GPL-2.0+" + "GPL-2.0-or-later" ], "authors": [ { @@ -5515,6 +5515,10 @@ "name": "joseph.olstad", "homepage": "https://www.drupal.org/user/1321830" }, + { + "name": "podarok", + "homepage": "https://www.drupal.org/user/116002" + }, { "name": "rjacobs", "homepage": "https://www.drupal.org/user/422459" @@ -5819,17 +5823,17 @@ }, { "name": "drupal/media_entity_twitter", - "version": "2.4.0", + "version": "2.6.0", "source": { "type": "git", "url": "https://git.drupalcode.org/project/media_entity_twitter.git", - "reference": "8.x-2.4" + "reference": "8.x-2.6" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/media_entity_twitter-8.x-2.4.zip", - "reference": "8.x-2.4", - "shasum": "11bca09cc6dd678dc7585d16d66167a09c6e42fb" + "url": "https://ftp.drupal.org/files/projects/media_entity_twitter-8.x-2.6.zip", + "reference": "8.x-2.6", + "shasum": "777062eb55314da47ee3878db6d10d022e91bed6" }, "require": { "drupal/core": "^8.8 || ^9", @@ -5837,12 +5841,9 @@ }, "type": "drupal-module", "extra": { - "branch-alias": { - "dev-2.x": "2.x-dev" - }, "drupal": { - "version": "8.x-2.4", - "datestamp": "1585646747", + "version": "8.x-2.6", + "datestamp": "1610375564", "security-coverage": { "status": "covered", "message": "Covered by Drupal's security advisory policy" @@ -6576,17 +6577,17 @@ }, { "name": "drupal/pantheon_advanced_page_cache", - "version": "1.1.0", + "version": "1.2.0", "source": { "type": "git", "url": "https://git.drupalcode.org/project/pantheon_advanced_page_cache.git", - "reference": "8.x-1.1" + "reference": "8.x-1.2" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/pantheon_advanced_page_cache-8.x-1.1.zip", - "reference": "8.x-1.1", - "shasum": "faef7abc7814c47dc0ba5cdb2c5a01f7386627ce" + "url": "https://ftp.drupal.org/files/projects/pantheon_advanced_page_cache-8.x-1.2.zip", + "reference": "8.x-1.2", + "shasum": "265f738df7e0d094f43b4f7a5b31ac3c5d799316" }, "require": { "drupal/core": "^8 || ^9" @@ -6599,8 +6600,8 @@ "type": "drupal-module", "extra": { "drupal": { - "version": "8.x-1.1", - "datestamp": "1589904160", + "version": "8.x-1.2", + "datestamp": "1611003910", "security-coverage": { "status": "covered", "message": "Covered by Drupal's security advisory policy" @@ -8473,17 +8474,17 @@ }, { "name": "drupal/views_bulk_operations", - "version": "3.9.0", + "version": "3.10.0", "source": { "type": "git", "url": "https://git.drupalcode.org/project/views_bulk_operations.git", - "reference": "8.x-3.9" + "reference": "8.x-3.10" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/views_bulk_operations-8.x-3.9.zip", - "reference": "8.x-3.9", - "shasum": "d7f6e50c31d21ff32f21e8f4aaedb52f6dee2da8" + "url": "https://ftp.drupal.org/files/projects/views_bulk_operations-8.x-3.10.zip", + "reference": "8.x-3.10", + "shasum": "e346c2a72fc9a1ae8af418e6a02076f52c0fcc7b" }, "require": { "drupal/core": "^8.8 || ^9" @@ -8497,8 +8498,8 @@ "type": "drupal-module", "extra": { "drupal": { - "version": "8.x-3.9", - "datestamp": "1597319021", + "version": "8.x-3.10", + "datestamp": "1608795018", "security-coverage": { "status": "covered", "message": "Covered by Drupal's security advisory policy" diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index e0aade52f2bc82bf9887eaf6622d5bef176e2262..f42a9ad2d804fd18186a8fe5567ba185e91b3695 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -4191,18 +4191,18 @@ }, { "name": "drupal/dropzonejs", - "version": "2.3.0", - "version_normalized": "2.3.0.0", + "version": "2.4.0", + "version_normalized": "2.4.0.0", "source": { "type": "git", "url": "https://git.drupalcode.org/project/dropzonejs.git", - "reference": "8.x-2.3" + "reference": "8.x-2.4" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/dropzonejs-8.x-2.3.zip", - "reference": "8.x-2.3", - "shasum": "c145f2560ed31de32ea8938b0c0378765f70e36a" + "url": "https://ftp.drupal.org/files/projects/dropzonejs-8.x-2.4.zip", + "reference": "8.x-2.4", + "shasum": "182e41163753bac785ad56d7d157cbe50706d706" }, "require": { "drupal/core": "^8.8 || ^9" @@ -4216,8 +4216,8 @@ "type": "drupal-module", "extra": { "drupal": { - "version": "8.x-2.3", - "datestamp": "1600311980", + "version": "8.x-2.4", + "datestamp": "1610726518", "security-coverage": { "status": "covered", "message": "Covered by Drupal's security advisory policy" @@ -5640,18 +5640,18 @@ }, { "name": "drupal/libraries", - "version": "3.0.0-alpha6", - "version_normalized": "3.0.0.0-alpha6", + "version": "3.0.0-beta1", + "version_normalized": "3.0.0.0-beta1", "source": { "type": "git", "url": "https://git.drupalcode.org/project/libraries.git", - "reference": "8.x-3.0-alpha6" + "reference": "8.x-3.0-beta1" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/libraries-8.x-3.0-alpha6.zip", - "reference": "8.x-3.0-alpha6", - "shasum": "d2aaf7f0968a1864457a7741b7e38ab11ef83e2c" + "url": "https://ftp.drupal.org/files/projects/libraries-8.x-3.0-beta1.zip", + "reference": "8.x-3.0-beta1", + "shasum": "7843870c52251cc5290e1cdca94524f71edbf016" }, "require": { "drupal/core": "^8 || ^9" @@ -5659,18 +5659,18 @@ "type": "drupal-module", "extra": { "drupal": { - "version": "8.x-3.0-alpha6", - "datestamp": "1608099124", + "version": "8.x-3.0-beta1", + "datestamp": "1609758293", "security-coverage": { "status": "not-covered", - "message": "Alpha releases are not covered by Drupal security advisories." + "message": "Beta releases are not covered by Drupal security advisories." } } }, "installation-source": "dist", "notification-url": "https://packages.drupal.org/8/downloads", "license": [ - "GPL-2.0+" + "GPL-2.0-or-later" ], "authors": [ { @@ -5681,6 +5681,10 @@ "name": "joseph.olstad", "homepage": "https://www.drupal.org/user/1321830" }, + { + "name": "podarok", + "homepage": "https://www.drupal.org/user/116002" + }, { "name": "rjacobs", "homepage": "https://www.drupal.org/user/422459" @@ -5995,18 +5999,18 @@ }, { "name": "drupal/media_entity_twitter", - "version": "2.4.0", - "version_normalized": "2.4.0.0", + "version": "2.6.0", + "version_normalized": "2.6.0.0", "source": { "type": "git", "url": "https://git.drupalcode.org/project/media_entity_twitter.git", - "reference": "8.x-2.4" + "reference": "8.x-2.6" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/media_entity_twitter-8.x-2.4.zip", - "reference": "8.x-2.4", - "shasum": "11bca09cc6dd678dc7585d16d66167a09c6e42fb" + "url": "https://ftp.drupal.org/files/projects/media_entity_twitter-8.x-2.6.zip", + "reference": "8.x-2.6", + "shasum": "777062eb55314da47ee3878db6d10d022e91bed6" }, "require": { "drupal/core": "^8.8 || ^9", @@ -6014,12 +6018,9 @@ }, "type": "drupal-module", "extra": { - "branch-alias": { - "dev-2.x": "2.x-dev" - }, "drupal": { - "version": "8.x-2.4", - "datestamp": "1585646747", + "version": "8.x-2.6", + "datestamp": "1610375564", "security-coverage": { "status": "covered", "message": "Covered by Drupal's security advisory policy" @@ -6778,18 +6779,18 @@ }, { "name": "drupal/pantheon_advanced_page_cache", - "version": "1.1.0", - "version_normalized": "1.1.0.0", + "version": "1.2.0", + "version_normalized": "1.2.0.0", "source": { "type": "git", "url": "https://git.drupalcode.org/project/pantheon_advanced_page_cache.git", - "reference": "8.x-1.1" + "reference": "8.x-1.2" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/pantheon_advanced_page_cache-8.x-1.1.zip", - "reference": "8.x-1.1", - "shasum": "faef7abc7814c47dc0ba5cdb2c5a01f7386627ce" + "url": "https://ftp.drupal.org/files/projects/pantheon_advanced_page_cache-8.x-1.2.zip", + "reference": "8.x-1.2", + "shasum": "265f738df7e0d094f43b4f7a5b31ac3c5d799316" }, "require": { "drupal/core": "^8 || ^9" @@ -6802,8 +6803,8 @@ "type": "drupal-module", "extra": { "drupal": { - "version": "8.x-1.1", - "datestamp": "1589904160", + "version": "8.x-1.2", + "datestamp": "1611003910", "security-coverage": { "status": "covered", "message": "Covered by Drupal's security advisory policy" @@ -8738,18 +8739,18 @@ }, { "name": "drupal/views_bulk_operations", - "version": "3.9.0", - "version_normalized": "3.9.0.0", + "version": "3.10.0", + "version_normalized": "3.10.0.0", "source": { "type": "git", "url": "https://git.drupalcode.org/project/views_bulk_operations.git", - "reference": "8.x-3.9" + "reference": "8.x-3.10" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/views_bulk_operations-8.x-3.9.zip", - "reference": "8.x-3.9", - "shasum": "d7f6e50c31d21ff32f21e8f4aaedb52f6dee2da8" + "url": "https://ftp.drupal.org/files/projects/views_bulk_operations-8.x-3.10.zip", + "reference": "8.x-3.10", + "shasum": "e346c2a72fc9a1ae8af418e6a02076f52c0fcc7b" }, "require": { "drupal/core": "^8.8 || ^9" @@ -8763,8 +8764,8 @@ "type": "drupal-module", "extra": { "drupal": { - "version": "8.x-3.9", - "datestamp": "1597319021", + "version": "8.x-3.10", + "datestamp": "1608795018", "security-coverage": { "status": "covered", "message": "Covered by Drupal's security advisory policy" diff --git a/web/modules/dropzonejs/composer.libraries.json b/web/modules/dropzonejs/composer.libraries.json index 7f82b5e1d07fe76f04edf51669b7ad80c2092646..dc4b1cd2c281d9c8d90804fff8545c311b6a52af 100644 --- a/web/modules/dropzonejs/composer.libraries.json +++ b/web/modules/dropzonejs/composer.libraries.json @@ -4,16 +4,16 @@ "type": "package", "package": { "name": "enyo/dropzone", - "version": "5.7.1", + "version": "5.7.2", "type": "drupal-library", "dist": { - "url": "https://github.com/enyo/dropzone/archive/v5.7.1.zip", + "url": "https://github.com/enyo/dropzone/archive/v5.7.2.zip", "type": "zip" } } } }, "require": { - "enyo/dropzone": "5.7.1" + "enyo/dropzone": "5.7.2" } } diff --git a/web/modules/dropzonejs/dropzonejs.info.yml b/web/modules/dropzonejs/dropzonejs.info.yml index 25f528f95958870969901534b81b748629ccb2ba..a8205d9f4e367a0e28c7d76e64f6d368c0b77240 100644 --- a/web/modules/dropzonejs/dropzonejs.info.yml +++ b/web/modules/dropzonejs/dropzonejs.info.yml @@ -1,12 +1,12 @@ name: dropzonejs type: module -description: DropzoneJS +description: The Drupal integration for DropzoneJS. core_version_requirement: ^8.8 || ^9 package: Media dependencies: - drupal:file -# Information added by Drupal.org packaging script on 2020-09-17 -version: '8.x-2.3' +# Information added by Drupal.org packaging script on 2021-01-15 +version: '8.x-2.4' project: 'dropzonejs' -datestamp: 1600310563 +datestamp: 1610726520 diff --git a/web/modules/dropzonejs/dropzonejs.libraries.yml b/web/modules/dropzonejs/dropzonejs.libraries.yml index a73667e399a17ec92fbdff0b183c9a62605f75e5..1a4fe857b5f427477947cbaf5adc11bffcf91cd5 100644 --- a/web/modules/dropzonejs/dropzonejs.libraries.yml +++ b/web/modules/dropzonejs/dropzonejs.libraries.yml @@ -1,16 +1,16 @@ dropzonejs: title: 'Dropzonejs' website: http://www.dropzonejs.com - version: 4.0.1 + version: 5.7.2 license: name: MIT url: https://github.com/enyo/dropzone/blob/master/LICENSE gpl-compatible: true js: - /libraries/dropzone/dist/min/dropzone.min.js: {} + /libraries/dropzone/dist/min/dropzone.min.js: { minified: true } css: component: - /libraries/dropzone/dist/min/dropzone.min.css: {} + /libraries/dropzone/dist/min/dropzone.min.css: { minified: true } widget: version: VERSION css: diff --git a/web/modules/dropzonejs/js/dropzone.integration.js b/web/modules/dropzonejs/js/dropzone.integration.js index 14b1bd0ed2231b3035c20be339ccbbfe325ce4dd..b30d11e7965e8c08c48f4b1f7dd4f2e46d11b454 100644 --- a/web/modules/dropzonejs/js/dropzone.integration.js +++ b/web/modules/dropzonejs/js/dropzone.integration.js @@ -25,7 +25,24 @@ // Initiate dropzonejs. var config = { url: input.attr('data-upload-path'), - addRemoveLinks: false + addRemoveLinks: false, + dictDefaultMessage: Drupal.t('Drop files here to upload'), + dictFallbackMessage: Drupal.t('Your browser does not support drag\'n\'drop file uploads.'), + dictFallbackText: Drupal.t('Please use the fallback form below to upload your files like in the olden days.'), + dictFileTooBig: Drupal.t('File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.'), + dictInvalidFileType: Drupal.t('You can\'t upload files of this type.'), + dictResponseError: Drupal.t('Server responded with {{statusCode}} code.'), + dictCancelUpload: Drupal.t('Cancel upload'), + dictCancelUploadConfirmation: Drupal.t('Are you sure you want to cancel this upload?'), + dictRemoveFile: Drupal.t('Remove file'), + dictMaxFilesExceeded: Drupal.t('You can not upload any more files.'), + dictFileSizeUnits: { + tb: Drupal.t('TB'), + gb: Drupal.t('GB'), + mb: Drupal.t('MB'), + kb: Drupal.t('KB'), + b: Drupal.t('b') + }, }; var instanceConfig = drupalSettings.dropzonejs.instances[selector.attr('id')]; diff --git a/web/modules/dropzonejs/modules/eb_widget/dropzonejs_eb_widget.info.yml b/web/modules/dropzonejs/modules/eb_widget/dropzonejs_eb_widget.info.yml index f803a34dc837b6a60c49a51c2b6564f45cb383f7..cd039f2fd2222f5576f75c8da42032d83d4beaf5 100644 --- a/web/modules/dropzonejs/modules/eb_widget/dropzonejs_eb_widget.info.yml +++ b/web/modules/dropzonejs/modules/eb_widget/dropzonejs_eb_widget.info.yml @@ -1,6 +1,6 @@ name: DropzoneJS entity browser widget type: module -description: DropzoneJS Entity browser widget +description: 'DropzoneJS Entity browser widget.' core_version_requirement: ^8.8 || ^9 package: Media dependencies: @@ -9,7 +9,7 @@ dependencies: - entity_browser:entity_browser -# Information added by Drupal.org packaging script on 2020-09-17 -version: '8.x-2.3' +# Information added by Drupal.org packaging script on 2021-01-15 +version: '8.x-2.4' project: 'dropzonejs' -datestamp: 1600310563 +datestamp: 1610726520 diff --git a/web/modules/dropzonejs/tests/modules/dropzonejs_test/dropzonejs_test.info.yml b/web/modules/dropzonejs/tests/modules/dropzonejs_test/dropzonejs_test.info.yml index ebe917b3029bc8c804dc8d219341b8f0720179c6..7a0c3dcd426b4caa4b9954fbcfce482c576ccdbd 100644 --- a/web/modules/dropzonejs/tests/modules/dropzonejs_test/dropzonejs_test.info.yml +++ b/web/modules/dropzonejs/tests/modules/dropzonejs_test/dropzonejs_test.info.yml @@ -9,7 +9,7 @@ dependencies: - dropzonejs:dropzonejs - dropzonejs:dropzonejs_eb_widget -# Information added by Drupal.org packaging script on 2020-09-17 -version: '8.x-2.3' +# Information added by Drupal.org packaging script on 2021-01-15 +version: '8.x-2.4' project: 'dropzonejs' -datestamp: 1600310563 +datestamp: 1610726520 diff --git a/web/modules/libraries/composer.json b/web/modules/libraries/composer.json index 4af11e12e838280670e4095241afeef46d2d91ca..a1807ddcb828def716b9d521e42efa6068a01c10 100644 --- a/web/modules/libraries/composer.json +++ b/web/modules/libraries/composer.json @@ -10,5 +10,5 @@ "irc": "irc://irc.freenode.org/drupal-contribute", "source": "http://cgit.drupalcode.org/libraries" }, - "license": "GPL-2.0+" + "license": "GPL-2.0-or-later" } diff --git a/web/modules/libraries/libraries.info.yml b/web/modules/libraries/libraries.info.yml index 68ea958a3ffe6b11eabfa45db73c68f393b68355..d0d9423667ae2d95f8d09473e39447ab09f78d35 100644 --- a/web/modules/libraries/libraries.info.yml +++ b/web/modules/libraries/libraries.info.yml @@ -4,7 +4,7 @@ description: Allows version-dependent and shared usage of external libraries. core: 8.x core_version_requirement: ^8 || ^9 -# Information added by Drupal.org packaging script on 2020-12-16 -version: '8.x-3.0-alpha6' +# Information added by Drupal.org packaging script on 2021-01-04 +version: '8.x-3.0-beta1' project: 'libraries' -datestamp: 1608099126 +datestamp: 1609758296 diff --git a/web/modules/libraries/src/ExternalLibrary/Exception/InvalidLibraryDependencyException.php b/web/modules/libraries/src/ExternalLibrary/Exception/InvalidLibraryDependencyException.php index 7ab3eeb7e4ce73dd3b3bbef97f2571ab13b214e0..e307846c3ee138e019c5584db7a52525f70e2093 100644 --- a/web/modules/libraries/src/ExternalLibrary/Exception/InvalidLibraryDependencyException.php +++ b/web/modules/libraries/src/ExternalLibrary/Exception/InvalidLibraryDependencyException.php @@ -12,8 +12,10 @@ */ class InvalidLibraryDependencyException extends \UnexpectedValueException implements LibraryAccessorInterface { - use LibraryAccessorTrait; - use DependencyAccessorTrait; + use LibraryAccessorTrait, DependencyAccessorTrait { + LibraryAccessorTrait::getLibrary insteadof DependencyAccessorTrait; + DependencyAccessorTrait::getLibrary as libraryAccessor; + } /** * Constructs a library exception. diff --git a/web/modules/libraries/src/ExternalLibrary/Local/LocalLibraryTrait.php b/web/modules/libraries/src/ExternalLibrary/Local/LocalLibraryTrait.php index 3f08e4ba4c1f2d346aa6158f6594e56ea3034cba..3cb75290295e8a9e03e89374b4512d983cad7d17 100644 --- a/web/modules/libraries/src/ExternalLibrary/Local/LocalLibraryTrait.php +++ b/web/modules/libraries/src/ExternalLibrary/Local/LocalLibraryTrait.php @@ -92,8 +92,8 @@ public function setLocalPath($path) { $this->installed = TRUE; $this->localPath = (string) $path; - assert('$this->localPath !== ""'); - assert('$this->localPath[0] !== "/"'); + assert($this->localPath !== ""); + assert($this->localPath[0] !== "/"); } } diff --git a/web/modules/libraries/src/Plugin/libraries/Locator/UriLocator.php b/web/modules/libraries/src/Plugin/libraries/Locator/UriLocator.php index 348be0c247c8aec40cbba68e28c132437b9c0938..27325050212d7c39d3f2c467d6eb02e072c09650 100644 --- a/web/modules/libraries/src/Plugin/libraries/Locator/UriLocator.php +++ b/web/modules/libraries/src/Plugin/libraries/Locator/UriLocator.php @@ -73,7 +73,7 @@ public static function create(ContainerInterface $container, array $configuratio public function locate(LocalLibraryInterface $library) { /** @var \Drupal\Core\StreamWrapper\LocalStream $stream_wrapper */ $stream_wrapper = $this->streamWrapperManager->getViaUri($this->uri); - assert('$stream_wrapper instanceof \Drupal\Core\StreamWrapper\LocalStream'); + assert($stream_wrapper instanceof \Drupal\Core\StreamWrapper\LocalStream); // Calling LocalStream::getDirectoryPath() explicitly avoids the realpath() // usage in LocalStream::getLocalPath(), which breaks if Libraries API is // symbolically linked into the Drupal installation. diff --git a/web/modules/libraries/src/Plugin/libraries/Type/AssetLibraryType.php b/web/modules/libraries/src/Plugin/libraries/Type/AssetLibraryType.php index ce0b276b17eb58aa46789392ae6eb6fb92e1c866..a92f27daa09b55166d1d8d7f7fe26dc1329ec6e8 100644 --- a/web/modules/libraries/src/Plugin/libraries/Type/AssetLibraryType.php +++ b/web/modules/libraries/src/Plugin/libraries/Type/AssetLibraryType.php @@ -24,7 +24,7 @@ public function getLibraryClass() { * {@inheritdoc} */ public function getAttachableAssetLibraries(LibraryInterface $library, LibraryManagerInterface $library_manager) { - assert('$library instanceof \Drupal\libraries\ExternalLibrary\Asset\AssetLibraryInterface'); + assert($library instanceof \Drupal\libraries\ExternalLibrary\Asset\AssetLibraryInterface); /** @var \Drupal\libraries\ExternalLibrary\Asset\AssetLibraryInterface $library */ return [$library->getId() => $library->getAttachableAssetLibrary($library_manager)]; } diff --git a/web/modules/libraries/src/Plugin/libraries/Type/MultipleAssetLibraryType.php b/web/modules/libraries/src/Plugin/libraries/Type/MultipleAssetLibraryType.php index 31ec6a62c6c41aace30735496788f4f85118900d..f73887e917f22e21bbf8609b7e3f5bc1dc95b06a 100644 --- a/web/modules/libraries/src/Plugin/libraries/Type/MultipleAssetLibraryType.php +++ b/web/modules/libraries/src/Plugin/libraries/Type/MultipleAssetLibraryType.php @@ -25,7 +25,7 @@ public function getLibraryClass() { * {@inheritdoc} */ public function getAttachableAssetLibraries(LibraryInterface $external_library, LibraryManagerInterface $library_manager) { - assert('$external_library instanceof \Drupal\libraries\ExternalLibrary\Asset\MultipleAssetLibraryInterface'); + assert($external_library instanceof \Drupal\libraries\ExternalLibrary\Asset\MultipleAssetLibraryInterface); /** @var \Drupal\libraries\ExternalLibrary\Asset\MultipleAssetLibraryInterface $external_library */ $attachable_libraries = []; foreach ($external_library->getAttachableAssetLibraries($library_manager) as $component_name => $attachable_library) { diff --git a/web/modules/libraries/src/StreamWrapper/LibraryDefinitionsStream.php b/web/modules/libraries/src/StreamWrapper/LibraryDefinitionsStream.php index 7cf0764ec0c75d3cd9cc2d0384c15f395c2811cd..eff3146ae7eeaf814c6c18bdc0fd8f58ca933f12 100644 --- a/web/modules/libraries/src/StreamWrapper/LibraryDefinitionsStream.php +++ b/web/modules/libraries/src/StreamWrapper/LibraryDefinitionsStream.php @@ -3,6 +3,7 @@ namespace Drupal\libraries\StreamWrapper; use Drupal\Core\StreamWrapper\LocalStream; +use Drupal\Core\Config\ConfigFactory; /** * Provides a stream wrapper for library definitions. @@ -33,7 +34,7 @@ class LibraryDefinitionsStream extends LocalStream { use PrivateStreamTrait; /** - * The config factory + * The config factory. * * @var \Drupal\Core\Config\ConfigFactoryInterface */ @@ -44,8 +45,8 @@ class LibraryDefinitionsStream extends LocalStream { * * @todo Dependency injection. */ - public function __construct() { - $this->configFactory = \Drupal::configFactory(); + public function __construct(ConfigFactory $config_factory) { + $this->configFactory = $config_factory; } /** diff --git a/web/modules/libraries/src/Tests/LibrariesWebTest.php b/web/modules/libraries/src/Tests/LibrariesWebTest.php index 2c9254c45323010c0145c28f58785d39e4e46f81..f0a0da04f75ff6c0d6b32d43e12ef3f20ba301b7 100644 --- a/web/modules/libraries/src/Tests/LibrariesWebTest.php +++ b/web/modules/libraries/src/Tests/LibrariesWebTest.php @@ -54,7 +54,7 @@ protected function setUp() { function testLibrariesDetectDependencies() { $library = array( 'name' => 'Example', - 'dependencies' => array('example_missing'), + 'dependencies' => array('Example missing'), ); libraries_detect_dependencies($library); $this->assertEqual($library['error'], 'missing dependency', 'libraries_detect_dependencies() detects missing dependency'); diff --git a/web/modules/libraries/tests/example/example_info_file.libraries.info.yml b/web/modules/libraries/tests/example/example_info_file.libraries.info.yml index d0ffc711a33096f3b68c6c0e2de3bf1186e9be38..90d4246681245efa5a1480d2f2d6160b5d65836c 100644 --- a/web/modules/libraries/tests/example/example_info_file.libraries.info.yml +++ b/web/modules/libraries/tests/example/example_info_file.libraries.info.yml @@ -1,7 +1,7 @@ # This is an example info file of a library used for testing purposes. name: Example info file -# Information added by Drupal.org packaging script on 2020-12-16 -version: '8.x-3.0-alpha6' +# Information added by Drupal.org packaging script on 2021-01-04 +version: '8.x-3.0-beta1' project: 'libraries' -datestamp: 1608099126 +datestamp: 1609758296 diff --git a/web/modules/libraries/tests/modules/libraries_test/libraries_test.info.yml b/web/modules/libraries/tests/modules/libraries_test/libraries_test.info.yml index f2bb897e8a092fcafba1d595314f8f8a9a62c0c5..6a9118db1042dfa891a3d1b8eae8af80cbd762ca 100644 --- a/web/modules/libraries/tests/modules/libraries_test/libraries_test.info.yml +++ b/web/modules/libraries/tests/modules/libraries_test/libraries_test.info.yml @@ -3,13 +3,13 @@ type: module description: Tests library detection and loading. core: 8.x dependencies: - - libraries + - libraries:libraries hidden: TRUE library_dependencies: - test_asset_library - test_asset_multiple_library -# Information added by Drupal.org packaging script on 2020-12-16 -version: '8.x-3.0-alpha6' +# Information added by Drupal.org packaging script on 2021-01-04 +version: '8.x-3.0-beta1' project: 'libraries' -datestamp: 1608099126 +datestamp: 1609758296 diff --git a/web/modules/libraries/tests/src/Functional/ExternalLibrary/Definition/DefinitionDiscoveryFactoryTest.php b/web/modules/libraries/tests/src/Functional/ExternalLibrary/Definition/DefinitionDiscoveryFactoryTest.php index 14bf74e4f6ecfbbd5e1a7a693c4a88349af084be..0b049bfdab1a0c1c61cfa3f5469dfba05469012d 100644 --- a/web/modules/libraries/tests/src/Functional/ExternalLibrary/Definition/DefinitionDiscoveryFactoryTest.php +++ b/web/modules/libraries/tests/src/Functional/ExternalLibrary/Definition/DefinitionDiscoveryFactoryTest.php @@ -108,11 +108,11 @@ public function testDiscovery() { /** @var \Drupal\libraries\ExternalLibrary\Definition\DefinitionDiscoveryInterface $discovery */ $discovery = $this->container->get($discovery_service_id); $definition_file = "$definitions_directory/$library_id.json"; - $this->assertFalse(file_exists($definition_file)); + $this->assertFileNotExists($definition_file); $this->assertTrue($discovery->hasDefinition($library_id)); - $this->assertFalse(file_exists($definition_file)); + $this->assertFileNotExists($definition_file); $this->assertEquals($discovery->getDefinition($library_id), $expected_definition); - $this->assertTrue(file_exists($definition_file)); + $this->assertFileExists($definition_file); } } diff --git a/web/modules/media_entity_twitter/media_entity_twitter.info.yml b/web/modules/media_entity_twitter/media_entity_twitter.info.yml index 0c97051226a80c0915b0e89329ddaabbba4d34a7..03aa469d411658a8a1911666a43a8c437fde586f 100644 --- a/web/modules/media_entity_twitter/media_entity_twitter.info.yml +++ b/web/modules/media_entity_twitter/media_entity_twitter.info.yml @@ -6,7 +6,7 @@ core_version_requirement: ^8.8 || ^9 dependencies: - drupal:media -# Information added by Drupal.org packaging script on 2020-03-31 -version: '8.x-2.4' +# Information added by Drupal.org packaging script on 2021-01-11 +version: '8.x-2.6' project: 'media_entity_twitter' -datestamp: 1585646749 +datestamp: 1610375567 diff --git a/web/modules/media_entity_twitter/src/Plugin/Validation/Constraint/TweetEmbedCodeConstraint.php b/web/modules/media_entity_twitter/src/Plugin/Validation/Constraint/TweetEmbedCodeConstraint.php deleted file mode 100644 index 28aca9571f63f2a894a0035fbc440952fe3a371e..0000000000000000000000000000000000000000 --- a/web/modules/media_entity_twitter/src/Plugin/Validation/Constraint/TweetEmbedCodeConstraint.php +++ /dev/null @@ -1,25 +0,0 @@ -<?php - -namespace Drupal\media_entity_twitter\Plugin\Validation\Constraint; - -use Symfony\Component\Validator\Constraint; - -/** - * Checks if a value is a valid Tweet embed code/URL. - * - * @Constraint( - * id = "TweetEmbedCode", - * label = @Translation("Tweet embed code", context = "Validation"), - * type = { "link", "string", "string_long" } - * ) - */ -class TweetEmbedCodeConstraint extends Constraint { - - /** - * The default violation message. - * - * @var string - */ - public $message = 'Not valid Tweet URL/embed code.'; - -} diff --git a/web/modules/media_entity_twitter/src/Plugin/Validation/Constraint/TweetEmbedCodeConstraintValidator.php b/web/modules/media_entity_twitter/src/Plugin/Validation/Constraint/TweetEmbedCodeConstraintValidator.php deleted file mode 100644 index 699a819416639accfb0f82221d05e101bb512620..0000000000000000000000000000000000000000 --- a/web/modules/media_entity_twitter/src/Plugin/Validation/Constraint/TweetEmbedCodeConstraintValidator.php +++ /dev/null @@ -1,54 +0,0 @@ -<?php - -namespace Drupal\media_entity_twitter\Plugin\Validation\Constraint; - -use Drupal\media_entity_twitter\Plugin\media\Source\Twitter; -use Drupal\Core\Field\FieldItemList; -use Drupal\Core\Field\FieldItemInterface; -use Symfony\Component\Validator\Constraint; -use Symfony\Component\Validator\ConstraintValidator; - -/** - * Validates the TweetEmbedCode constraint. - */ -class TweetEmbedCodeConstraintValidator extends ConstraintValidator { - - /** - * {@inheritdoc} - */ - public function validate($value, Constraint $constraint) { - $data = ''; - if (is_string($value)) { - $data = $value; - } - elseif ($value instanceof FieldItemList) { - $fieldtype = $value->getFieldDefinition()->getType(); - $field_value = $value->getValue(); - if ($fieldtype == 'link') { - $data = empty($field_value[0]['uri']) ? "" : $field_value[0]['uri']; - } - else { - $data = empty($field_value[0]['value']) ? "" : $field_value[0]['value']; - } - } - elseif ($value instanceof FieldItemInterface) { - $class = get_class($value); - $property = $class::mainPropertyName(); - if ($property) { - $data = $value->{$property}; - } - } - if ($data) { - $matches = []; - foreach (Twitter::$validationRegexp as $pattern => $key) { - if (preg_match($pattern, $data, $item_matches)) { - $matches[] = $item_matches; - } - } - if (empty($matches)) { - $this->context->addViolation($constraint->message); - } - } - } - -} diff --git a/web/modules/media_entity_twitter/src/Plugin/Validation/Constraint/TweetVisibleConstraint.php b/web/modules/media_entity_twitter/src/Plugin/Validation/Constraint/TweetVisibleConstraint.php deleted file mode 100644 index 2a16846a9d461d013d885d228336fbbce7b161eb..0000000000000000000000000000000000000000 --- a/web/modules/media_entity_twitter/src/Plugin/Validation/Constraint/TweetVisibleConstraint.php +++ /dev/null @@ -1,25 +0,0 @@ -<?php - -namespace Drupal\media_entity_twitter\Plugin\Validation\Constraint; - -use Symfony\Component\Validator\Constraint; - -/** - * Checks if a Tweet is publicly visible. - * - * @Constraint( - * id = "TweetVisible", - * label = @Translation("Tweet publicly visible", context = "Validation"), - * type = { "entity", "entity_reference", "string", "string_long" } - * ) - */ -class TweetVisibleConstraint extends Constraint { - - /** - * The default violation message. - * - * @var string - */ - public $message = 'Referenced tweet is not publicly visible.'; - -} diff --git a/web/modules/media_entity_twitter/src/Plugin/Validation/Constraint/TweetVisibleConstraintValidator.php b/web/modules/media_entity_twitter/src/Plugin/Validation/Constraint/TweetVisibleConstraintValidator.php deleted file mode 100644 index 81967dab07e16aee442b0743cb16c62a3d90904d..0000000000000000000000000000000000000000 --- a/web/modules/media_entity_twitter/src/Plugin/Validation/Constraint/TweetVisibleConstraintValidator.php +++ /dev/null @@ -1,97 +0,0 @@ -<?php - -namespace Drupal\media_entity_twitter\Plugin\Validation\Constraint; - -use Drupal\Core\DependencyInjection\ContainerInjectionInterface; -use Drupal\Core\Field\FieldItemListInterface; -use Drupal\media_entity_twitter\Plugin\media\Source\Twitter; -use Drupal\Core\Field\FieldItemInterface; -use GuzzleHttp\Client; -use GuzzleHttp\Exception\ClientException; -use Symfony\Component\DependencyInjection\ContainerInterface; -use Symfony\Component\Validator\Constraint; -use Symfony\Component\Validator\ConstraintValidator; - -/** - * Validates the TweetVisible constraint. - */ -class TweetVisibleConstraintValidator extends ConstraintValidator implements ContainerInjectionInterface { - - /** - * The HTTP client to fetch the feed data with. - * - * @var \GuzzleHttp\Client - */ - protected $httpClient; - - /** - * Constructs a new TweetVisibleConstraintValidator. - * - * @param \GuzzleHttp\Client $http_client - * The http client service. - */ - public function __construct(Client $http_client) { - $this->httpClient = $http_client; - } - - /** - * {@inheritdoc} - */ - public static function create(ContainerInterface $container) { - return new static($container->get('http_client')); - } - - /** - * {@inheritdoc} - */ - public function validate($value, Constraint $constraint) { - $data = ''; - if (is_string($value)) { - $data = $value; - } - elseif ($value instanceof FieldItemListInterface) { - $fieldtype = $value->getFieldDefinition()->getType(); - $field_value = $value->getValue(); - if ($fieldtype == 'link') { - $data = empty($field_value[0]['uri']) ? "" : $field_value[0]['uri']; - } - else { - $data = empty($field_value[0]['value']) ? "" : $field_value[0]['value']; - } - } - elseif ($value instanceof FieldItemInterface) { - $class = get_class($value); - $property = $class::mainPropertyName(); - if ($property) { - $data = $value->{$property}; - } - } - foreach (Twitter::$validationRegexp as $pattern => $key) { - if (preg_match($pattern, $data, $item_matches)) { - $matches[] = $item_matches; - } - } - - if (empty($matches[0][0])) { - // If there are no matches the URL is not correct, so stop validation. - return; - } - - // Fetch content from the given url. - try { - $response = $this->httpClient->get($matches[0][0], ['allow_redirects' => FALSE]); - } - catch (ClientException $e) { - $this->context->addViolation($constraint->message); - return; - } - - if ($response->getStatusCode() == 302 && ($location = $response->getHeader('location'))) { - $effective_url_parts = parse_url($location[0]); - if (!empty($effective_url_parts) && isset($effective_url_parts['query']) && $effective_url_parts['query'] == 'protected_redirect=true') { - $this->context->addViolation($constraint->message); - } - } - } - -} diff --git a/web/modules/media_entity_twitter/src/Plugin/media/Source/Twitter.php b/web/modules/media_entity_twitter/src/Plugin/media/Source/Twitter.php index 72018dfee2a72d58c9117bedeb96ce3b35bbb6b6..22abcfeac576bbcb96582ec7aac2cc10777af7d0 100644 --- a/web/modules/media_entity_twitter/src/Plugin/media/Source/Twitter.php +++ b/web/modules/media_entity_twitter/src/Plugin/media/Source/Twitter.php @@ -14,6 +14,7 @@ use Drupal\media\MediaInterface; use Drupal\media\MediaSourceBase; use Drupal\media\MediaTypeInterface; +use Drupal\media\Plugin\media\Source\OEmbedInterface; use Drupal\media_entity_twitter\TweetFetcherInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Drupal\Core\Field\FieldTypePluginManagerInterface; @@ -33,7 +34,7 @@ * } * ) */ -class Twitter extends MediaSourceBase implements MediaSourceFieldConstraintsInterface { +class Twitter extends MediaSourceBase implements MediaSourceFieldConstraintsInterface, OEmbedInterface { /** * The renderer. @@ -114,6 +115,8 @@ public static function create(ContainerInterface $container, array $configuratio * The tweet fetcher. * @param \Drupal\Core\Logger\LoggerChannelInterface $logger * The logger channel. + * @param \Drupal\Core\File\FileSystemInterface $file_system + * The file system. */ public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, FieldTypePluginManagerInterface $field_type_manager, ConfigFactoryInterface $config_factory, RendererInterface $renderer, TweetFetcherInterface $tweet_fetcher, LoggerChannelInterface $logger, FileSystemInterface $file_system) { parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_type_manager, $entity_field_manager, $field_type_manager, $config_factory); @@ -210,7 +213,6 @@ public function getMetadata(MediaInterface $media, $attribute_name) { ]; $svg = $this->renderer->renderRoot($thumbnail); - return $this->fileSystem->saveData($svg, $thumbnail_uri, FileSystemInterface::EXISTS_ERROR) ?: parent::getMetadata($media, $attribute_name); } @@ -379,8 +381,7 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta */ public function getSourceFieldConstraints() { return [ - 'TweetEmbedCode' => [], - 'TweetVisible' => [], + 'oembed_resource' => [], ]; } @@ -448,7 +449,7 @@ protected function matchRegexp(MediaInterface $media) { $matches = []; $source_field = $this->getSourceFieldDefinition($media->bundle->entity)->getName(); - if ($media->hasField($source_field)) { + if ($media->hasField($source_field) && !$media->get($source_field)->isEmpty()) { $property_name = $media->get($source_field)->first()->mainPropertyName(); foreach (static::$validationRegexp as $pattern => $key) { if (preg_match($pattern, $media->get($source_field)->{$property_name}, $matches)) { @@ -480,4 +481,11 @@ protected function fetchTweet($id) { return $this->tweetFetcher->fetchTweet($id); } + /** + * {@inheritdoc} + */ + public function getProviders() { + return ['Twitter']; + } + } diff --git a/web/modules/media_entity_twitter/tests/src/Functional/TweetEmbedFormatterTest.php b/web/modules/media_entity_twitter/tests/src/Functional/TweetEmbedFormatterTest.php index 2df19dca8c51235ca5050b61838105d4c0496f4d..e928db8dcd55591de5d214e7c47b3655cb7efadb 100644 --- a/web/modules/media_entity_twitter/tests/src/Functional/TweetEmbedFormatterTest.php +++ b/web/modules/media_entity_twitter/tests/src/Functional/TweetEmbedFormatterTest.php @@ -67,14 +67,14 @@ public function testManageEmbedFormatter() { ]; $this->drupalPostForm(NULL, $edit_conf, t('Save and continue')); $this->assertSession() - ->responseContains('These settings apply to the <em class="placeholder">' . $edit_conf['label'] . '</em> field everywhere it is used.'); + ->responseContains('These settings apply to the <em class="placeholder">' . $edit_conf['label'] . '</em> field everywhere it is used.'); $edit = [ 'cardinality' => 'number', 'cardinality_number' => '1', ]; $this->drupalPostForm(NULL, $edit, t('Save field settings')); $this->assertSession() - ->responseContains('Updated field <em class="placeholder">' . $edit_conf['label'] . '</em> field settings.'); + ->responseContains('Updated field <em class="placeholder">' . $edit_conf['label'] . '</em> field settings.'); // Set the new string_long field type as required. $edit = [ @@ -82,7 +82,7 @@ public function testManageEmbedFormatter() { ]; $this->drupalPostForm(NULL, $edit, t('Save settings')); $this->assertSession() - ->responseContains('Saved <em class="placeholder">' . $edit_conf['label'] . '</em> configuration.'); + ->responseContains('Saved <em class="placeholder">' . $edit_conf['label'] . '</em> configuration.'); // Assert that the new field types configurations have been successfully // saved. @@ -139,7 +139,7 @@ public function testManageEmbedFormatter() { // Assert that the link url formatter exists on this page. $this->assertSession()->pageTextContains('Tweet URL'); $this->assertSession() - ->responseContains('<a href="https://twitter.com/RamzyStinson/statuses/670650348319576064">', 'Link in embedded Tweet found.'); + ->responseContains('<a href="https://twitter.com/RamzyStinson/statuses/670650348319576064">', 'Link in embedded Tweet found.'); // Assert that the string_long code formatter exists on this page. $this->assertSession()->pageTextContains('Embed code'); diff --git a/web/modules/media_entity_twitter/tests/src/Kernel/ThumbnailTest.php b/web/modules/media_entity_twitter/tests/src/Kernel/ThumbnailTest.php index 4c43d24c816980b5e9db62234a46c6837ff1075d..1c0d4b66831f17782f7962aece3b3a99cd2672df 100644 --- a/web/modules/media_entity_twitter/tests/src/Kernel/ThumbnailTest.php +++ b/web/modules/media_entity_twitter/tests/src/Kernel/ThumbnailTest.php @@ -107,7 +107,7 @@ protected function setUp() { ->get('media_entity_twitter.settings') ->get('local_images'); - \Drupal::service('file_system')->prepareDirectory($dir, FileSystemInterface::CREATE_DIRECTORY| FileSystemInterface::MODIFY_PERMISSIONS); + \Drupal::service('file_system')->prepareDirectory($dir, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS); } /** diff --git a/web/modules/media_entity_twitter/tests/src/Unit/ConstraintsTest.php b/web/modules/media_entity_twitter/tests/src/Unit/ConstraintsTest.php deleted file mode 100644 index 69e4a1bb0f641ec187b72a584615b4c626625720..0000000000000000000000000000000000000000 --- a/web/modules/media_entity_twitter/tests/src/Unit/ConstraintsTest.php +++ /dev/null @@ -1,198 +0,0 @@ -<?php - -namespace Drupal\Tests\media_entity_twitter\Unit; - -use Drupal\Core\Field\Plugin\Field\FieldType\StringLongItem; -use Drupal\Core\TypedData\ComplexDataDefinitionInterface; -use Drupal\media_entity_twitter\Plugin\Validation\Constraint\TweetEmbedCodeConstraint; -use Drupal\media_entity_twitter\Plugin\Validation\Constraint\TweetEmbedCodeConstraintValidator; -use Drupal\media_entity_twitter\Plugin\Validation\Constraint\TweetVisibleConstraint; -use Drupal\media_entity_twitter\Plugin\Validation\Constraint\TweetVisibleConstraintValidator; -use Drupal\Tests\UnitTestCase; - -/** - * Tests media_entity_twitter constraints. - * - * @group media_entity - */ -class ConstraintsTest extends UnitTestCase { - - /** - * Creates a string_long FieldItemInterface wrapper around a value. - * - * @param string $value - * The wrapped value. - * - * @return \Drupal\Core\Field\FieldItemInterface - * Mocked string field item. - */ - protected function getMockFieldItem($value) { - $definition = $this->prophesize(ComplexDataDefinitionInterface::class); - $definition->getPropertyDefinitions()->willReturn([]); - - $item = new StringLongItem($definition->reveal()); - $item->set('value', $value); - - return $item; - } - - /** - * Tests TweetEmbedCode constraint. - * - * @covers \Drupal\media_entity_twitter\Plugin\Validation\Constraint\TweetEmbedCodeConstraintValidator - * @covers \Drupal\media_entity_twitter\Plugin\Validation\Constraint\TweetEmbedCodeConstraint - * - * @dataProvider embedCodeProvider - */ - public function testTweetEmbedCodeConstraint($embed_code, $expected_violation_count) { - // Check message in constraint. - $constraint = new TweetEmbedCodeConstraint(); - $this->assertEquals('Not valid Tweet URL/embed code.', $constraint->message, 'Correct constraint message found.'); - - $execution_context = $this->getMockBuilder('\Drupal\Core\TypedData\Validation\ExecutionContext') - ->disableOriginalConstructor() - ->getMock(); - - if ($expected_violation_count) { - $execution_context->expects($this->exactly($expected_violation_count)) - ->method('addViolation') - ->with($constraint->message); - } - else { - $execution_context->expects($this->exactly($expected_violation_count)) - ->method('addViolation'); - } - - $validator = new TweetEmbedCodeConstraintValidator(); - $validator->initialize($execution_context); - - $validator->validate($this->getMockFieldItem($embed_code), $constraint); - } - - /** - * Provides test data for testTweetEmbedCodeConstraint(). - */ - public function embedCodeProvider() { - return [ - 'valid tweet URL' => ['https://twitter.com/drupal8changes/status/649167396230578176', 0], - 'valid tweet embed code' => ['<blockquote class="twitter-tweet" lang="en"><p lang="en" dir="ltr">EntityChangedInterface now also defines the function setChangedTime <a href="http://t.co/1Q58UcR8OY">http://t.co/1Q58UcR8OY</a></p>— Drupal 8 Changes (@drupal8changes) <a href="https://twitter.com/drupal8changes/status/649167396230578176">September 30, 2015</a></blockquote><script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>', 0], - 'invalid URL' => ['https://drupal.org/project/media_entity_twitter', 1], - 'invalid text' => ['I want my Tweet!', 1], - 'invalid tweet URL' => ['https://twitter.com/drupal8changes/statustypo/649167396230578176', 1], - 'invalid tweet ID' => ['https://twitter.com/drupal8changes/status/aa64916739bb6230578176', 1], - ]; - } - - /** - * Tests TweetVisible constraint. - * - * @covers \Drupal\media_entity_twitter\Plugin\Validation\Constraint\TweetVisibleConstraintValidator - * @covers \Drupal\media_entity_twitter\Plugin\Validation\Constraint\TweetVisibleConstraint - * - * @dataProvider visibleProvider - */ - public function testTweetVisibleConstraint($embed_code, $mocked_response, $violations) { - // Check message in constraint. - $constraint = new TweetVisibleConstraint(); - $this->assertEquals('Referenced tweet is not publicly visible.', $constraint->message, 'Correct constraint message found.'); - - $http_client = $this->createMock('\GuzzleHttp\Client'); - $http_client->expects($this->once()) - ->method('__call') - ->with('get', [$embed_code, ['allow_redirects' => FALSE]]) - ->willReturn($mocked_response); - - // Make sure no violations are raised for visible tweet. - $execution_context = $this->getMockBuilder('\Drupal\Core\TypedData\Validation\ExecutionContext') - ->disableOriginalConstructor() - ->getMock(); - - if ($violations) { - $execution_context->expects($this->once()) - ->method('addViolation') - ->with($constraint->message); - } - else { - $execution_context->expects($this->exactly($violations)) - ->method('addViolation'); - } - - $validator = new TweetVisibleConstraintValidator($http_client); - $validator->initialize($execution_context); - - $validator->validate($this->getMockFieldItem($embed_code), $constraint); - } - - /** - * Provides test data for testTweetVisibleConstraint(). - */ - public function visibleProvider() { - $visible_response = $this->createMock('\GuzzleHttp\Psr7\Response'); - $visible_response->expects($this->any()) - ->method('getStatusCode') - ->will($this->returnValue(200)); - - $invisible_response = $this->createMock('\GuzzleHttp\Psr7\Response'); - $invisible_response->expects($this->once()) - ->method('getStatusCode') - ->will($this->returnValue(302)); - $invisible_response->expects($this->once()) - ->method('getHeader') - ->with('location') - ->will($this->returnValue(['https://twitter.com/drupal8changes?protected_redirect=true'])); - - return [ - 'valid URL' => [ - 'https://twitter.com/drupal8changes/status/649167396230578176', - $visible_response, - 0, - ], - 'invalid URL' => [ - 'https://twitter.com/drupal8changes/status/649637310024273920', - $invisible_response, - 1, - ], - ]; - } - - /** - * Tests whether the TweetVisible constraint is robust against bad URLs. - * - * @covers \Drupal\media_entity_twitter\Plugin\Validation\Constraint\TweetVisibleConstraintValidator - * @covers \Drupal\media_entity_twitter\Plugin\Validation\Constraint\TweetVisibleConstraint - * - * @dataProvider badUrlsProvider - */ - public function testBadUrlsOnVisibleConstraint($embed_code) { - - $http_client = $this->createMock('\GuzzleHttp\Client'); - $http_client->expects($this->never()) - ->method('__call') - ->with('get', [$embed_code, ['allow_redirects' => FALSE]]); - - $execution_context = $this->getMockBuilder('\Drupal\Core\TypedData\Validation\ExecutionContext') - ->disableOriginalConstructor() - ->getMock(); - - $validator = new TweetVisibleConstraintValidator($http_client); - $validator->initialize($execution_context); - - $constraint = new TweetVisibleConstraint(); - $validator->validate($this->getMockFieldItem($embed_code), $constraint); - } - - /** - * Provides test data for testBadUrlsOnVisibleConstraint(). - */ - public function badUrlsProvider() { - - return [ - ['https://google.com'], - ['https://twitter.com/drupal/ssstatus/725771037837762561'], - ['https://twitter.com/drupal/status'], - ['https://twitter.com/drupal/status/foo'], - ]; - - } - -} diff --git a/web/modules/pantheon_advanced_page_cache/.circleci/config.yml b/web/modules/pantheon_advanced_page_cache/.circleci/config.yml index 6c7397c29dc8c236f75ec89c06a6a5fa16671e3c..f07920472edeca64a79537a68e7057221d01fcfa 100644 --- a/web/modules/pantheon_advanced_page_cache/.circleci/config.yml +++ b/web/modules/pantheon_advanced_page_cache/.circleci/config.yml @@ -1,80 +1,72 @@ version: 2 # https://circleci.com/docs/configuration#machine jobs: - # @todo, separate build and test phases. build: docker: - # @todo, update container - - image: quay.io/pantheon-public/build-tools-ci:1.x - working_directory: ~/pantheon_advanced_page_cache + - image: quay.io/pantheon-public/build-tools-ci:6.x environment: - BASH_ENV: ~/.bashrc - TZ: "/usr/share/zoneinfo/America/Los_Angeles" TERMINUS_SITE: d9-papc2 steps: + - run: + name: login-pantheon + command: terminus auth:login -n --machine-token="$TERMINUS_TOKEN" + # Start making a multidev right away in the background so that + # this slow step is done as soon as possible. + - run: + name: make-multidev + command: | + terminus env:create $TERMINUS_SITE.dev ${CIRCLE_BUILD_NUM} || echo "mystery errors were being thrown by env:create so I am adding this OR (https://circleci.com/gh/pantheon-systems/pantheon_advanced_page_cache/610)" + touch multidev-made.txt + background: true - checkout - - restore_cache: - key: dependency-cache-{{ checksum "composer.lock" }} - run: name: Composer install command: | composer install - drush help - - save_cache: - key: dependency-cache-{{ checksum "composer.lock" }} - paths: - - ~/.composer/cache + - run: + name: Git Config + command: | + git config --global user.email "$GitEmail" + git config --global user.name "Circle CI" + - run: + # this configuration prevents a prompt from stopping git pushes. + name: ssh config + command: | + touch $HOME/.ssh/config + echo "StrictHostKeyChecking no" >> "$HOME/.ssh/config" - run: name: PHP Code Sniff command: composer codesniff - run: name: Unit Tests for Behat helper command: composer phpunit +# - run: +# # @todo, update core update mechanism for D9 +# name: apply upstream updates in dev +# command: terminus connection:set $TERMINUS_SITE.dev git && terminus upstream:updates:apply $TERMINUS_SITE && terminus connection:set $TERMINUS_SITE.dev sftp + - run: - name: login-pantheon - command: terminus auth:login -n --machine-token="$TERMINUS_TOKEN" - - run: - name: delete old sites - command: terminus env:list --field=id $TERMINUS_SITE | grep -v '[a-z]' | grep -Eo '[0-9]{1,9}' | sort --numeric-sort --reverse | sed 1,7d | xargs -n1 -I ENV terminus env:delete --yes $TERMINUS_SITE.ENV + name: Add modules to site + command: ./.circleci/scripts/setup-drupal-repo.sh + - run: - name: ssh + name: Wait for multidev creation to be completed before doing site install. command: | - touch $HOME/.ssh/config - echo "StrictHostKeyChecking no" >> "$HOME/.ssh/config" - - run: - # @todo, update core update mechanism for D9 - name: apply upstream updates in dev - command: terminus connection:set $TERMINUS_SITE.dev git && terminus upstream:updates:apply $TERMINUS_SITE && terminus connection:set $TERMINUS_SITE.dev sftp - - run: - name: make-multidev - command: terminus env:create $TERMINUS_SITE.dev ${CIRCLE_BUILD_NUM} || echo "mystery errors were being thrown by env:create so I am adding this OR (https://circleci.com/gh/pantheon-systems/pantheon_advanced_page_cache/610)" + while [ ! -f multidev-made.txt ] + do + sleep 2 + done + exit 0 + - run: name: site install command: | terminus connection:set ${TERMINUS_SITE}.${CIRCLE_BUILD_NUM} sftp - terminus drush ${TERMINUS_SITE}.${CIRCLE_BUILD_NUM} -- site-install -y + terminus drush ${TERMINUS_SITE}.${CIRCLE_BUILD_NUM} -- site-install -y --quiet terminus drush ${TERMINUS_SITE}.${CIRCLE_BUILD_NUM} -- cset system.performance cache.page.max_age 600 -y - run: - name: Permissions - command: | - # composer will write to the default directory - $(terminus connection:info ${TERMINUS_SITE}.${CIRCLE_BUILD_NUM} --field=sftp_command) <<EOF - chmod 755 code/web/sites/default - exit - EOF - - - run: - name: Composer require papc - command: | - terminus composer ${TERMINUS_SITE}.${CIRCLE_BUILD_NUM} -- config repositories.papc vcs git@github.com:pantheon-systems/pantheon_advanced_page_cache.git - terminus composer ${TERMINUS_SITE}.${CIRCLE_BUILD_NUM} -- require drupal/pantheon_advanced_page_cache:dev-${CIRCLE_BRANCH}#${CIRCLE_SHA1} - - run: - name: composer require drupal/views_custom_cache_tag - command: | - terminus composer ${TERMINUS_SITE}.${CIRCLE_BUILD_NUM} -- require drupal/views_custom_cache_tag - - run: - name: en -y views_custom_cache_tag_demo pantheon_advanced_page_cache + name: Enable modules command: | terminus drush ${TERMINUS_SITE}.${CIRCLE_BUILD_NUM} -- en -y views_custom_cache_tag_demo pantheon_advanced_page_cache - run: diff --git a/web/modules/pantheon_advanced_page_cache/.circleci/scripts/setup-drupal-repo.sh b/web/modules/pantheon_advanced_page_cache/.circleci/scripts/setup-drupal-repo.sh new file mode 100755 index 0000000000000000000000000000000000000000..90c19b121f1115cbbf45a1ee231da0571a61991c --- /dev/null +++ b/web/modules/pantheon_advanced_page_cache/.circleci/scripts/setup-drupal-repo.sh @@ -0,0 +1,20 @@ +#!/bin/bash +set -e +export TERMINUS_ENV=$CIRCLE_BUILD_NUM + +# Bring the code down to Circle so that modules can be added via composer. +git clone $(terminus connection:info ${TERMINUS_SITE}.dev --field=git_url) --branch $TERMINUS_ENV drupal-site +cd drupal-site + + +composer -- config repositories.papc vcs git@github.com:pantheon-systems/pantheon_advanced_page_cache.git +# Composer require the given commit of this module +composer -- require drupal/views_custom_cache_tag "drupal/pantheon_advanced_page_cache:dev-${CIRCLE_BRANCH}#${CIRCLE_SHA1}" + +# Don't commit a submodule +rm -rf web/modules/contrib/pantheon_advanced_page_cache/.git/ + +# Make a git commit +git add . +git commit -m 'Result of build step' +git push --set-upstream origin $TERMINUS_ENV diff --git a/web/modules/pantheon_advanced_page_cache/README.md b/web/modules/pantheon_advanced_page_cache/README.md index c2df80fb940f8dcac12a49d2f902393cafdb4bb3..1ce74e3a31b6e27428da433fa2af39bf719bd5a2 100644 --- a/web/modules/pantheon_advanced_page_cache/README.md +++ b/web/modules/pantheon_advanced_page_cache/README.md @@ -22,6 +22,16 @@ A direct way of inspecting headers is with `curl -I`. This command will make a r `curl -IH "Pantheon-Debug:1" https://dev-cache-tags-demo.pantheonsite.io/ | grep -i Surrogate-Key-Raw` +## Changing Listing Tags + +Prior to the 1.2 release, this module would change the cache tags used on default listings. +This changing of was done to make cache hits more likely but resulted in [confusing cache clearing behavior](https://www.drupal.org/project/pantheon_advanced_page_cache/issues/2944229). +Sites that installed this module prior to 1.2 should uninstall and reinstall or run this command to update their settings. + +``` +terminus drush [MACHINE-NAME-OF-SITE].[ENV-NAME] -- config:set pantheon_advanced_page_cache.settings --input-format=yaml "override_list_tags" "false" +``` + ## Limit on header size Pantheon's nginx configuration limits total header size to 32k. diff --git a/web/modules/pantheon_advanced_page_cache/config/install/pantheon_advanced_page_cache.settings.yml b/web/modules/pantheon_advanced_page_cache/config/install/pantheon_advanced_page_cache.settings.yml new file mode 100644 index 0000000000000000000000000000000000000000..68e445b930b12c56166b299b974fa192c73dc06d --- /dev/null +++ b/web/modules/pantheon_advanced_page_cache/config/install/pantheon_advanced_page_cache.settings.yml @@ -0,0 +1 @@ +override_list_tags: false \ No newline at end of file diff --git a/web/modules/pantheon_advanced_page_cache/pantheon_advanced_page_cache.info.yml b/web/modules/pantheon_advanced_page_cache/pantheon_advanced_page_cache.info.yml index e8ad3870f2a5ffb6d34dddc934a0fe394bf6faf7..d276de1fd4fe86046011182e13bc7cd8b3924330 100644 --- a/web/modules/pantheon_advanced_page_cache/pantheon_advanced_page_cache.info.yml +++ b/web/modules/pantheon_advanced_page_cache/pantheon_advanced_page_cache.info.yml @@ -4,7 +4,7 @@ package: Performance and scalability type: module core_version_requirement: ^8 || ^9 -# Information added by Drupal.org packaging script on 2020-05-19 -version: '8.x-1.1' +# Information added by Drupal.org packaging script on 2021-01-18 +version: '8.x-1.2' project: 'pantheon_advanced_page_cache' -datestamp: 1589904163 +datestamp: 1611003913 diff --git a/web/modules/pantheon_advanced_page_cache/pantheon_advanced_page_cache.install b/web/modules/pantheon_advanced_page_cache/pantheon_advanced_page_cache.install new file mode 100644 index 0000000000000000000000000000000000000000..eb7f642d692930808fab30e1b2fb219bb51c1e81 --- /dev/null +++ b/web/modules/pantheon_advanced_page_cache/pantheon_advanced_page_cache.install @@ -0,0 +1,13 @@ +<?php + +/** + * @file + * Update functions for the Pantheon Advanced Page Cache module. + */ + +/** + * Set override_list_tags to TRUE for backwards compatibility. We recommend manually changing to FALSE for more consistent clearing. See README + */ +function pantheon_advanced_page_cache_update_8001() { + \Drupal::configFactory()->getEditable('pantheon_advanced_page_cache.settings')->set('override_list_tags', TRUE)->save(); +} diff --git a/web/modules/pantheon_advanced_page_cache/pantheon_advanced_page_cache.services.yml b/web/modules/pantheon_advanced_page_cache/pantheon_advanced_page_cache.services.yml index 6b0326c92438e22c15ea8422800aa2d3b4ea4c38..266c2398dd7956335888e638626d018b6a4eb357 100644 --- a/web/modules/pantheon_advanced_page_cache/pantheon_advanced_page_cache.services.yml +++ b/web/modules/pantheon_advanced_page_cache/pantheon_advanced_page_cache.services.yml @@ -8,6 +8,6 @@ services: - { name: cache_tags_invalidator } pantheon_advanced_page_cache.cacheable_response_subscriber: class: Drupal\pantheon_advanced_page_cache\EventSubscriber\CacheableResponseSubscriber - arguments: ['@logger.channel.pantheon_advanced_page_cache'] + arguments: ['@logger.channel.pantheon_advanced_page_cache', '@config.factory'] tags: - { name: event_subscriber } diff --git a/web/modules/pantheon_advanced_page_cache/src/EventSubscriber/CacheableResponseSubscriber.php b/web/modules/pantheon_advanced_page_cache/src/EventSubscriber/CacheableResponseSubscriber.php index 905b5356ce962651602aaca05db64c4572e0b88e..b9a72a9bc6031cc43e3569880bd24803f5d3f581 100644 --- a/web/modules/pantheon_advanced_page_cache/src/EventSubscriber/CacheableResponseSubscriber.php +++ b/web/modules/pantheon_advanced_page_cache/src/EventSubscriber/CacheableResponseSubscriber.php @@ -8,6 +8,7 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Psr\Log\LoggerInterface; use Drupal\Core\Logger\RfcLogLevel; +use Drupal\Core\Config\ConfigFactoryInterface; /** * Adds Surrogate-Key header to cacheable master responses. @@ -21,14 +22,44 @@ class CacheableResponseSubscriber implements EventSubscriberInterface { */ protected $logger; + /** + * Configuration Factory. + * + * @var \Drupal\Core\Config\ConfigFactoryInterface + */ + protected $configFactory; + /** * Constructs a new DefaultExceptionHtmlSubscriber. * * @param \Psr\Log\LoggerInterface $logger * The logger service. + * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory + * Configuration for this module. */ - public function __construct(LoggerInterface $logger) { + public function __construct(LoggerInterface $logger, ConfigFactoryInterface $config_factory = NULL) { + if (!$config_factory instanceof ConfigFactoryInterface) { + @trigger_error('Not passing the config factory service as the second parameter to ' . __METHOD__ . ' is deprecated in pantheon_advanced_page_cache:8.x-1.2 and will throw a type error in pantheon_advanced_page_cache:8.x-2.0. Pass an instance of \\Drupal\\Core\\Config\\ConfigFactoryInterface. See https://www.drupal.org/node/2944229', E_USER_DEPRECATED); + $config_factory = \Drupal::service('config.factory'); + } $this->logger = $logger; + $this->configFactory = $config_factory; + } + + /** + * Returns whether entity_list tags should be overridden. + * + * Overriding these tags was the initial behavior of the 1.0 version of this + * module. That is no longer recommended. + */ + public function getOverrideListTagsSetting() { + $config = $this->configFactory->get('pantheon_advanced_page_cache.settings'); + // Only return FALSE if this config value is really set to false. + // A null value should return TRUE for backwards compatibility. + if ($config->get('override_list_tags') === FALSE) { + return FALSE; + } + return TRUE; } /** @@ -49,8 +80,10 @@ public function onRespond(FilterResponseEvent $event) { // Rename all _list cache tags to _emit_list to avoid clearing list cache // tags by default. - foreach ($tags as $key => $tag) { - $tags[$key] = str_replace('_list', '_emit_list', $tag); + if ($this->getOverrideListTagsSetting()) { + foreach ($tags as $key => $tag) { + $tags[$key] = str_replace('_list', '_emit_list', $tag); + } } $tags_string = implode(' ', $tags); diff --git a/web/modules/pantheon_advanced_page_cache/tests/behat/features/override_list_tag.feature b/web/modules/pantheon_advanced_page_cache/tests/behat/features/override_list_tag.feature new file mode 100644 index 0000000000000000000000000000000000000000..a4ecbd1c4fe10d8f2a72a025da0651ac715f941c --- /dev/null +++ b/web/modules/pantheon_advanced_page_cache/tests/behat/features/override_list_tag.feature @@ -0,0 +1,21 @@ +Feature: Listing tags +In order to control caching of lists +As an administrator +I want to toggle the setting for overriding cache tags + + @api + Scenario: Core behavior + Given there are some "article" nodes + And "/" is caching + When a generate a "article" node + Then "/" has been purged + And "/" is caching + + @api @current + Scenario: Old override + Given there are some "article" nodes + When I run drush "config:set pantheon_advanced_page_cache.settings --input-format=yaml override_list_tags true" + And "/" is caching + When a generate a "article" node + And "/" has not been purged + diff --git a/web/modules/pantheon_advanced_page_cache/tests/modules/pantheon_advanced_page_cache_test/pantheon_advanced_page_cache_test.info.yml b/web/modules/pantheon_advanced_page_cache/tests/modules/pantheon_advanced_page_cache_test/pantheon_advanced_page_cache_test.info.yml index 89b371af46c5be905f52d26c1678f42829b06a1a..cfff2567679d75ee7b494c5e129edfb0a5e76a8c 100644 --- a/web/modules/pantheon_advanced_page_cache/tests/modules/pantheon_advanced_page_cache_test/pantheon_advanced_page_cache_test.info.yml +++ b/web/modules/pantheon_advanced_page_cache/tests/modules/pantheon_advanced_page_cache_test/pantheon_advanced_page_cache_test.info.yml @@ -4,7 +4,7 @@ package: Testing type: module core_version_requirement: ^8 || ^9 -# Information added by Drupal.org packaging script on 2020-05-19 -version: '8.x-1.1' +# Information added by Drupal.org packaging script on 2021-01-18 +version: '8.x-1.2' project: 'pantheon_advanced_page_cache' -datestamp: 1589904163 +datestamp: 1611003913 diff --git a/web/modules/views_bulk_operations/js/frontUi.js b/web/modules/views_bulk_operations/js/frontUi.js index 97bef561112012e4926c74117c4e73bd5f617ef4..82013da155ed4deef854abd508b30ae0153846f8 100644 --- a/web/modules/views_bulk_operations/js/frontUi.js +++ b/web/modules/views_bulk_operations/js/frontUi.js @@ -38,14 +38,14 @@ if (event.which === 13) { event.preventDefault(); event.stopPropagation(); - selectionObject.update(this.checked, index, $(this).val()); + selectionObject.update(!this.checked, index, $(this).val()); $(this).trigger('click'); } if (event.which === 32) { - selectionObject.update(this.checked, index, $(this).val()); + selectionObject.update(!this.checked, index, $(this).val()); } }); - $element.on('mousedown', function (event) { + $element.on('click', function (event) { // Act only on left button click. if (event.which === 1) { selectionObject.update(this.checked, index, $(this).val()); @@ -70,8 +70,8 @@ var list = {}, op = ''; if (index === 'selection_method_change') { - var op = state ? 'method_include' : 'method_exclude'; - if (!state) { + var op = state ? 'method_exclude' : 'method_include'; + if (state) { list = this.list[index]; } } @@ -82,7 +82,7 @@ else { list = this.list[index]; } - op = state ? 'remove' : 'add'; + op = state ? 'add' : 'remove'; } var $placeholder = this.$placeholder; @@ -167,6 +167,10 @@ this.checked = value; }); + // Clear the selection information if exists. + $vboForm.find('.vbo-info-list-wrapper').each(function () { + $(this).html(''); + }); }); if ($multiSelectElement.length) { diff --git a/web/modules/views_bulk_operations/modules/actions_permissions/actions_permissions.info.yml b/web/modules/views_bulk_operations/modules/actions_permissions/actions_permissions.info.yml index cbe4230c851dbbe3d0837f8658310751ef1ee623..3b5675c624840a62212724f42cff8e6be452c8b1 100644 --- a/web/modules/views_bulk_operations/modules/actions_permissions/actions_permissions.info.yml +++ b/web/modules/views_bulk_operations/modules/actions_permissions/actions_permissions.info.yml @@ -6,7 +6,7 @@ core_version_requirement: ^8 || ^9 dependencies: - drupal:views_bulk_operations -# Information added by Drupal.org packaging script on 2020-08-13 -version: '8.x-3.9' +# Information added by Drupal.org packaging script on 2020-12-24 +version: '8.x-3.10' project: 'views_bulk_operations' -datestamp: 1597319023 +datestamp: 1608795021 diff --git a/web/modules/views_bulk_operations/modules/views_bulk_operations_example/src/Plugin/Action/ViewsBulkOperationExampleAction.php b/web/modules/views_bulk_operations/modules/views_bulk_operations_example/src/Plugin/Action/ViewsBulkOperationExampleAction.php index 6d9e813d7d14af30026c318010150fdc9765466b..3c7b9d23cc080f6a9f0160eeb8b01256e4863171 100644 --- a/web/modules/views_bulk_operations/modules/views_bulk_operations_example/src/Plugin/Action/ViewsBulkOperationExampleAction.php +++ b/web/modules/views_bulk_operations/modules/views_bulk_operations_example/src/Plugin/Action/ViewsBulkOperationExampleAction.php @@ -83,7 +83,7 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta * Submit handler for the action configuration form. * * If not implemented, the cleaned form values will be - * passed direclty to the action $configuration parameter. + * passed directly to the action $configuration parameter. * * @param array $form * Form array. diff --git a/web/modules/views_bulk_operations/modules/views_bulk_operations_example/views_bulk_operations_example.info.yml b/web/modules/views_bulk_operations/modules/views_bulk_operations_example/views_bulk_operations_example.info.yml index f221f4c2ca8ff269643bd574d0424bb770885b3c..2d2965100fc775258329b7ff2eae5911bf5a18de 100644 --- a/web/modules/views_bulk_operations/modules/views_bulk_operations_example/views_bulk_operations_example.info.yml +++ b/web/modules/views_bulk_operations/modules/views_bulk_operations_example/views_bulk_operations_example.info.yml @@ -6,7 +6,7 @@ core_version_requirement: ^8 || ^9 dependencies: - drupal:views_bulk_operations -# Information added by Drupal.org packaging script on 2020-08-13 -version: '8.x-3.9' +# Information added by Drupal.org packaging script on 2020-12-24 +version: '8.x-3.10' project: 'views_bulk_operations' -datestamp: 1597319023 +datestamp: 1608795021 diff --git a/web/modules/views_bulk_operations/src/Commands/ViewsBulkOperationsCommands.php b/web/modules/views_bulk_operations/src/Commands/ViewsBulkOperationsCommands.php index b03c244932e6b983a7a239d2f0a4f3163bc0f318..643ccdce938d0e85a69ad76d625d3b81173c8d2a 100644 --- a/web/modules/views_bulk_operations/src/Commands/ViewsBulkOperationsCommands.php +++ b/web/modules/views_bulk_operations/src/Commands/ViewsBulkOperationsCommands.php @@ -76,7 +76,7 @@ public function __construct( * @option display-id * ID of the display to use. * @option args - * View arguments (slash is a delimeter). + * View arguments (slash is a delimiter). * @option exposed * Exposed filters (query string format). * @option batch-size diff --git a/web/modules/views_bulk_operations/src/Form/ConfigureAction.php b/web/modules/views_bulk_operations/src/Form/ConfigureAction.php index e4bce65029384a033a64e118a9b95c46131a8747..a5d4972b2f3def700dd5b6dd98de650413e445d7 100644 --- a/web/modules/views_bulk_operations/src/Form/ConfigureAction.php +++ b/web/modules/views_bulk_operations/src/Form/ConfigureAction.php @@ -92,7 +92,7 @@ public function buildForm(array $form, FormStateInterface $form_state, $view_id $form['list'] = $this->getListRenderable($form_data); // :D Make sure the submit button is at the bottom of the form - // and is editale from the action buildConfigurationForm method. + // and is editable from the action buildConfigurationForm method. $form['actions']['#weight'] = 666; $form['actions']['submit'] = [ '#type' => 'submit', diff --git a/web/modules/views_bulk_operations/src/Form/ViewsBulkOperationsFormTrait.php b/web/modules/views_bulk_operations/src/Form/ViewsBulkOperationsFormTrait.php index 9d83f90c122992c8d68dda3d6420daf48b8e4dab..5fe4260896908a5cfb0f4c21daac2267df09ae2a 100644 --- a/web/modules/views_bulk_operations/src/Form/ViewsBulkOperationsFormTrait.php +++ b/web/modules/views_bulk_operations/src/Form/ViewsBulkOperationsFormTrait.php @@ -108,6 +108,8 @@ protected function getListRenderable(array $form_data) { $renderable['#title'] = $this->t('Selected @count entities:', ['@count' => $form_data['selected_count']]); } + $renderable['#wrapper_attributes'] = ['class' => ['vbo-info-list-wrapper']]; + return $renderable; } diff --git a/web/modules/views_bulk_operations/src/Plugin/Action/EntityDeleteAction.php b/web/modules/views_bulk_operations/src/Plugin/Action/EntityDeleteAction.php index 9243b259c3419df15e67a649d1e4626545d8fa8a..0c1c08cef0afcc2a1730834c2b26acd9cfc6c10a 100644 --- a/web/modules/views_bulk_operations/src/Plugin/Action/EntityDeleteAction.php +++ b/web/modules/views_bulk_operations/src/Plugin/Action/EntityDeleteAction.php @@ -3,6 +3,7 @@ namespace Drupal\views_bulk_operations\Plugin\Action; use Drupal\views_bulk_operations\Action\ViewsBulkOperationsActionBase; +use Drupal\Core\Entity\TranslatableInterface; use Drupal\Core\Session\AccountInterface; /** @@ -10,7 +11,7 @@ * * @Action( * id = "views_bulk_operations_delete_entity", - * label = @Translation("Delete selected entities"), + * label = @Translation("Delete selected entities / translations"), * type = "", * confirm = TRUE, * ) @@ -21,8 +22,16 @@ class EntityDeleteAction extends ViewsBulkOperationsActionBase { * {@inheritdoc} */ public function execute($entity = NULL) { - $entity->delete(); - return $this->t('Delete entities'); + if ($entity instanceof TranslatableInterface && !$entity->isDefaultTranslation()) { + $untranslated_entity = $entity->getUntranslated(); + $untranslated_entity->removeTranslation($entity->language()->getId()); + $untranslated_entity->save(); + return $this->t('Delete translations'); + } + else { + $entity->delete(); + return $this->t('Delete entities'); + } } /** diff --git a/web/modules/views_bulk_operations/src/Plugin/views/field/ViewsBulkOperationsBulkForm.php b/web/modules/views_bulk_operations/src/Plugin/views/field/ViewsBulkOperationsBulkForm.php index 8579de308f6f74c5a8a24262c8899417c25cb771..1f1f00d7bd68f8b880d478ee7c366727e6ae79c0 100644 --- a/web/modules/views_bulk_operations/src/Plugin/views/field/ViewsBulkOperationsBulkForm.php +++ b/web/modules/views_bulk_operations/src/Plugin/views/field/ViewsBulkOperationsBulkForm.php @@ -202,8 +202,11 @@ public function init(ViewExecutable $view, DisplayPluginBase $display, array &$o * This function must be called a bit later, when the view * query has been built. Also, no point doing this on the view * admin page. + * + * @param array $bulk_form_keys + * The calculated bulk form keys. */ - protected function updateTempstoreData() { + protected function updateTempstoreData(array $bulk_form_keys = NULL) { // Initialize tempstore object and get data if available. $this->tempStoreData = $this->getTempstoreData($this->view->id(), $this->view->current_display); @@ -216,6 +219,11 @@ protected function updateTempstoreData() { 'exposed_input' => $this->view->getExposedInput(), ]; + // Add bulk form keys when the form is displayed. + if (isset($bulk_form_keys)) { + $variable['bulk_form_keys'] = $bulk_form_keys; + } + // A fix to account for empty initial exposed input vs the default values // difference. if (empty($variable['exposed_input'])) { @@ -580,8 +588,29 @@ public function viewsForm(array &$form, FormStateInterface $form_state) { $action_options = $this->getBulkOptions(); if (!empty($this->view->result) && !empty($action_options)) { - // Update tempstore data. - $this->updateTempstoreData(); + // Calculate bulk form keys for all rows. + $bulk_form_keys = []; + $base_field = $this->view->storage->get('base_field'); + foreach ($this->view->result as $row_index => $row) { + $entity = $this->getEntity($row); + $bulk_form_keys[$row_index] = self::calculateEntityBulkFormKey( + $entity, + $row->{$base_field} + ); + } + + // Update and fetch tempstore data to be available from this point + // as it's needed for proper functioning of further logic. + // Update tempstore data with bulk form keys only when the form is + // displayed, but not when the form is being built before submission + // (data is subject to change - new entities added or deleted after + // the form display). TODO: consider using $form_state->set() instead. + if (empty($form_state->getUserInput())) { + $this->updateTempstoreData($bulk_form_keys); + } + else { + $this->updateTempstoreData(); + } $form[$this->options['id']]['#tree'] = TRUE; @@ -595,14 +624,8 @@ public function viewsForm(array &$form, FormStateInterface $form_state) { // Render checkboxes for all rows. $page_selected = []; - $base_field = $this->view->storage->get('base_field'); foreach ($this->view->result as $row_index => $row) { - $entity = $this->getEntity($row); - $bulk_form_key = self::calculateEntityBulkFormKey( - $entity, - $row->{$base_field} - ); - + $bulk_form_key = $bulk_form_keys[$row_index]; $checked = isset($this->tempStoreData['list'][$bulk_form_key]); if (!empty($this->tempStoreData['exclude_mode'])) { $checked = !$checked; @@ -618,6 +641,15 @@ public function viewsForm(array &$form, FormStateInterface $form_state) { '#default_value' => $checked, '#return_value' => $bulk_form_key, ]; + + // We should use #value instead of #default_value to always apply + // the plugin's own saved checkbox state (data being changed after form + // submission results in wrong values applied by the FAPI), + // however - automated tests fail if it's done this way. + // We have to apply values conditionally for tests to pass. + if (isset($element['#value']) && $element['#value'] != $checked) { + $element['#value'] = $checked; + } } // Ensure a consistent container for filters/operations @@ -847,26 +879,22 @@ public function viewsFormSubmit(array &$form, FormStateInterface $form_state) { } // Update list data with the current page selection. - if ($form_state->getValue('select_all')) { - foreach ($form_state->getValue($this->options['id']) as $row_index => $bulkFormKey) { - if ($bulkFormKey) { - unset($this->tempStoreData['list'][$bulkFormKey]); - } - else { - $row_bulk_form_key = $form[$this->options['id']][$row_index]['#return_value']; - $this->tempStoreData['list'][$row_bulk_form_key] = $this->getListItem($row_bulk_form_key); - } - } + $selected_keys = []; + $input = $form_state->getUserInput(); + foreach ($input[$this->options['id']] as $row_index => $bulk_form_key) { + $selected_keys[$bulk_form_key] = $bulk_form_key; } - else { - foreach ($form_state->getValue($this->options['id']) as $row_index => $bulkFormKey) { - if ($bulkFormKey) { - $this->tempStoreData['list'][$bulkFormKey] = $this->getListItem($bulkFormKey); - } - else { - $row_bulk_form_key = $form[$this->options['id']][$row_index]['#return_value']; - unset($this->tempStoreData['list'][$row_bulk_form_key]); - } + $select_all = $form_state->getValue('select_all'); + + foreach ($this->tempStoreData['bulk_form_keys'] as $bulk_form_key) { + if ( + (isset($selected_keys[$bulk_form_key]) && !$select_all) || + (!isset($selected_keys[$bulk_form_key]) && $select_all) + ) { + $this->tempStoreData['list'][$bulk_form_key] = $this->getListItem($bulk_form_key); + } + else { + unset($this->tempStoreData['list'][$bulk_form_key]); } } @@ -971,6 +999,18 @@ public function viewsFormValidate(&$form, FormStateInterface $form_state) { $actionObject->validateConfigurationForm($form['header'][$this->options['id']]['configuration'], $form_state); } } + + // Update bulk form key list if the form has errors, as data might have + // changed before validation took place. + if ($form_state->getErrors()) { + $bulk_form_keys = []; + foreach ($form[$this->options['id']] as $row_index => $element) { + if (is_numeric($row_index) && isset($element['#return_value'])) { + $bulk_form_keys[$row_index] = $element['#return_value']; + } + } + $this->updateTempstoreData($bulk_form_keys); + } } /** diff --git a/web/modules/views_bulk_operations/src/Service/ViewsBulkOperationsActionManager.php b/web/modules/views_bulk_operations/src/Service/ViewsBulkOperationsActionManager.php index 40af081bb9af06ef4ca7d1137af36110e22ddcc6..00db7e5153e28cc0165d5dd0fa85ec6bb5783566 100644 --- a/web/modules/views_bulk_operations/src/Service/ViewsBulkOperationsActionManager.php +++ b/web/modules/views_bulk_operations/src/Service/ViewsBulkOperationsActionManager.php @@ -6,6 +6,7 @@ use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Extension\ModuleHandlerInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Drupal\Core\Entity\EntityTypeManagerInterface; use Symfony\Component\EventDispatcher\Event; use Drupal\Component\Plugin\Exception\PluginNotFoundException; @@ -26,6 +27,13 @@ class ViewsBulkOperationsActionManager extends ActionManager { */ protected $eventDispatcher; + /** + * The entity type manager. + * + * @var \Drupal\Core\Entity\EntityTypeManagerInterface + */ + protected $entityTypeManager; + /** * Additional parameters passed to alter event. * @@ -45,15 +53,21 @@ class ViewsBulkOperationsActionManager extends ActionManager { * The module handler to invoke the alter hook with. * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $eventDispatcher * The event dispatcher service. + * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager + * Entity type manager. */ public function __construct( \Traversable $namespaces, CacheBackendInterface $cacheBackend, ModuleHandlerInterface $moduleHandler, - EventDispatcherInterface $eventDispatcher + EventDispatcherInterface $eventDispatcher, + EntityTypeManagerInterface $entityTypeManager ) { parent::__construct($namespaces, $cacheBackend, $moduleHandler); + $this->eventDispatcher = $eventDispatcher; + $this->entityTypeManager = $entityTypeManager; + $this->setCacheBackend($cacheBackend, 'views_bulk_operations_action_info'); } @@ -63,18 +77,28 @@ public function __construct( protected function findDefinitions() { $definitions = $this->getDiscovery()->getDefinitions(); - // Incompatible actions. - $incompatible = [ - // Deprecated anyway, to be deleted eventually. - 'node_delete_action', - // Those are up to date. - 'entity:delete_action:node', - 'user_cancel_user_action', - ]; - + $entity_type_definitions = $this->entityTypeManager->getDefinitions(); foreach ($definitions as $plugin_id => &$definition) { $this->processDefinition($definition, $plugin_id); - if (empty($definition) || in_array($definition['id'], $incompatible)) { + + // We only allow actions of existing entity type and empty + // type meaning it's applicable to all entity types. + if ( + empty($definition) || + ( + !empty($definition['type']) && + !isset($entity_type_definitions[$definition['type']]) + ) + ) { + unset($definitions[$plugin_id]); + } + + // Filter definitions that are incompatible due to applied core + // configuration form workaround (using confirm_form_route for config + // forms and using action execute() method for purposes other than + // actual action execution). Luckily, core also has useful actions + // without the workaround, like node_assign_owner_action. + if (!in_array('Drupal\views_bulk_operations\Action\ViewsBulkOperationsActionInterface', class_implements($definition['class'])) && (!empty($definition['confirm_form_route_name']))) { unset($definitions[$plugin_id]); } } diff --git a/web/modules/views_bulk_operations/src/Service/ViewsBulkOperationsActionProcessor.php b/web/modules/views_bulk_operations/src/Service/ViewsBulkOperationsActionProcessor.php index 801f647e15b78ed6fd747e8abc89510ee482d2c6..c40294a84a2bb3793607f56732ed42b5a775cdbb 100644 --- a/web/modules/views_bulk_operations/src/Service/ViewsBulkOperationsActionProcessor.php +++ b/web/modules/views_bulk_operations/src/Service/ViewsBulkOperationsActionProcessor.php @@ -127,7 +127,7 @@ public function initialize(array $view_data, $view = NULL) { $this->queue = []; } - $this->excludeMode = $view_data['exclude_mode']; + $this->excludeMode = !empty($view_data['exclude_mode']); if (isset($view_data['action_id'])) { if (!isset($view_data['configuration'])) { @@ -210,7 +210,7 @@ public function getPageList($page) { $this->view->setExposedInput(['_views_bulk_operations_override' => TRUE]); } - // In some cases we may encounter nondeterministic bahaviour in + // In some cases we may encounter nondeterministic behaviour in // db queries with sorts allowing different order of results. // To fix this we're removing all sorts and setting one sorting // rule by the view base id field. @@ -303,7 +303,7 @@ public function populateQueue(array $data, array &$context = []) { $batch_list = $list; } - $this->view->setItemsPerPage(0); + $this->view->setItemsPerPage($batch_size); $this->view->setCurrentPage(0); $this->view->setOffset(0); $this->view->initHandlers(); diff --git a/web/modules/views_bulk_operations/src/Service/ViewsBulkOperationsViewData.php b/web/modules/views_bulk_operations/src/Service/ViewsBulkOperationsViewData.php index d72ae49e0eddec0be7e605e254418708d527c015..a3466f4b340387cc65ca05074d98751e6b06cee2 100644 --- a/web/modules/views_bulk_operations/src/Service/ViewsBulkOperationsViewData.php +++ b/web/modules/views_bulk_operations/src/Service/ViewsBulkOperationsViewData.php @@ -38,7 +38,7 @@ class ViewsBulkOperationsViewData implements ViewsBulkOperationsViewDataInterfac protected $view; /** - * The realtionship ID. + * The relationship ID. * * @var string */ diff --git a/web/modules/views_bulk_operations/src/ViewsBulkOperationsBatch.php b/web/modules/views_bulk_operations/src/ViewsBulkOperationsBatch.php index b809ebf464d75f89ed63eaf8c7f0a08537bf0601..97356a16fa3cac36b3a57cfb060fb4e2ef666d6f 100644 --- a/web/modules/views_bulk_operations/src/ViewsBulkOperationsBatch.php +++ b/web/modules/views_bulk_operations/src/ViewsBulkOperationsBatch.php @@ -77,7 +77,7 @@ public static function getList(array $data, array &$context) { * Save generated list to user tempstore. * * @param bool $success - * Was the process successfull? + * Was the process successful? * @param array $results * Batch process results array. * @param array $operations @@ -145,7 +145,7 @@ public static function operation(array $data, array &$context) { * Batch finished callback. * * @param bool $success - * Was the process successfull? + * Was the process successful? * @param array $results * Batch process results array. * @param array $operations diff --git a/web/modules/views_bulk_operations/tests/src/Functional/ViewsBulkOperationsBulkFormTest.php b/web/modules/views_bulk_operations/tests/src/Functional/ViewsBulkOperationsBulkFormTest.php index b008520b345e89065ee653f413b89622a363b430..3c700d685a5ff52159e1102c423f8da2b755ff0f 100644 --- a/web/modules/views_bulk_operations/tests/src/Functional/ViewsBulkOperationsBulkFormTest.php +++ b/web/modules/views_bulk_operations/tests/src/Functional/ViewsBulkOperationsBulkFormTest.php @@ -56,47 +56,6 @@ protected function setUp() { } - /** - * Helper function to test a batch process. - * - * After checking if we're on a Batch API page, - * the iterations are executed, the finished page is opened - * and browser redirects to the final destination. - * - * NOTE: As of Drupal 8.4, functional test - * automatically redirects user through all Batch API pages, - * so this function is not longer needed. - */ - protected function assertBatchProcess() { - // Get the current batch ID. - $current_url = $this->getUrl(); - $q = substr($current_url, strrpos($current_url, '/') + 1); - $this->assertEquals('batch?', substr($q, 0, 6), 'We are on a Batch API page.'); - - preg_match('#id=([0-9]+)#', $q, $matches); - $batch_id = $matches[1]; - - // Proceed with the operations. - // Assumption: all operations will be completed within a single request. - // TODO: modify code to include an option when the assumption is false. - do { - $this->drupalGet('batch', [ - 'query' => [ - 'id' => $batch_id, - 'op' => 'do_nojs', - ], - ]); - } while (FALSE); - - // Get the finished page. - $this->drupalGet('batch', [ - 'query' => [ - 'id' => $batch_id, - 'op' => 'finished', - ], - ]); - } - /** * Tests the VBO bulk form with simple test action. */ diff --git a/web/modules/views_bulk_operations/tests/src/FunctionalJavascript/ViewsBulkOperationsBulkFormTest.php b/web/modules/views_bulk_operations/tests/src/FunctionalJavascript/ViewsBulkOperationsBulkFormTest.php new file mode 100644 index 0000000000000000000000000000000000000000..7263470640aa5648322ffbd247c2d5d95206d348 --- /dev/null +++ b/web/modules/views_bulk_operations/tests/src/FunctionalJavascript/ViewsBulkOperationsBulkFormTest.php @@ -0,0 +1,143 @@ +<?php + +namespace Drupal\Tests\views_bulk_operations\FunctionalJavaScript; + +use Drupal\FunctionalJavascriptTests\WebDriverTestBase; +use Drupal\views_bulk_operations\Form\ViewsBulkOperationsFormTrait; + +/** + * @coversDefaultClass \Drupal\views_bulk_operations\Plugin\views\field\ViewsBulkOperationsBulkForm + * @group views_bulk_operations + */ +class ViewsBulkOperationsBulkFormTest extends WebDriverTestBase { + + use ViewsBulkOperationsFormTrait; + + const TEST_NODE_COUNT = 15; + + /** + * {@inheritdoc} + */ + protected $defaultTheme = 'stable'; + + + /** + * The assert session. + * + * @var \Drupal\Tests\WebAssert + */ + protected $assertSession; + + /** + * The page element. + * + * @var \Behat\Mink\Element\DocumentElement + */ + protected $page; + + + /** + * The selected indexes of rows. + * + * @var array + */ + protected $selectedIndexes = []; + + /** + * Modules to install. + * + * @var array + */ + public static $modules = [ + 'node', + 'views', + 'views_bulk_operations', + 'views_bulk_operations_test', + ]; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + + // Create some nodes for testing. + $this->drupalCreateContentType(['type' => 'page']); + for ($i = 1; $i <= self::TEST_NODE_COUNT; $i++) { + $this->drupalCreateNode([ + 'type' => 'page', + 'title' => 'Title ' . $i, + ]); + } + $admin_user = $this->drupalCreateUser( + [ + 'edit any page content', + 'create page content', + 'delete any page content', + ]); + $this->drupalLogin($admin_user); + + $this->assertSession = $this->assertSession(); + $this->page = $this->getSession()->getPage(); + + $this->drupalGet('/views-bulk-operations-test'); + + // Make sure a checkbox appears on all rows and the button exists. + for ($i = 0; $i < 4; $i++) { + $this->assertSession->fieldExists('edit-views-bulk-operations-bulk-form-' . $i); + } + $this->assertSession->buttonExists('Simple test action'); + + $this->selectedIndexes = [0, 1, 3]; + + foreach ($this->selectedIndexes as $selected_index) { + $this->page->checkField('edit-views-bulk-operations-bulk-form-' . $selected_index); + } + + } + + /** + * Tests the VBO bulk form without dynamic insertion. + */ + public function testViewsBulkOperationsWithOutDynamicInsertion() { + + $this->page->pressButton('Simple test action'); + + foreach ($this->selectedIndexes as $index) { + $this->assertSession->pageTextContains(sprintf('Test action (preconfig: Test setting, label: Title %s)', self::TEST_NODE_COUNT - $index)); + } + $this->assertSession->pageTextContains(sprintf('Action processing results: Test (%s)', count($this->selectedIndexes))); + + } + + /** + * Tests the VBO bulk form with dynamic insertion. + * + * Nodes inserted right after selecting targeted row(s) of the view. + */ + public function testViewsBulkOperationsWithDynamicInsertion() { + + // Insert nodes. + $nodes = []; + for ($i = 100; $i < 100 + self::TEST_NODE_COUNT; $i++) { + $nodes[] = $this->drupalCreateNode([ + 'type' => 'page', + 'title' => 'Title ' . $i, + ]); + } + + $this->page->pressButton('Simple test action'); + + foreach ($this->selectedIndexes as $index) { + $this->assertSession->pageTextContains(sprintf('Test action (preconfig: Test setting, label: Title %s)', self::TEST_NODE_COUNT - $index)); + } + $this->assertSession->pageTextContains(sprintf('Action processing results: Test (%s)', count($this->selectedIndexes))); + + // Remove nodes inserted in the middle. + foreach ($nodes as $node) { + $node->delete(); + } + + } + +} diff --git a/web/modules/views_bulk_operations/tests/src/Kernel/ViewsBulkOperationsKernelTestBase.php b/web/modules/views_bulk_operations/tests/src/Kernel/ViewsBulkOperationsKernelTestBase.php index 6c80cedd5d5f7bb0a46ce9d9215f3c005873d3f6..032e3a45cc72c81adcda62fc8d57a4682d906922 100644 --- a/web/modules/views_bulk_operations/tests/src/Kernel/ViewsBulkOperationsKernelTestBase.php +++ b/web/modules/views_bulk_operations/tests/src/Kernel/ViewsBulkOperationsKernelTestBase.php @@ -262,7 +262,7 @@ protected function executeAction(array $vbo_data) { $vbo_data['action_label'] = (string) $action_definition['label']; } - // Account for eclude mode. + // Account for exclude mode. if ($vbo_data['exclude_mode']) { $vbo_data['exclude_list'] = $vbo_data['list']; $vbo_data['list'] = []; diff --git a/web/modules/views_bulk_operations/tests/views_bulk_operations_test/views_bulk_operations_test.info.yml b/web/modules/views_bulk_operations/tests/views_bulk_operations_test/views_bulk_operations_test.info.yml index d38540259e69437dd3496847f8d19f16546fd188..1d3513193f973e4882c9f1e188fbe7a971d8172b 100644 --- a/web/modules/views_bulk_operations/tests/views_bulk_operations_test/views_bulk_operations_test.info.yml +++ b/web/modules/views_bulk_operations/tests/views_bulk_operations_test/views_bulk_operations_test.info.yml @@ -7,7 +7,7 @@ dependencies: - drupal:views_bulk_operations - drupal:node -# Information added by Drupal.org packaging script on 2020-08-13 -version: '8.x-3.9' +# Information added by Drupal.org packaging script on 2020-12-24 +version: '8.x-3.10' project: 'views_bulk_operations' -datestamp: 1597319023 +datestamp: 1608795021 diff --git a/web/modules/views_bulk_operations/views_bulk_operations.drush.inc b/web/modules/views_bulk_operations/views_bulk_operations.drush.inc index 4593d13f58f4cf606e594752219be1e9e158d597..8ac8bd17600bca0fbf10920e1312110187a7043d 100644 --- a/web/modules/views_bulk_operations/views_bulk_operations.drush.inc +++ b/web/modules/views_bulk_operations/views_bulk_operations.drush.inc @@ -22,7 +22,7 @@ function views_bulk_operations_drush_command() { ], 'options' => [ 'display-id' => 'ID of the display to use (default: default)', - 'args' => 'View arguments (slash is a delimeter, default: none)', + 'args' => 'View arguments (slash is a delimiter, default: none)', 'exposed' => 'Exposed filters (query string format)', 'batch-size' => 'Processing batch size (default: 100)', 'config' => 'Action configuration (query string format)', @@ -77,7 +77,7 @@ function _views_bulk_operations_timer($debug = TRUE, $id = NULL) { } /** - * The vbo-exec command executtion function. + * The vbo-exec command execution function. * * @param string $view_id * The ID of the view to use. diff --git a/web/modules/views_bulk_operations/views_bulk_operations.info.yml b/web/modules/views_bulk_operations/views_bulk_operations.info.yml index 0c013455895cbb137b3edb4186600f914730ef73..9539dbe95dbe7a65e514e269b8d624345a6303cf 100644 --- a/web/modules/views_bulk_operations/views_bulk_operations.info.yml +++ b/web/modules/views_bulk_operations/views_bulk_operations.info.yml @@ -6,7 +6,7 @@ core_version_requirement: ^8.8 || ^9 dependencies: - drupal:views -# Information added by Drupal.org packaging script on 2020-08-13 -version: '8.x-3.9' +# Information added by Drupal.org packaging script on 2020-12-24 +version: '8.x-3.10' project: 'views_bulk_operations' -datestamp: 1597319023 +datestamp: 1608795021 diff --git a/web/modules/views_bulk_operations/views_bulk_operations.services.yml b/web/modules/views_bulk_operations/views_bulk_operations.services.yml index ef64d9e476501b7c1a8bcd8589255fb65f2d2858..3937a3d0273cd1e5e8aa1014d5d22abe86fa31ff 100644 --- a/web/modules/views_bulk_operations/views_bulk_operations.services.yml +++ b/web/modules/views_bulk_operations/views_bulk_operations.services.yml @@ -7,7 +7,7 @@ services: arguments: ['@views_bulk_operations.data', '@plugin.manager.views_bulk_operations_action', '@current_user', '@module_handler'] plugin.manager.views_bulk_operations_action: class: Drupal\views_bulk_operations\Service\ViewsBulkOperationsActionManager - arguments: ['@container.namespaces', '@cache.discovery', '@module_handler', '@event_dispatcher'] + arguments: ['@container.namespaces', '@cache.discovery', '@module_handler', '@event_dispatcher', '@entity_type.manager'] views_bulk_operations.access: class: Drupal\views_bulk_operations\Access\ViewsBulkOperationsAccess arguments: ['@tempstore.private']