diff --git a/core/modules/node/src/NodeViewBuilder.php b/core/modules/node/src/NodeViewBuilder.php index f4243b2e679876ef989858f3dc66a76d3cc72c5e..c65250ee9082a48b9bda8a5508bbcc2cf9a32a78 100644 --- a/core/modules/node/src/NodeViewBuilder.php +++ b/core/modules/node/src/NodeViewBuilder.php @@ -146,10 +146,21 @@ protected function alterBuild(array &$build, EntityInterface $entity, EntityView /** @var \Drupal\node\NodeInterface $entity */ parent::alterBuild($build, $entity, $display, $view_mode); if ($entity->id()) { - $build['#contextual_links']['node'] = array( - 'route_parameters' => array('node' => $entity->id()), - 'metadata' => array('changed' => $entity->getChangedTime()), - ); + if ($entity->isDefaultRevision()) { + $build['#contextual_links']['node'] = [ + 'route_parameters' => ['node' => $entity->id()], + 'metadata' => ['changed' => $entity->getChangedTime()], + ]; + } + else { + $build['#contextual_links']['node_revision'] = [ + 'route_parameters' => [ + 'node' => $entity->id(), + 'node_revision' => $entity->getRevisionId(), + ], + 'metadata' => ['changed' => $entity->getChangedTime()], + ]; + } } } diff --git a/core/modules/node/src/Tests/NodeRevisionsTest.php b/core/modules/node/src/Tests/NodeRevisionsTest.php index 40f2a40290dfe581573a40d8b5b2136609986de3..bfdd213f4100bb161f523942ac84353ab2e2f34d 100644 --- a/core/modules/node/src/Tests/NodeRevisionsTest.php +++ b/core/modules/node/src/Tests/NodeRevisionsTest.php @@ -8,6 +8,7 @@ use Drupal\language\Entity\ConfigurableLanguage; use Drupal\node\Entity\Node; use Drupal\node\NodeInterface; +use Drupal\Component\Serialization\Json; /** * Create a node with revisions and test viewing, saving, reverting, and @@ -34,7 +35,7 @@ class NodeRevisionsTest extends NodeTestBase { /** * {@inheritdoc} */ - public static $modules = array('node', 'datetime', 'language', 'content_translation'); + public static $modules = ['node', 'contextual', 'datetime', 'language', 'content_translation']; /** * {@inheritdoc} @@ -71,6 +72,7 @@ protected function setUp() { 'delete page revisions', 'edit any page content', 'delete any page content', + 'access contextual links', 'translate any entity', 'administer content types', ) @@ -152,6 +154,18 @@ function testRevisions() { // Confirm that this is the default revision. $this->assertTrue($node->isDefaultRevision(), 'Third node revision is the default one.'); + // Confirm that the "Edit" and "Delete" contextual links appear for the + // default revision. + $ids = ['node:node=' . $node->id() . ':changed=' . $node->getChangedTime()]; + $json = $this->renderContextualLinks($ids, 'node/' . $node->id()); + $this->verbose($json[$ids[0]]); + + $expected = '
  • Edit
  • '; + $this->assertTrue(strstr($json[$ids[0]], $expected), 'The "Edit" contextual link is shown for the default revision.'); + $expected = '
  • Delete
  • '; + $this->assertTrue(strstr($json[$ids[0]], $expected), 'The "Delete" contextual link is shown for the default revision.'); + + // Confirm that revisions revert properly. $this->drupalPostForm("node/" . $node->id() . "/revisions/" . $nodes[1]->getRevisionid() . "/revert", array(), t('Revert')); $this->assertRaw(t('@type %title has been reverted to the revision from %revision-date.', @@ -165,6 +179,16 @@ function testRevisions() { $node = node_revision_load($node->getRevisionId()); $this->assertFalse($node->isDefaultRevision(), 'Third node revision is not the default one.'); + // Confirm that "Edit" and "Delete" contextual links don't appear for + // non-default revision. + $ids = ['node_revision::node=' . $node->id() . '&node_revision=' . $node->getRevisionId() . ':']; + $json = $this->renderContextualLinks($ids, 'node/' . $node->id() . '/revisions/' . $node->getRevisionId() . '/view'); + $this->verbose($json[$ids[0]]); + + $this->assertFalse(strstr($json[$ids[0]], '
  • '), 'The "Edit" contextual link is not shown for a non-default revision.'); + $this->assertFalse(strstr($json[$ids[0]], '
  • '), 'The "Delete" contextual link is not shown for a non-default revision.'); + + // Confirm revisions delete properly. $this->drupalPostForm("node/" . $node->id() . "/revisions/" . $nodes[1]->getRevisionId() . "/delete", array(), t('Delete')); $this->assertRaw(t('Revision from %revision-date of @type %title has been deleted.', @@ -317,6 +341,27 @@ function testNodeRevisionWithoutLogMessage() { $this->assertTrue(empty($node_revision->revision_log->value), 'After a new node revision is saved with an empty log message, the log message for the node is empty.'); } + /** + * Gets server-rendered contextual links for the given contextual links IDs. + * + * @param string[] $ids + * An array of contextual link IDs. + * @param string $current_path + * The Drupal path for the page for which the contextual links are rendered. + * + * @return string + * The decoded JSON response body. + */ + protected function renderContextualLinks(array $ids, $current_path) { + $post = array(); + for ($i = 0; $i < count($ids); $i++) { + $post['ids[' . $i . ']'] = $ids[$i]; + } + $response = $this->drupalPost('contextual/render', 'application/json', $post, ['query' => ['destination' => $current_path]]); + + return Json::decode($response); + } + /** * Tests the revision translations are correctly reverted. */