diff --git a/core/modules/content_moderation/config/install/workflows.workflow.editorial.yml b/core/modules/content_moderation/config/install/workflows.workflow.editorial.yml index d8daa51..9625065 100644 --- a/core/modules/content_moderation/config/install/workflows.workflow.editorial.yml +++ b/core/modules/content_moderation/config/install/workflows.workflow.editorial.yml @@ -23,7 +23,7 @@ transitions: to: archived weight: 2 archived_draft: - label: 'Restore to Draft' + label: 'Restore to draft' from: - archived to: draft @@ -35,7 +35,7 @@ transitions: to: published weight: 4 create_new_draft: - label: 'Create New Draft' + label: 'Create new draft' from: - draft - published diff --git a/core/modules/content_moderation/src/Plugin/Field/FieldWidget/ModerationStateWidget.php b/core/modules/content_moderation/src/Plugin/Field/FieldWidget/ModerationStateWidget.php index e64dc97..5350c01 100644 --- a/core/modules/content_moderation/src/Plugin/Field/FieldWidget/ModerationStateWidget.php +++ b/core/modules/content_moderation/src/Plugin/Field/FieldWidget/ModerationStateWidget.php @@ -2,6 +2,10 @@ namespace Drupal\content_moderation\Plugin\Field\FieldWidget; +use Drupal\Core\Ajax\AjaxResponse; +use Drupal\Core\Ajax\AppendCommand; +use Drupal\Core\Ajax\InsertCommand; +use Drupal\Core\Ajax\ReplaceCommand; use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Field\FieldDefinitionInterface; @@ -126,52 +130,62 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen $transitions = $this->validator->getValidTransitions($entity, $this->currentUser); $target_states = []; + $transition_labels = []; foreach ($transitions as $transition) { - $target_states[$transition->to()->id()] = $transition->label(); + $target_states[$transition->to()->id()] = $transition->to()->label(); + $transition_labels[$transition->to()->id()] = $transition->label(); } // @todo https://www.drupal.org/node/2779933 write a test for this. $element += [ - '#type' => 'select', - '#options' => $target_states, - '#default_value' => isset($target_states[$default->id()]) ? $default->id() : NULL, - '#empty_option' => '- Select moderation state -', - '#key_column' => $this->column, + '#type' => 'container', + 'current' => [ + '#type' => 'item', + '#wrapper_attributes' => ['class' => ['current-moderation-state', 'container-inline']], + '#markup' => '

' . t('Current moderation state') . '

