diff --git a/composer.json b/composer.json index 6c97470805a9f510515b34904fef1177d817ae36..d04004f4c6fba873fe9eb7ee54a2280c55e746ea 100644 --- a/composer.json +++ b/composer.json @@ -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..6d5b3ce12dbc7c9fc937138ecc2b9cfbc786912f 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": "3e27a76fd706d895eb8803af3caafa29", "packages": [ { "name": "alchemy/zippy", @@ -8473,17 +8473,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 +8497,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..3045459dbe7e86543c4e02dfb0f572c05bec9149 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -8738,18 +8738,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 +8763,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/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']