diff --git a/core/lib/Drupal/Core/Pager/PagerParameters.php b/core/lib/Drupal/Core/Pager/PagerParameters.php index 9a70c74d1a5bd34748c4ceef4442fcd55100f129..b5b2cf9b71f29ec3921c25737854a923ae4367a2 100644 --- a/core/lib/Drupal/Core/Pager/PagerParameters.php +++ b/core/lib/Drupal/Core/Pager/PagerParameters.php @@ -36,7 +36,7 @@ public function getQueryParameters() { $request = $this->requestStack->getCurrentRequest(); if ($request) { return UrlHelper::filterQueryParameters( - $request->query->all(), ['page'] + $request->query->all(), ['page', 'ajax_page_state'] ); } return []; diff --git a/core/modules/views/src/Controller/ViewAjaxController.php b/core/modules/views/src/Controller/ViewAjaxController.php index 67caeb62b9c28417de0182eb54882b0eea84584b..37bd261b527acd4ef879538420ff44b12a4494fc 100644 --- a/core/modules/views/src/Controller/ViewAjaxController.php +++ b/core/modules/views/src/Controller/ViewAjaxController.php @@ -162,17 +162,21 @@ public function ajaxView(Request $request) { $this->currentPath->setPath('/' . ltrim($path, '/'), $request); } + // Create a clone of the request object to avoid mutating the request + // object stored in the request stack. + $request_clone = clone $request; + // Add all POST data, because AJAX is sometimes a POST and many things, // such as tablesorts, exposed filters and paging assume GET. - $request_all = $request->request->all(); - $query_all = $request->query->all(); - $request->query->replace($request_all + $query_all); + $param_union = $request_clone->request->all() + $request_clone->query->all(); + unset($param_union['ajax_page_state']); + $request_clone->query->replace($param_union); // Overwrite the destination. // @see the redirect.destination service. - $origin_destination = $path; + $origin_destination = $request_clone->getBasePath() . '/' . ltrim($path ?? '/', '/'); - $used_query_parameters = $request->query->all(); + $used_query_parameters = $request_clone->query->all(); $query = UrlHelper::buildQuery($used_query_parameters); if ($query != '') { $origin_destination .= '?' . $query; diff --git a/core/modules/views/src/ViewExecutable.php b/core/modules/views/src/ViewExecutable.php index af976a24569cb1907ab8088f834dcb085d2f4e43..674e12ba62d1fe62987814ea942db87ca11a6b1b 100644 --- a/core/modules/views/src/ViewExecutable.php +++ b/core/modules/views/src/ViewExecutable.php @@ -705,7 +705,7 @@ public function getExposedInput() { $this->exposed_input = \Drupal::request()->query->all(); // unset items that are definitely not our input: - foreach (['page', 'q'] as $key) { + foreach (['page', 'q', 'ajax_page_state'] as $key) { if (isset($this->exposed_input[$key])) { unset($this->exposed_input[$key]); } diff --git a/core/modules/views/tests/src/FunctionalJavascript/PaginationAJAXTest.php b/core/modules/views/tests/src/FunctionalJavascript/PaginationAJAXTest.php index d4a73743320da151f98a609b3f17c18ab9338a36..758a8a4676a983bbc1db19464cbca4c666b86c48 100644 --- a/core/modules/views/tests/src/FunctionalJavascript/PaginationAJAXTest.php +++ b/core/modules/views/tests/src/FunctionalJavascript/PaginationAJAXTest.php @@ -100,6 +100,9 @@ public function testBasicPagination() { $link = $page->findLink('Go to page 3'); $this->assertNoDuplicateAssetsOnPage(); + // Test that no unwanted parameters are added to the URL. + $this->assertEquals('?status=All&type=All&langcode=All&items_per_page=5&order=changed&sort=asc&page=2', $link->getAttribute('href')); + $this->clickLink('Go to page 3'); $session_assert->assertWaitOnAjaxRequest(); $rows = $page->findAll('css', 'tbody tr'); diff --git a/core/modules/views/tests/src/FunctionalJavascript/RedirectAjaxTest.php b/core/modules/views/tests/src/FunctionalJavascript/RedirectAjaxTest.php new file mode 100644 index 0000000000000000000000000000000000000000..c07f72446b11f9bae00c8e03a2c402bf2aa62e01 --- /dev/null +++ b/core/modules/views/tests/src/FunctionalJavascript/RedirectAjaxTest.php @@ -0,0 +1,76 @@ +<?php + +namespace Drupal\Tests\views\FunctionalJavascript; + +use Drupal\FunctionalJavascriptTests\WebDriverTestBase; +use Drupal\Tests\node\Traits\ContentTypeCreationTrait; +use Drupal\Tests\node\Traits\NodeCreationTrait; + +/** + * Tests that the redirects work with Ajax enabled views. + * + * @group views + */ +class RedirectAjaxTest extends WebDriverTestBase { + + use ContentTypeCreationTrait; + use NodeCreationTrait; + + /** + * {@inheritdoc} + */ + protected static $modules = ['node', 'views']; + + /** + * {@inheritdoc} + */ + protected $defaultTheme = 'stark'; + + /** + * {@inheritdoc} + */ + protected function setUp(): void { + parent::setUp(); + + // Enable AJAX on the /admin/content View. + \Drupal::configFactory()->getEditable('views.view.content') + ->set('display.default.display_options.use_ajax', TRUE) + ->save(); + + $this->createContentType(['type' => 'article']); + $this->createNode(['title' => 'Tiny paws and playful mews, kittens bring joy in every hue', 'type' => 'article']); + + $user = $this->drupalCreateUser([ + 'access content overview', + 'administer nodes', + 'bypass node access', + ]); + $this->drupalLogin($user); + } + + /** + * Ensures that redirects work with ajax. + */ + public function testRedirectWithAjax() { + $this->drupalGet('admin/content'); + $original_url = $this->getSession()->getCurrentUrl(); + + $this->assertSession()->pageTextContains('Tiny paws and playful mews, kittens bring joy in every hue'); + + $this->submitForm(['title' => 'Kittens'], 'Filter'); + $this->assertSession()->assertWaitOnAjaxRequest(); + + $this->assertSession()->pageTextContains('Tiny paws and playful mews, kittens bring joy in every hue'); + $this->getSession()->getPage()->find('css', '.dropbutton-toggle button')->click(); + $this->clickLink('Delete'); + $this->assertSession()->assertWaitOnAjaxRequest(); + + $this->assertEquals('Are you sure you want to delete the content item Tiny paws and playful mews, kittens bring joy in every hue?', $this->assertSession()->waitForElement('css', '.ui-dialog-title')->getText()); + $this->getSession()->getPage()->find('css', '.ui-dialog-buttonset')->pressButton('Delete'); + + $this->assertSession()->pageTextContains('The Article Tiny paws and playful mews, kittens bring joy in every hue has been deleted.'); + $this->assertStringStartsWith($original_url, $this->getSession()->getCurrentUrl()); + $this->assertSession()->responseContains('core/modules/views/css/views.module.css'); + } + +} diff --git a/core/modules/views/tests/src/Unit/Controller/ViewAjaxControllerTest.php b/core/modules/views/tests/src/Unit/Controller/ViewAjaxControllerTest.php index a455b74257dd26cf861d6662927c1769ee2e2ba3..1d07ee94f38c6aabaf758c83eb68f266638cf03a 100644 --- a/core/modules/views/tests/src/Unit/Controller/ViewAjaxControllerTest.php +++ b/core/modules/views/tests/src/Unit/Controller/ViewAjaxControllerTest.php @@ -195,7 +195,7 @@ public function testAjaxView() { $this->redirectDestination->expects($this->atLeastOnce()) ->method('set') - ->with('/test-page?ajax_page_state=drupal.settings%5B%5D&type=article'); + ->with('/test-page?type=article'); $this->currentPath->expects($this->once()) ->method('setPath') ->with('/test-page', $request); @@ -224,7 +224,7 @@ public function testAjaxViewViewPathNoSlash() { $this->redirectDestination->expects($this->atLeastOnce()) ->method('set') - ->with('test-page?ajax_page_state=drupal.settings%5B%5D&type=article'); + ->with('/test-page?type=article'); $this->currentPath->expects($this->once()) ->method('setPath') ->with('/test-page');