BUGFIX Respecting server-overrides on X-Pjax responses during ajax redirects. Fixes GridFieldDetailForm redirect after delete, e.g. in ModelAdmin. Partially reverts 8b4b896. Closes pull request #488

This commit is contained in:
Ingo Schommer 2012-05-29 11:34:47 +02:00
parent 909c5bd3b1
commit 5b03f49245
5 changed files with 21 additions and 17 deletions

View File

@ -351,6 +351,8 @@ class LeftAndMain extends Controller implements PermissionProvider {
function redirect($url, $code=302) {
if($this->request->isAjax()) {
$this->response->addHeader('X-ControllerURL', $url);
if($header = $this->request->getHeader('X-Pjax')) $this->response->addHeader('X-Pjax', $header);
if($header = $this->request->getHeader('X-Pjax-Selector')) $this->response->addHeader('X-Pjax-Selector', $header);
return ''; // Actual response will be re-requested by client
} else {
parent::redirect($url, $code);

View File

@ -80,18 +80,14 @@
// as automatic browser ajax response redirects seem to discard the hash/fragment.
formData.push({name: 'BackURL', value:History.getPageUrl()});
// Some action buttons are redirecting to content areas as oposed to reloading the form.
// They will have pjax-content class on them.
var pjaxType = 'CurrentForm', pjaxSelector = '.cms-edit-form';
if ($(button).hasClass('pjax-content')) {
pjaxType = 'Content';
pjaxSelector = '.cms-content';
}
// Standard Pjax behaviour is to replace the submitted form with new content.
// The returned view isn't always decided upon when the request
// is fired, so the server might decide to change it based on its own logic,
// sending back different `X-Pjax` headers and content
jQuery.ajax(jQuery.extend({
headers: {
"X-Pjax" : pjaxType,
'X-Pjax-Selector': pjaxSelector
"X-Pjax" : "CurrentForm",
'X-Pjax-Selector': '.cms-edit-form'
},
url: form.attr('action'),
data: formData,

View File

@ -36,13 +36,13 @@ jQuery.noConflict();
$(document).ajaxComplete(function(e, xhr, settings) {
// Simulates a redirect on an ajax response.
if(window.History.enabled) {
var url = xhr.getResponseHeader('X-ControllerURL');
var url = xhr.getResponseHeader('X-ControllerURL'), opts, requestHeaders = settings.headers;
// Normalize trailing slashes in URL to work around routing weirdnesses in SS_HTTPRequest.
var isSame = (url && History.getPageUrl().replace(/\/+$/, '') == url.replace(/\/+$/, ''));
if(url && !isSame) {
var opts = {
pjax: settings.headers ? settings.headers['X-Pjax'] : null,
selector: settings.headers ? settings.headers['X-Pjax-Selector'] : null
opts = {
pjax: xhr.getResponseHeader('X-Pjax') ? xhr.getResponseHeader('X-Pjax') : settings.headers['X-Pjax'],
selector: xhr.getResponseHeader('X-Pjax-Selector') ? xhr.getResponseHeader('X-Pjax-Selector') : settings.headers['X-Pjax-Selector']
};
window.History.pushState(opts, '', url);
}
@ -216,11 +216,14 @@ jQuery.noConflict();
state: state, element: contentEl
});
// Set Pjax headers, which can declare a preference for the returned view.
// The actually returned view isn't always decided upon when the request
// is fired, so the server might decide to change it based on its own logic.
var headers = {};
if(state.data.pjax) {
headers['X-Pjax'] = state.data.pjax;
} else {
// Replace full RHS content area
// Standard Pjax behaviour is to replace right content area
headers["X-Pjax"] = 'Content';
}
headers['X-Pjax-Selector'] = selector;

View File

@ -183,6 +183,9 @@ Within the PHP logic, the `[api:PjaxResponseNegotiator]` class determines which
Through a custom `X-Pjax` HTTP header, the client can declare which view he's expecting,
through identifiers like `CurrentForm` or `Content` (see `[api:LeftAndMain->getResponseNegotiator()]`).
These identifiers are passed to `loadPanel()` via the `pjax` data option.
Keep in mind that the returned view isn't always decided upon when the Ajax request
is fired, so the server might decide to change it based on its own logic,
sending back different `X-Pjax` headers and content.
## Ajax Redirects

View File

@ -291,9 +291,8 @@ class GridFieldDetailForm_ItemRequest extends RequestHandler {
if($this->record->ID !== 0) {
$actions->push(FormAction::create('doSave', _t('GridFieldDetailForm.Save', 'Save'))
->setUseButtonTag(true)->addExtraClass('ss-ui-action-constructive')->setAttribute('data-icon', 'accept'));
// The delete action will redirect, hence pjax-content class.
$actions->push(FormAction::create('doDelete', _t('GridFieldDetailForm.Delete', 'Delete'))
->addExtraClass('ss-ui-action-destructive')->addExtraClass('pjax-content'));
->addExtraClass('ss-ui-action-destructive'));
}else{ // adding new record
//Change the Save label to 'Create'
$actions->push(FormAction::create('doSave', _t('GridFieldDetailForm.Create', 'Create'))
@ -405,6 +404,7 @@ class GridFieldDetailForm_ItemRequest extends RequestHandler {
//when an item is deleted, redirect to the revelant admin section without the action parameter
$controller = Controller::curr();
$noActionURL = $controller->removeAction($data['url']);
$controller->getRequest()->addHeader('X-Pjax', 'Content'); // Force a content refresh
return $controller->redirect($noActionURL, 302); //redirect back to admin section
}