Issue #956186 by catch, dpolant, SteffenR, yhahn, lauriii, nod_, sokrplare, rwaery.11, Supreetam09, effulgentsia, geek-merlin: Allow AJAX to use GET requests

merge-requests/3445/merge
Lauri Eskola 2023-04-07 12:48:30 +03:00
parent d4b5939879
commit 29763eaaf5
No known key found for this signature in database
GPG Key ID: 382FC0F5B0DF53F8
11 changed files with 52 additions and 50 deletions

View File

@ -132,7 +132,7 @@ class AjaxResponseAttachmentsProcessor implements AttachmentsResponseProcessorIn
* An array of commands ready to be returned as JSON.
*/
protected function buildAttachmentsCommands(AjaxResponse $response, Request $request) {
$ajax_page_state = $request->request->all('ajax_page_state');
$ajax_page_state = $request->get('ajax_page_state');
// Aggregate CSS/JS if necessary, but only during normal site operation.
$optimize_css = !defined('MAINTENANCE_MODE') && $this->config->get('css.preprocess');

View File

@ -244,6 +244,7 @@ abstract class RenderElement extends PluginBase implements ElementInterface {
* - #ajax['event']
* - #ajax['prevent']
* - #ajax['url']
* - #ajax['type']
* - #ajax['callback']
* - #ajax['options']
* - #ajax['wrapper']
@ -340,6 +341,7 @@ abstract class RenderElement extends PluginBase implements ElementInterface {
// to be substantially different for a JavaScript triggered submission.
$settings += [
'url' => NULL,
'type' => 'POST',
'options' => ['query' => []],
'dialogType' => 'ajax',
];

View File

@ -65,7 +65,7 @@ class AjaxBasePageNegotiator implements ThemeNegotiatorInterface {
* {@inheritdoc}
*/
public function applies(RouteMatchInterface $route_match) {
$ajax_page_state = $this->requestStack->getCurrentRequest()->request->all('ajax_page_state');
$ajax_page_state = $this->requestStack->getCurrentRequest()->get('ajax_page_state');
return !empty($ajax_page_state['theme']) && isset($ajax_page_state['theme_token']);
}
@ -73,7 +73,7 @@ class AjaxBasePageNegotiator implements ThemeNegotiatorInterface {
* {@inheritdoc}
*/
public function determineActiveTheme(RouteMatchInterface $route_match) {
$ajax_page_state = $this->requestStack->getCurrentRequest()->request->all('ajax_page_state');
$ajax_page_state = $this->requestStack->getCurrentRequest()->get('ajax_page_state');
$theme = $ajax_page_state['theme'];
$token = $ajax_page_state['theme_token'];

View File

@ -325,6 +325,13 @@
elementSettings.url = href;
elementSettings.event = 'click';
}
const type = $linkElement.data('ajax-type');
/**
* In case of setting custom ajax type for link we rewrite ajax.type.
*/
if (type) {
elementSettings.type = type;
}
Drupal.ajax(elementSettings);
});
};
@ -391,6 +398,7 @@
*/
Drupal.Ajax = function (base, element, elementSettings) {
const defaults = {
type: 'POST',
event: element ? 'mousedown' : null,
keypress: true,
selector: base ? `#${base}` : null,
@ -591,7 +599,7 @@
},
dataType: 'json',
jsonp: false,
type: 'POST',
type: ajax.type,
};
if (elementSettings.dialog) {

View File

@ -465,7 +465,7 @@ class BigPipe {
// - the HTML to load the CSS can be rendered.
// - the HTML to load the JS (at the top) can be rendered.
$fake_request = $this->requestStack->getMainRequest()->duplicate();
$fake_request->request->set('ajax_page_state', ['libraries' => implode(',', $cumulative_assets->getAlreadyLoadedLibraries())]);
$fake_request->query->set('ajax_page_state', ['libraries' => implode(',', $cumulative_assets->getAlreadyLoadedLibraries())]);
try {
$html_response = $this->filterEmbeddedResponse($fake_request, $html_response);
}
@ -575,7 +575,7 @@ class BigPipe {
// - the attachments associated with the response are finalized, which
// allows us to track the total set of asset libraries sent in the
// initial HTML response plus all embedded AJAX responses sent so far.
$fake_request->request->set('ajax_page_state', ['libraries' => implode(',', $cumulative_assets->getAlreadyLoadedLibraries())] + $cumulative_assets->getSettings()['ajaxPageState']);
$fake_request->query->set('ajax_page_state', ['libraries' => implode(',', $cumulative_assets->getAlreadyLoadedLibraries())] + $cumulative_assets->getSettings()['ajaxPageState']);
try {
$ajax_response = $this->filterEmbeddedResponse($fake_request, $ajax_response);
}

View File

@ -90,6 +90,7 @@
this.element_settings = {
url: ajaxPath + queryString,
submit: settings,
type: 'GET',
setClick: true,
event: 'click',
selector,
@ -127,6 +128,7 @@
const selfSettings = $.extend({}, this.element_settings, {
event: 'RefreshView',
base: this.selector,
type: 'GET',
element: this.$view.get(0),
});
this.refreshViewAjax = Drupal.ajax(selfSettings);
@ -201,6 +203,7 @@
submit: viewData,
base: false,
element: link,
type: 'GET',
});
this.pagerAjax = Drupal.ajax(selfSettings);
};

View File

@ -12,8 +12,6 @@ use Drupal\Core\EventSubscriber\AjaxResponseSubscriber;
use Drupal\Core\EventSubscriber\MainContentViewSubscriber;
use Drupal\Core\Form\FormBuilderInterface;
use Drupal\Core\Path\CurrentPathStack;
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\Core\Render\RenderContext;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Routing\RedirectDestinationInterface;
use Drupal\Core\Ajax\ScrollTopCommand;
@ -112,10 +110,10 @@ class ViewAjaxController implements ContainerInjectionInterface {
* Thrown when the view was not found.
*/
public function ajaxView(Request $request) {
$name = $request->request->get('view_name');
$display_id = $request->request->get('view_display_id');
$name = $request->get('view_name');
$display_id = $request->get('view_display_id');
if (isset($name) && isset($display_id)) {
$args = $request->request->get('view_args', '');
$args = $request->get('view_args', '');
$args = $args !== '' ? explode('/', Html::decodeEntities($args)) : [];
// Arguments can be empty, make sure they are passed on as NULL so that
@ -124,10 +122,10 @@ class ViewAjaxController implements ContainerInjectionInterface {
return ($arg == '' ? NULL : $arg);
}, $args);
$path = $request->request->get('view_path');
$dom_id = $request->request->get('view_dom_id');
$path = $request->get('view_path');
$dom_id = $request->get('view_dom_id');
$dom_id = isset($dom_id) ? preg_replace('/[^a-zA-Z0-9_-]+/', '-', $dom_id) : NULL;
$pager_element = $request->request->get('pager_element');
$pager_element = $request->get('pager_element');
$pager_element = isset($pager_element) ? intval($pager_element) : NULL;
$response = new ViewAjaxResponse();
@ -164,10 +162,9 @@ class ViewAjaxController implements ContainerInjectionInterface {
$this->currentPath->setPath('/' . ltrim($path, '/'), $request);
}
// Add all POST data, because AJAX is always a post and many things,
// 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();
unset($request_all['ajax_page_state']);
$query_all = $request->query->all();
$request->query->replace($request_all + $query_all);
@ -190,16 +187,7 @@ class ViewAjaxController implements ContainerInjectionInterface {
// Reuse the same DOM id so it matches that in drupalSettings.
$view->dom_id = $dom_id;
$context = new RenderContext();
$preview = $this->renderer->executeInRenderContext($context, function () use ($view, $display_id, $args) {
return $view->preview($display_id, $args);
});
if (!$context->isEmpty()) {
$bubbleable_metadata = $context->pop();
BubbleableMetadata::createFromRenderArray($preview)
->merge($bubbleable_metadata)
->applyTo($preview);
}
$preview = $view->preview($display_id, $args);
$response->addCommand(new ReplaceCommand(".js-view-dom-id-$dom_id", $preview));
$response->addCommand(new PrependCommand(".js-view-dom-id-$dom_id", ['#type' => 'status_messages']));

View File

@ -157,7 +157,7 @@ class ViewsForm implements FormInterface, ContainerInjectionInterface {
$form = [];
$query = $this->requestStack->getCurrentRequest()->query->all();
$query = UrlHelper::filterQueryParameters($query, [], '');
$query = UrlHelper::filterQueryParameters($query, ['_wrapper_format'], '');
$options = ['query' => $query];
$form['#action'] = $view->hasUrl() ? $view->getUrl()->setOptions($options)->toString() : Url::fromRoute('<current>')->setOptions($options)->toString();

View File

@ -98,8 +98,6 @@ class PaginationAJAXTest extends WebDriverTestBase {
$this->assertCount(5, $rows);
$this->assertStringContainsString('Node 6 content', $rows[0]->getHtml());
$link = $page->findLink('Go to page 3');
// 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->assertNoDuplicateAssetsOnPage();
$this->clickLink('Go to page 3');

View File

@ -182,18 +182,18 @@ class ViewAjaxControllerTest extends UnitTestCase {
*/
public function testAjaxView() {
$request = new Request();
$request->request->set('view_name', 'test_view');
$request->request->set('view_display_id', 'page_1');
$request->request->set('view_path', '/test-page');
$request->request->set('_wrapper_format', 'ajax');
$request->request->set('ajax_page_state', 'drupal.settings[]');
$request->request->set('type', 'article');
$request->query->set('view_name', 'test_view');
$request->query->set('view_display_id', 'page_1');
$request->query->set('view_path', '/test-page');
$request->query->set('_wrapper_format', 'ajax');
$request->query->set('ajax_page_state', 'drupal.settings[]');
$request->query->set('type', 'article');
[$view, $executable] = $this->setupValidMocks();
$this->redirectDestination->expects($this->atLeastOnce())
->method('set')
->with('/test-page?type=article');
->with('/test-page?ajax_page_state=drupal.settings%5B%5D&type=article');
$this->currentPath->expects($this->once())
->method('setPath')
->with('/test-page', $request);
@ -211,18 +211,18 @@ class ViewAjaxControllerTest extends UnitTestCase {
*/
public function testAjaxViewViewPathNoSlash() {
$request = new Request();
$request->request->set('view_name', 'test_view');
$request->request->set('view_display_id', 'page_1');
$request->request->set('view_path', 'test-page');
$request->request->set('_wrapper_format', 'ajax');
$request->request->set('ajax_page_state', 'drupal.settings[]');
$request->request->set('type', 'article');
$request->query->set('view_name', 'test_view');
$request->query->set('view_display_id', 'page_1');
$request->query->set('view_path', 'test-page');
$request->query->set('_wrapper_format', 'ajax');
$request->query->set('ajax_page_state', 'drupal.settings[]');
$request->query->set('type', 'article');
[$view, $executable] = $this->setupValidMocks();
$this->redirectDestination->expects($this->atLeastOnce())
->method('set')
->with('test-page?type=article');
->with('test-page?ajax_page_state=drupal.settings%5B%5D&type=article');
$this->currentPath->expects($this->once())
->method('setPath')
->with('/test-page');

View File

@ -55,8 +55,10 @@ class AjaxBasePageNegotiatorTest extends UnitTestCase {
* @dataProvider providerTestApplies
*/
public function testApplies($request_data, $expected) {
$request = new Request([], $request_data);
$request->request = new InputBag($request->request->all());
$request = new Request();
foreach ($request_data as $key => $data) {
$request->query->set($key, $data);
}
$route_match = RouteMatch::createFromRequest($request);
$this->requestStack->push($request);
@ -80,8 +82,8 @@ class AjaxBasePageNegotiatorTest extends UnitTestCase {
$theme = 'claro';
$theme_token = 'valid_theme_token';
$request = new Request([], ['ajax_page_state' => ['theme' => $theme, 'theme_token' => $theme_token]]);
$request->request = new InputBag($request->request->all());
$request = new Request();
$request->query->set('ajax_page_state', ['theme' => $theme, 'theme_token' => $theme_token]);
$this->requestStack->push($request);
$route_match = RouteMatch::createFromRequest($request);
@ -97,8 +99,8 @@ class AjaxBasePageNegotiatorTest extends UnitTestCase {
public function testDetermineActiveThemeInvalidToken() {
$theme = 'claro';
$theme_token = 'invalid_theme_token';
$request = new Request([], ['ajax_page_state' => ['theme' => $theme, 'theme_token' => $theme_token]]);
$request = new Request();
$request->query->set('ajax_page_state', ['theme' => $theme, 'theme_token' => $theme_token]);
$request->request = new InputBag($request->request->all());
$this->requestStack->push($request);
$route_match = RouteMatch::createFromRequest($request);
@ -118,7 +120,8 @@ class AjaxBasePageNegotiatorTest extends UnitTestCase {
// theme token. See system_js_settings_alter().
$theme_token = '';
$request = new Request([], ['ajax_page_state' => ['theme' => $theme, 'theme_token' => $theme_token]]);
$request = new Request([]);
$request->query->set('ajax_page_state', ['theme' => $theme, 'theme_token' => $theme_token]);
$request->request = new InputBag($request->request->all());
$this->requestStack->push($request);
$route_match = RouteMatch::createFromRequest($request);