diff --git a/src/Plugin/Field/FieldWidget/EntityReferenceBrowserWidget.php b/src/Plugin/Field/FieldWidget/EntityReferenceBrowserWidget.php index a60cd12..592a553 100644 --- a/src/Plugin/Field/FieldWidget/EntityReferenceBrowserWidget.php +++ b/src/Plugin/Field/FieldWidget/EntityReferenceBrowserWidget.php @@ -197,7 +197,7 @@ class EntityReferenceBrowserWidget extends WidgetBase implements ContainerFactor $element['field_widget_remove'] = [ '#title' => $this->t('Display Remove / Replace button'), - '#description' => $this->t('In required single-valued fields, this button will show "Replace" instead of the default "Remove". In that scenario, when clicked the current selection will be emptied and the browser will be opened to allow a new selection to take place.'), + '#description' => $this->t('In required single-valued fields, this button will show "Replace" instead of the default "Remove". In that scenario, once clicked the current selection will be emptied and the browser will be opened to allow a new selection to take place.'), '#type' => 'checkbox', '#default_value' => $this->getSetting('field_widget_remove'), ]; @@ -431,7 +431,7 @@ class EntityReferenceBrowserWidget extends WidgetBase implements ContainerFactor } elseif ($trigger['#type'] == 'submit' && strpos($trigger['#name'], '_remove_')) { $parents = array_slice($trigger['#array_parents'], 0, -static::$deleteDepth); - if ((string) $trigger['#value'] === (string) t('Replace')) { + if (!empty($trigger['#attributes']['class']) && in_array('replace-button', $trigger['#attributes']['class'])) { // We need to re-open the browser. Instead of just passing "TRUE", send // to the JS the unique part of the button's name that needs to be // clicked. @@ -558,6 +558,7 @@ class EntityReferenceBrowserWidget extends WidgetBase implements ContainerFactor '#attributes' => [ 'data-entity-id' => $entity->getEntityTypeId() . ':' . $entity->id(), 'data-row-id' => $row_id, + 'class' => [$show_replace ? 'replace-button' : 'remove-button'], ], '#access' => (bool) $this->getSetting('field_widget_remove'), ], diff --git a/tests/src/FunctionalJavascript/EntityReferenceWidgetTest.php b/tests/src/FunctionalJavascript/EntityReferenceWidgetTest.php index c760cce..d88825d 100644 --- a/tests/src/FunctionalJavascript/EntityReferenceWidgetTest.php +++ b/tests/src/FunctionalJavascript/EntityReferenceWidgetTest.php @@ -24,8 +24,11 @@ class EntityReferenceWidgetTest extends EntityBrowserJavascriptTestBase { /** @var \Drupal\user\RoleInterface $role */ $role = Role::load('authenticated'); - $this->grantPermissions($role, ['access test_entity_browser_iframe_node_view entity browser pages']); - $this->grantPermissions($role, ['bypass node access']); + $this->grantPermissions($role, [ + 'access test_entity_browser_iframe_node_view entity browser pages', + 'bypass node access', + 'administer node form display', + ]); } @@ -33,12 +36,12 @@ class EntityReferenceWidgetTest extends EntityBrowserJavascriptTestBase { * Tests Entity Reference widget. */ public function testEntityReferenceWidget() { - - $page = $this->getSession()->getPage(); + $session = $this->getSession(); + $page = $session->getPage(); $assert_session = $this->assertSession(); // Create an entity_reference field to test the widget. - FieldStorageConfig::create([ + $field_storage = FieldStorageConfig::create([ 'field_name' => 'field_entity_reference1', 'type' => 'entity_reference', 'entity_type' => 'node', @@ -46,15 +49,17 @@ class EntityReferenceWidgetTest extends EntityBrowserJavascriptTestBase { 'settings' => [ 'target_type' => 'node', ], - ])->save(); + ]); + $field_storage->save(); - FieldConfig::create([ + $field = FieldConfig::create([ 'field_name' => 'field_entity_reference1', 'entity_type' => 'node', 'bundle' => 'article', 'label' => 'Referenced articles', 'settings' => [], - ])->save(); + ]); + $field->save(); /** @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface $form_display */ $form_display = $this->container->get('entity_type.manager') @@ -83,11 +88,11 @@ class EntityReferenceWidgetTest extends EntityBrowserJavascriptTestBase { $this->drupalGet('/node/add/article'); $page->fillField('title[0][value]', 'Referencing node 1'); - $this->getSession()->switchToIFrame('entity_browser_iframe_test_entity_browser_iframe_node_view'); + $session->switchToIFrame('entity_browser_iframe_test_entity_browser_iframe_node_view'); $this->waitForAjaxToFinish(); $page->checkField('edit-entity-browser-select-node1'); $page->pressButton('Select entities'); - $this->getSession()->switchToIFrame(); + $session->switchToIFrame(); $this->waitForAjaxToFinish(); $page->pressButton('Save'); @@ -133,25 +138,73 @@ class EntityReferenceWidgetTest extends EntityBrowserJavascriptTestBase { ], ])->save(); $this->drupalGet('node/' . $nid . '/edit'); - $assert_session->buttonExists('edit-field-entity-reference1-current-items-0-remove-button'); - $assert_session->buttonExists('edit-field-entity-reference1-current-items-0-edit-button'); + $remove_button = $assert_session->buttonExists('edit-field-entity-reference1-current-items-0-remove-button'); + $this->assertEquals('Remove', $remove_button->getValue()); + $this->assertTrue($remove_button->hasClass('remove-button')); + $this->assertFalse($remove_button->hasClass('replace-button')); + $edit_button = $assert_session->buttonExists('edit-field-entity-reference1-current-items-0-edit-button'); + $this->assertEquals('Edit', $edit_button->getValue()); // Test the "Remove" button on the widget works. $page->pressButton('Remove'); $this->waitForAjaxToFinish(); $assert_session->pageTextNotContains('Target example node 1'); + // Change the field cardinality to 1 and make it required, so we can check + // that the "Remove" button shows "Replace" instead. + $field_storage->setCardinality(1)->save(); + $field->setRequired(TRUE)->save(); + // We'll need a third node to be able to make a new selection. + $target_node2 = Node::create([ + 'title' => 'Target example node 2', + 'type' => 'article', + ]); + $target_node2->save(); + $this->drupalGet('node/' . $nid . '/edit'); + $remove_button = $assert_session->buttonExists('edit-field-entity-reference1-current-items-0-remove-button'); + $this->assertEquals('Replace', $remove_button->getValue()); + $this->assertTrue($remove_button->hasClass('replace-button')); + $this->assertFalse($remove_button->hasClass('remove-button')); + // Clicking on the button should empty the selection and automatically + // open the browser again. + $remove_button->click(); + $this->waitForAjaxToFinish(); + $session->switchToIFrame('entity_browser_iframe_test_entity_browser_iframe_node_view'); + $this->waitForAjaxToFinish(); + $page->checkField('edit-entity-browser-select-node3'); + $page->pressButton('Select entities'); + $session->switchToIFrame(); + $this->waitForAjaxToFinish(); + $page->pressButton('Save'); + $assert_session->pageTextContains('Article Referencing node 1 has been updated.'); + + // Go to the widget config settings and check that the "Remove" button + // option has the correct help text. + $this->drupalGet('/admin/structure/types/manage/article/form-display'); + $assert_session->elementExists('css', '#edit-fields-field-entity-reference1-settings-edit')->click(); + $this->waitForAjaxToFinish(); + $assert_session->elementContains( + 'css', + '.ajax-new-content .form-item-fields-field-entity-reference1-settings-edit-form-settings-field-widget-remove label', + 'Display Remove / Replace button' + ); + $assert_session->elementContains( + 'css', + '.ajax-new-content .form-item-fields-field-entity-reference1-settings-edit-form-settings-field-widget-remove .description', + 'In required single-valued fields, this button will show "Replace" instead of the default "Remove". In that scenario, once clicked the current selection will be emptied and the browser will be opened to allow a new selection to take place.' + ); + // Verify that if the user cannot edit the entity, the "Edit" button does // not show up, even if configured to. /** @var \Drupal\user\RoleInterface $role */ $role = Role::load('authenticated'); $role->revokePermission('bypass node access')->trustData()->save(); $this->drupalGet('node/add/article'); - $this->getSession()->switchToIFrame('entity_browser_iframe_test_entity_browser_iframe_node_view'); + $session->switchToIFrame('entity_browser_iframe_test_entity_browser_iframe_node_view'); $this->waitForAjaxToFinish(); $page->checkField('edit-entity-browser-select-node1'); $page->pressButton('Select entities'); - $this->getSession()->switchToIFrame(); + $session->switchToIFrame(); $this->waitForAjaxToFinish(); $assert_session->buttonNotExists('edit-field-entity-reference1-current-items-0-edit-button');