' . $default->label(), + ], + 'state' => [ + '#type' => 'select', + '#options' => $target_states, + '#default_value' => isset($target_states[$default->id()]) ? $default->id() : NULL, + '#empty_option' => '- Select new state -', + '#key_column' => $this->column, + '#transitions' => $transition_labels, + '#description' => isset($transition_labels[$default->id()]) ? $transition_labels[$default->id()] . ' when saved.' : '
', + '#ajax' => [ + 'callback' => [get_class($this), 'change'], + 'event' => 'change', + 'wrapper' => 'edit-moderation-state-0-state--description', + 'method' => 'html', + ] + ] ]; - $element['#element_validate'][] = array(get_class($this), 'validateElement'); + $element['#element_validate'][] = [get_class($this), 'validateElement']; return $element; } /** - * {@inheritdoc} + * @param array $element + * @param \Drupal\Core\Form\FormStateInterface $form_state + * + * @return array */ - public static function validateElement(array $element, FormStateInterface $form_state) { - if (empty($element['#value'])) { - $form_state->setError($element, t('Please select a moderation state.')); - return; - } - $form_state->setValueForElement($element, [$element['#key_column'] => $element['#value']]); + public static function change(array $element, FormStateInterface $form_state) { + $state = $form_state->getValue('moderation_state')[0]['value']; + $transition_labels = $element['moderation_state']['widget'][0]['state']['#transitions']; + return ['#plain_text' => isset($transition_labels[$state]) ? $transition_labels[$state] . ' when saved.' : '']; } - /** - * Entity builder updating the node moderation state with the submitted value. - * - * @param string $entity_type_id - * The entity type identifier. - * @param \Drupal\Core\Entity\ContentEntityInterface $entity - * The entity updated with the submitted values. - * @param array $form - * The complete form array. - * @param \Drupal\Core\Form\FormStateInterface $form_state - * The current state of the form. + * {@inheritdoc} */ - public static function updateStatus($entity_type_id, ContentEntityInterface $entity, array $form, FormStateInterface $form_state) { - $element = $form_state->getTriggeringElement(); - if (isset($element['#moderation_state'])) { - $entity->moderation_state->value = $element['#moderation_state']; + public static function validateElement(array $element, FormStateInterface $form_state) { + if (empty($element['state']['#value'])) { + $form_state->setError($element, t('Please select a moderation state.')); + return; } + $form_state->setValueForElement($element, [$element['state']['#key_column'] => $element['state']['#value']]); } /** diff --git a/core/modules/content_moderation/src/Tests/ModerationFormTest.php b/core/modules/content_moderation/src/Tests/ModerationFormTest.php index 778bc9a..9522c78 100644 --- a/core/modules/content_moderation/src/Tests/ModerationFormTest.php +++ b/core/modules/content_moderation/src/Tests/ModerationFormTest.php @@ -34,7 +34,7 @@ public function testModerationForm() { $this->drupalPostForm('node/add/moderated_content', [ 'title[0][value]' => 'Some moderated content', 'body[0][value]' => 'First version of the content.', - 'moderation_state[0]' => 'draft', + 'moderation_state[0][state]' => 'draft', ], t('Save')); $node = $this->drupalGetNodeByTitle('Some moderated content'); @@ -51,19 +51,19 @@ public function testModerationForm() { // Try saving with no moderation state. $this->drupalGet($edit_path); - $this->assertFieldsByValue($this->xpath('//select[@id="edit-moderation-state-0"]'), 'draft'); + $this->assertFieldsByValue($this->xpath('//select[@id="edit-moderation-state-0-state"]'), 'draft'); $this->drupalPostForm($edit_path, [ 'body[0][value]' => 'Second version of the content.', - 'moderation_state[0]' => '', + 'moderation_state[0][state]' => '', ], t('Save')); $this->assertText('Please select a moderation state.'); // Update the draft. $this->drupalGet($edit_path); - $this->assertFieldsByValue($this->xpath('//select[@id="edit-moderation-state-0"]'), 'draft'); + $this->assertFieldsByValue($this->xpath('//select[@id="edit-moderation-state-0-state"]'), 'draft'); $this->drupalPostForm($edit_path, [ 'body[0][value]' => 'Second version of the content.', - 'moderation_state[0]' => 'draft', + 'moderation_state[0][state]' => 'draft', ], t('Save')); // The latest version page should not show, because there is still no @@ -73,26 +73,26 @@ public function testModerationForm() { // Publish the draft. $this->drupalGet($edit_path); - $this->assertFieldsByValue($this->xpath('//select[@id="edit-moderation-state-0"]'), 'draft'); + $this->assertFieldsByValue($this->xpath('//select[@id="edit-moderation-state-0-state"]'), 'draft'); $this->drupalPostForm($edit_path, [ 'body[0][value]' => 'Third version of the content.', - 'moderation_state[0]' => 'published', + 'moderation_state[0][state]' => 'published', ], t('Save')); // Archive the published entity. $this->drupalGet($edit_path); - $this->assertFieldsByValue($this->xpath('//select[@id="edit-moderation-state-0"]'), 'published'); + $this->assertFieldsByValue($this->xpath('//select[@id="edit-moderation-state-0-state"]'), 'published'); $this->drupalPostForm($edit_path, [ 'body[0][value]' => 'Fourth version of the content.', - 'moderation_state[0]' => 'archived', + 'moderation_state[0][state]' => 'archived', ], t('Save')); // Then back to Published so we can add a forward revision. $this->drupalGet($edit_path); - $this->assertFieldsByValue($this->xpath('//select[@id="edit-moderation-state-0"]'), ''); + $this->assertFieldsByValue($this->xpath('//select[@id="edit-moderation-state-0-state"]'), ''); $this->drupalPostForm($edit_path, [ 'body[0][value]' => 'Fifth version of the content.', - 'moderation_state[0]' => 'published', + 'moderation_state[0][state]' => 'published', ], t('Save')); // The published view should not have a moderation form, because it is the @@ -108,10 +108,10 @@ public function testModerationForm() { // Make a forward revision. $this->drupalGet($edit_path); - $this->assertFieldsByValue($this->xpath('//select[@id="edit-moderation-state-0"]'), 'published'); + $this->assertFieldsByValue($this->xpath('//select[@id="edit-moderation-state-0-state"]'), 'published'); $this->drupalPostForm($edit_path, [ 'body[0][value]' => 'Sixth version of the content.', - 'moderation_state[0]' => 'draft', + 'moderation_state[0][state]' => 'draft', ], t('Save')); // The published view should not have a moderation form, because it is the diff --git a/core/modules/content_moderation/src/Tests/ModerationStateBlockTest.php b/core/modules/content_moderation/src/Tests/ModerationStateBlockTest.php index 9990f60..9f0b6a4 100644 --- a/core/modules/content_moderation/src/Tests/ModerationStateBlockTest.php +++ b/core/modules/content_moderation/src/Tests/ModerationStateBlockTest.php @@ -67,7 +67,7 @@ public function testCustomBlockModeration() { $body = 'Body of moderated block'; $edit = [ 'info[0][value]' => 'Moderated block', - 'moderation_state[0]' => 'draft', + 'moderation_state[0][state]' => 'draft', 'body[0][value]' => $body, ]; $this->drupalPostForm('block/add', $edit, t('Save')); @@ -92,7 +92,7 @@ public function testCustomBlockModeration() { $updated_body = 'This is the new body value'; $edit = [ 'body[0][value]' => $updated_body, - 'moderation_state[0]' => 'draft' + 'moderation_state[0][state]' => 'draft' ]; $this->drupalPostForm('block/' . $block->id(), $edit, t('Save')); $this->assertText(t('basic Moderated block has been updated.')); @@ -105,14 +105,14 @@ public function testCustomBlockModeration() { // Publish the block so we can create a forward revision. $this->drupalPostForm('block/' . $block->id(), [ - 'moderation_state[0]' => 'published' + 'moderation_state[0][state]' => 'published' ], t('Save')); // Create a forward revision. $forward_revision_body = 'This is the forward revision body value'; $edit = [ 'body[0][value]' => $forward_revision_body, - 'moderation_state[0]' => 'draft' + 'moderation_state[0][state]' => 'draft' ]; $this->drupalPostForm('block/' . $block->id(), $edit, t('Save')); $this->assertText(t('basic Moderated block has been updated.')); diff --git a/core/modules/content_moderation/src/Tests/ModerationStateNodeTest.php b/core/modules/content_moderation/src/Tests/ModerationStateNodeTest.php index 3652ddc..1861872 100644 --- a/core/modules/content_moderation/src/Tests/ModerationStateNodeTest.php +++ b/core/modules/content_moderation/src/Tests/ModerationStateNodeTest.php @@ -28,7 +28,7 @@ protected function setUp() { public function testCreatingContent() { $this->drupalPostForm('node/add/moderated_content', [ 'title[0][value]' => 'moderated content', - 'moderation_state[0]' => 'draft' + 'moderation_state[0][state]' => 'draft' ], t('Save')); $node = $this->getNodeByTitle('moderated content'); if (!$node) { @@ -39,7 +39,7 @@ public function testCreatingContent() { $path = 'node/' . $node->id() . '/edit'; // Set up published revision. $this->drupalPostForm($path, [ - 'moderation_state[0]' => 'published' + 'moderation_state[0][state]' => 'published' ], t('Save')); \Drupal::entityTypeManager()->getStorage('node')->resetCache([$node->id()]); /* @var \Drupal\node\NodeInterface $node */ @@ -83,7 +83,7 @@ public function testFormSaveDestination() { $this->drupalPostForm('node/add/moderated_content', [ 'title[0][value]' => 'Some moderated content', 'body[0][value]' => 'First version of the content.', - 'moderation_state[0]' => 'draft' + 'moderation_state[0][state]' => 'draft' ], t('Save')); $node = $this->drupalGetNodeByTitle('Some moderated content'); @@ -98,7 +98,7 @@ public function testFormSaveDestination() { // URL, but viewing the second revision. $this->drupalPostForm($edit_path, [ 'body[0][value]' => 'Second version of the content.', - 'moderation_state[0]' => 'draft' + 'moderation_state[0][state]' => 'draft' ], t('Save')); $this->assertUrl(Url::fromRoute('entity.node.canonical', ['node' => $node->id()])); $this->assertText('Second version of the content.'); @@ -107,7 +107,7 @@ public function testFormSaveDestination() { // canonical URL. $this->drupalPostForm($edit_path, [ 'body[0][value]' => 'Third version of the content.', - 'moderation_state[0]' => 'published' + 'moderation_state[0][state]' => 'published' ], t('Save')); $this->assertUrl(Url::fromRoute('entity.node.canonical', ['node' => $node->id()])); $this->assertText('Third version of the content.'); @@ -116,7 +116,7 @@ public function testFormSaveDestination() { // version" tab. $this->drupalPostForm($edit_path, [ 'body[0][value]' => 'Fourth version of the content.', - 'moderation_state[0]' => 'draft' + 'moderation_state[0][state]' => 'draft' ], t('Save')); $this->assertUrl(Url::fromRoute('entity.node.latest_version', ['node' => $node->id()])); $this->assertText('Fourth version of the content.'); diff --git a/core/modules/content_moderation/src/Tests/ModerationStateNodeTypeTest.php b/core/modules/content_moderation/src/Tests/ModerationStateNodeTypeTest.php index f0dd6cc..f72e6c5 100644 --- a/core/modules/content_moderation/src/Tests/ModerationStateNodeTypeTest.php +++ b/core/modules/content_moderation/src/Tests/ModerationStateNodeTypeTest.php @@ -67,7 +67,7 @@ public function testEnablingOnExistingContent() { $this->assertLinkByHref('node/' . $node->id() . '/edit'); $this->drupalGet('node/' . $node->id() . '/edit'); $this->assertResponse(200); - $this->assertRaw('Create New Draft'); + $this->assertRaw('Draft'); $this->assertRaw('Publish'); } diff --git a/core/modules/content_moderation/tests/src/Functional/ModerationLocaleTest.php b/core/modules/content_moderation/tests/src/Functional/ModerationLocaleTest.php index 92b6a3b..3523e98 100644 --- a/core/modules/content_moderation/tests/src/Functional/ModerationLocaleTest.php +++ b/core/modules/content_moderation/tests/src/Functional/ModerationLocaleTest.php @@ -53,7 +53,7 @@ public function testTranslateModeratedContent() { $edit = [ 'title[0][value]' => 'Published English node', 'langcode[0][value]' => 'en', - 'moderation_state[0]' => 'published' + 'moderation_state[0][state]' => 'published' ]; $this->drupalPostForm('node/add/article', $edit, t('Save')); $this->assertText(t('Article Published English node has been created.')); @@ -64,7 +64,7 @@ public function testTranslateModeratedContent() { $this->clickLink(t('Add')); $edit = [ 'title[0][value]' => 'French node Draft', - 'moderation_state[0]' => 'draft' + 'moderation_state[0][state]' => 'draft' ]; $this->drupalPostForm(NULL, $edit, t('Save (this translation)')); // Here the error has occurred "The website encountered an unexpected error. @@ -76,7 +76,7 @@ public function testTranslateModeratedContent() { $edit = [ 'title[0][value]' => 'English node', 'langcode[0][value]' => 'en', - 'moderation_state[0]' => 'draft', + 'moderation_state[0][state]' => 'draft', ]; $this->drupalPostForm('node/add/article', $edit, t('Save')); $this->assertText(t('Article English node has been created.')); @@ -87,7 +87,7 @@ public function testTranslateModeratedContent() { $this->clickLink(t('Add')); $edit = [ 'title[0][value]' => 'French node', - 'moderation_state[0]' => 'draft' + 'moderation_state[0][state]' => 'draft' ]; $this->drupalPostForm(NULL, $edit, t('Save (this translation)')); $this->assertText(t('Article French node has been updated.')); @@ -96,7 +96,7 @@ public function testTranslateModeratedContent() { // Publish the English article and check that the translation stays // unpublished. $this->drupalPostForm('node/' . $english_node->id() . '/edit', [ - 'moderation_state[0]' => 'published', + 'moderation_state[0][state]' => 'published', ], t('Save (this translation)')); $this->assertText(t('Article English node has been updated.')); $english_node = $this->drupalGetNodeByTitle('English node', TRUE); @@ -112,7 +112,7 @@ public function testTranslateModeratedContent() { // the translation first. $edit = [ 'title[0][value]' => 'Another node', - 'moderation_state[0]' => 'draft', + 'moderation_state[0][state]' => 'draft', ]; $this->drupalPostForm('node/add/article', $edit, t('Save')); $this->assertText(t('Article Another node has been created.')); @@ -123,7 +123,7 @@ public function testTranslateModeratedContent() { $this->clickLink(t('Add')); $edit = [ 'title[0][value]' => 'Translated node', - 'moderation_state[0]' => 'draft', + 'moderation_state[0][state]' => 'draft', ]; $this->drupalPostForm(NULL, $edit, t('Save (this translation)')); $this->assertText(t('Article Translated node has been updated.')); @@ -132,7 +132,7 @@ public function testTranslateModeratedContent() { // Publish the translation and check that the source language version stays // unpublished. $this->drupalPostForm('fr/node/' . $english_node->id() . '/edit', [ - 'moderation_state[0]' => 'published', + 'moderation_state[0][state]' => 'published', ], t('Save (this translation)')); $this->assertText(t('Article Translated node has been updated.')); $english_node = $this->drupalGetNodeByTitle('Another node', TRUE); @@ -145,7 +145,7 @@ public function testTranslateModeratedContent() { // Now check that we can create a new draft of the translation. $edit = [ 'title[0][value]' => 'New draft of translated node', - 'moderation_state[0]' => 'draft', + 'moderation_state[0][state]' => 'draft', ]; $this->drupalPostForm('fr/node/' . $english_node->id() . '/edit', $edit, t('Save (this translation)')); $this->assertText(t('Article New draft of translated node has been updated.')); @@ -169,7 +169,7 @@ public function testTranslateModeratedContent() { // Publish the English article before testing the archive transition. $this->drupalPostForm('node/' . $english_node->id() . '/edit', [ - 'moderation_state[0]' => 'published', + 'moderation_state[0][state]' => 'published', ], t('Save (this translation)')); $this->assertText(t('Article Another node has been updated.')); $english_node = $this->drupalGetNodeByTitle('Another node', TRUE); @@ -177,11 +177,11 @@ public function testTranslateModeratedContent() { // Archive the node and its translation. $this->drupalPostForm('node/' . $english_node->id() . '/edit', [ - 'moderation_state[0]' => 'archived', + 'moderation_state[0][state]' => 'archived', ], t('Save (this translation)')); $this->assertText(t('Article Another node has been updated.')); $this->drupalPostForm('fr/node/' . $english_node->id() . '/edit', [ - 'moderation_state[0]' => 'archived', + 'moderation_state[0][state]' => 'archived', ], t('Save (this translation)')); $this->assertText(t('Article New draft of translated node has been updated.')); $english_node = $this->drupalGetNodeByTitle('Another node', TRUE); @@ -195,7 +195,7 @@ public function testTranslateModeratedContent() { // after creating a forward french revision. $edit = [ 'title[0][value]' => 'An english node', - 'moderation_state[0]' => 'draft', + 'moderation_state[0][state]' => 'draft', ]; $this->drupalPostForm('node/add/article', $edit, t('Save')); $this->assertText(t('Article An english node has been created.')); @@ -207,7 +207,7 @@ public function testTranslateModeratedContent() { $this->clickLink(t('Add')); $edit = [ 'title[0][value]' => 'A french node', - 'moderation_state[0]' => 'published', + 'moderation_state[0][state]' => 'published', ]; $this->drupalPostForm(NULL, $edit, t('Save (this translation)')); $english_node = $this->drupalGetNodeByTitle('An english node', TRUE); @@ -217,7 +217,7 @@ public function testTranslateModeratedContent() { // Create a forward revision $this->drupalPostForm('fr/node/' . $english_node->id() . '/edit', [ - 'moderation_state[0]' => 'draft', + 'moderation_state[0][state]' => 'draft', ], t('Save (this translation)')); $english_node = $this->drupalGetNodeByTitle('An english node', TRUE); $french_node = $english_node->getTranslation('fr'); @@ -227,7 +227,7 @@ public function testTranslateModeratedContent() { // Publish the english node and the default french node not the latest // french node should be used. $this->drupalPostForm('/node/' . $english_node->id() . '/edit', [ - 'moderation_state[0]' => 'published', + 'moderation_state[0][state]' => 'published', ], t('Save (this translation)')); $english_node = $this->drupalGetNodeByTitle('An english node', TRUE); $french_node = $english_node->getTranslation('fr'); diff --git a/core/modules/content_moderation/tests/src/Functional/NodeAccessTest.php b/core/modules/content_moderation/tests/src/Functional/NodeAccessTest.php index facab6f..6849289 100644 --- a/core/modules/content_moderation/tests/src/Functional/NodeAccessTest.php +++ b/core/modules/content_moderation/tests/src/Functional/NodeAccessTest.php @@ -28,7 +28,7 @@ public function testPageAccess() { // Create a node to test with. $this->drupalPostForm('node/add/moderated_content', [ 'title[0][value]' => 'moderated content', - 'moderation_state[0]' => 'draft' + 'moderation_state[0][state]' => 'draft' ], t('Save')); $node = $this->getNodeByTitle('moderated content'); if (!$node) { @@ -41,7 +41,7 @@ public function testPageAccess() { // Publish the node. $this->drupalPostForm($edit_path, [ - 'moderation_state[0]' => 'published' + 'moderation_state[0][state]' => 'published' ], t('Save')); // Ensure access works correctly for anonymous users. @@ -59,7 +59,7 @@ public function testPageAccess() { $this->drupalLogin($this->adminUser); $this->drupalPostForm($edit_path, [ 'title[0][value]' => 'moderated content revised', - 'moderation_state[0]' => 'draft' + 'moderation_state[0][state]' => 'draft' ], t('Save')); // Now make a new user and verify that the new user's access is correct.