diff --git a/core/modules/content_moderation/content_moderation.libraries.yml b/core/modules/content_moderation/content_moderation.libraries.yml
index 6caaaf3..377667b 100644
--- a/core/modules/content_moderation/content_moderation.libraries.yml
+++ b/core/modules/content_moderation/content_moderation.libraries.yml
@@ -3,3 +3,8 @@ entity-moderation-form:
css:
layout:
css/entity-moderation-form.css: {}
+moderation-state-widget:
+ version: VERSION
+ css:
+ layout:
+ css/moderation-state-widget.css: {}
diff --git a/core/modules/content_moderation/css/moderation-state-widget.css b/core/modules/content_moderation/css/moderation-state-widget.css
new file mode 100644
index 0000000..edb21de
--- /dev/null
+++ b/core/modules/content_moderation/css/moderation-state-widget.css
@@ -0,0 +1,6 @@
+.field--widget-moderation-state-default label {
+ display: inline;
+}
+.field--widget-moderation-state-default label:after {
+ content: ":";
+}
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 2290dfe..3a2bd45 100644
--- a/core/modules/content_moderation/src/Plugin/Field/FieldWidget/ModerationStateWidget.php
+++ b/core/modules/content_moderation/src/Plugin/Field/FieldWidget/ModerationStateWidget.php
@@ -2,9 +2,7 @@
namespace Drupal\content_moderation\Plugin\Field\FieldWidget;
-use Drupal\Component\Utility\Html;
use Drupal\content_moderation\Plugin\Field\ModerationStateFieldItemList;
-use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemListInterface;
@@ -108,7 +106,7 @@ public static function create(ContainerInterface $container, array $configuratio
* {@inheritdoc}
*/
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
- /** @var ContentEntityInterface $entity */
+ /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
$entity = $items->getEntity();
/* @var \Drupal\Core\Config\Entity\ConfigEntityInterface $bundle_entity */
@@ -119,43 +117,48 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
}
$workflow = $this->moderationInformation->getWorkflowForEntity($entity);
- $default = $items->get($delta)->value ? $workflow->getState($items->get($delta)->value) : $workflow->getInitialState();
- if (!$default) {
+ $current_state = $items->get($delta)->value ? $workflow->getState($items->get($delta)->value) : $workflow->getInitialState();
+ if (!$current_state) {
throw new \UnexpectedValueException(sprintf('The %s bundle has an invalid moderation state configuration, moderation states are enabled but no default is set.', $bundle_entity->label()));
}
/** @var \Drupal\workflows\Transition[] $transitions */
$transitions = $this->validator->getValidTransitions($entity, $this->currentUser);
- $target_states = [];
$transition_labels = [];
+ $default_value = NULL;
foreach ($transitions as $transition) {
- $target_states[$transition->to()->id()] = $transition->to()->label();
- $transition_labels[$transition->to()->id()] = $transition->label();
+ $transition_to_state = $transition->to();
+ if ($transition_to_state->id() === $current_state->id() && !$entity->isNew()) {
+ $default_value = $transition_to_state->id();
+ // Add the default transition to the top of the list.
+ $transition_labels = [
+ $transition_to_state->id() => $this->t('Keep @state', ['@state' => $transition_to_state->label()])
+ ] + $transition_labels;
+ }
+ else {
+ $transition_labels[$transition_to_state->id()] = $transition->label();
+ }
}
- $description_wrapper_id = Html::getUniqueId($this->fieldDefinition->getName() . '-state');
$element += [
'#type' => 'container',
'current' => [
- '#markup' => $this->t('Current moderation state: @current_state', ['@current_state' => $default->label()]),
+ '#type' => 'item',
+ '#title' => $this->t('Current state'),
+ '#markup' => $current_state->label(),
+ '#access' => !$entity->isNew(),
],
'state' => [
'#type' => 'select',
- '#title' => $this->t('New state'),
- '#options' => $target_states,
- '#default_value' => isset($target_states[$default->id()]) ? $default->id() : NULL,
- '#empty_option' => $this->t('- Select new state -'),
+ '#title' => $this->t('On save'),
'#key_column' => $this->column,
- '#transitions' => $transition_labels,
- '#description' => isset($transition_labels[$default->id()]) ? $this->t('
@transition when saved.
', ['@id' => $description_wrapper_id, '@transition' => $transition_labels[$default->id()]]) : '',
- '#ajax' => [
- 'callback' => [get_class($this), 'change'],
- 'event' => 'change',
- 'wrapper' => $description_wrapper_id,
- 'method' => 'html',
- ]
- ]
+ '#options' => $transition_labels,
+ '#default_value' => $default_value,
+ ],
+ '#attached' => [
+ 'library' => ['content_moderation/moderation-state-widget']
+ ],
];
$element['#element_validate'][] = [get_class($this), 'validateElement'];
@@ -163,31 +166,9 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
}
/**
- * Ajax callback for the moderation state field description.
- *
- * @param array $element
- * The form element.
- * @param \Drupal\Core\Form\FormStateInterface $form_state
- * The form state.
- *
- * @return array
- * The render array to use for the field description.
- */
- public static function change(array $element, FormStateInterface $form_state) {
- $field_name = $form_state->getTriggeringElement()['#parents'][0];
- $state = $form_state->getValue($field_name)[0]['value'];
- $transition_labels = $element[$field_name]['widget'][0]['state']['#transitions'];
- return ['#plain_text' => isset($transition_labels[$state]) ? \Drupal::translation()->translate('@transition when saved.', ['@transition' => $transition_labels[$state]]) : ''];
- }
-
- /**
* {@inheritdoc}
*/
public static function validateElement(array $element, FormStateInterface $form_state) {
- if (empty($element['state']['#value'])) {
- $form_state->setError($element, \Drupal::translation()->translate('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 9522c78..1b7e133 100644
--- a/core/modules/content_moderation/src/Tests/ModerationFormTest.php
+++ b/core/modules/content_moderation/src/Tests/ModerationFormTest.php
@@ -2,6 +2,8 @@
namespace Drupal\content_moderation\Tests;
+use Drupal\workflows\Entity\Workflow;
+
/**
* Tests the moderation form, specifically on nodes.
*
@@ -31,7 +33,11 @@ protected function setUp() {
*/
public function testModerationForm() {
// Create new moderated content in draft.
- $this->drupalPostForm('node/add/moderated_content', [
+ $this->drupalGet('node/add/moderated_content');
+ // Since the node is being created there is no current state.
+ $this->assertNoText('Current state:');
+
+ $this->drupalPostForm(NULL, [
'title[0][value]' => 'Some moderated content',
'body[0][value]' => 'First version of the content.',
'moderation_state[0][state]' => 'draft',
@@ -49,18 +55,21 @@ public function testModerationForm() {
$this->drupalGet($latest_version_path);
$this->assertResponse(403);
- // Try saving with no moderation state.
+ // Test what occurs when the current state is not available to transition
+ // to.
+ $workflow = Workflow::load('editorial');
+ $workflow->setTransitionFromStates('create_new_draft', ['published'])->save();
$this->drupalGet($edit_path);
+ $this->assertText('Current state: Draft');
+ $this->assertFieldsByValue($this->xpath('//select[@id="edit-moderation-state-0-state"]'), 'published');
+ $workflow->setTransitionFromStates('create_new_draft', ['draft', 'published'])->save();
+ $this->drupalGet($edit_path);
+ $this->assertText('Current state: 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][state]' => '',
- ], t('Save'));
- $this->assertText('Please select a moderation state.');
+ $this->assertText("Keep Draft");
// Update the draft.
$this->drupalGet($edit_path);
- $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][state]' => 'draft',
@@ -74,6 +83,7 @@ public function testModerationForm() {
// Publish the draft.
$this->drupalGet($edit_path);
$this->assertFieldsByValue($this->xpath('//select[@id="edit-moderation-state-0-state"]'), 'draft');
+ $this->assertText("Keep Draft");
$this->drupalPostForm($edit_path, [
'body[0][value]' => 'Third version of the content.',
'moderation_state[0][state]' => 'published',
@@ -82,6 +92,7 @@ public function testModerationForm() {
// Archive the published entity.
$this->drupalGet($edit_path);
$this->assertFieldsByValue($this->xpath('//select[@id="edit-moderation-state-0-state"]'), 'published');
+ $this->assertText("Keep Published");
$this->drupalPostForm($edit_path, [
'body[0][value]' => 'Fourth version of the content.',
'moderation_state[0][state]' => 'archived',
@@ -89,7 +100,7 @@ public function testModerationForm() {
// 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-state"]'), '');
+ $this->assertFieldsByValue($this->xpath('//select[@id="edit-moderation-state-0-state"]'), 'draft');
$this->drupalPostForm($edit_path, [
'body[0][value]' => 'Fifth version of the content.',
'moderation_state[0][state]' => 'published',