mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merge pull request #2352 from mateusz/loadfragment
API Provide a thin alternative to loadPanel/submitForm.
This commit is contained in:
commit
aa9403b5b0
@ -115,7 +115,15 @@ jQuery.noConflict();
|
|||||||
*/
|
*/
|
||||||
$('.cms-container').entwine({
|
$('.cms-container').entwine({
|
||||||
|
|
||||||
CurrentXHR: null,
|
/**
|
||||||
|
* Tracks current panel request.
|
||||||
|
*/
|
||||||
|
StateChangeXHR: null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tracks current fragment-only parallel PJAX requests.
|
||||||
|
*/
|
||||||
|
FragmentXHR: {},
|
||||||
|
|
||||||
StateChangeCount: 0,
|
StateChangeCount: 0,
|
||||||
|
|
||||||
@ -419,7 +427,7 @@ jQuery.noConflict();
|
|||||||
*/
|
*/
|
||||||
handleStateChange: function() {
|
handleStateChange: function() {
|
||||||
// Don't allow parallel loading to avoid edge cases
|
// Don't allow parallel loading to avoid edge cases
|
||||||
if(this.getCurrentXHR()) this.getCurrentXHR().abort();
|
if(this.getStateChangeXHR()) this.getStateChangeXHR().abort();
|
||||||
|
|
||||||
var self = this, h = window.History, state = h.getState(),
|
var self = this, h = window.History, state = h.getState(),
|
||||||
fragments = state.data.pjax || 'Content', headers = {},
|
fragments = state.data.pjax || 'Content', headers = {},
|
||||||
@ -455,7 +463,7 @@ jQuery.noConflict();
|
|||||||
headers: headers,
|
headers: headers,
|
||||||
url: state.url,
|
url: state.url,
|
||||||
complete: function() {
|
complete: function() {
|
||||||
self.setCurrentXHR(null);
|
self.setStateChangeXHR(null);
|
||||||
// Remove loading indication from old content els (regardless of which are replaced)
|
// Remove loading indication from old content els (regardless of which are replaced)
|
||||||
contentEls.removeClass('loading');
|
contentEls.removeClass('loading');
|
||||||
},
|
},
|
||||||
@ -465,7 +473,75 @@ jQuery.noConflict();
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.setCurrentXHR(xhr);
|
this.setStateChangeXHR(xhr);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ALternative to loadPanel/submitForm.
|
||||||
|
*
|
||||||
|
* Triggers a parallel-fetch of a PJAX fragment, which is a separate request to the
|
||||||
|
* state change requests. There could be any amount of these fetches going on in the background,
|
||||||
|
* and they don't register as a HTML5 history states.
|
||||||
|
*
|
||||||
|
* This is meant for updating a PJAX areas that are not complete panel/form reloads. These you'd
|
||||||
|
* normally do via submitForm or loadPanel which have a lot of automation built in.
|
||||||
|
*
|
||||||
|
* On receiving successful response, the framework will update the element tagged with appropriate
|
||||||
|
* data-pjax-fragment attribute (e.g. data-pjax-fragment="<pjax-fragment-name>"). Make sure this element
|
||||||
|
* is available.
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
* $('.cms-container').loadFragment('admin/foobar/', 'FragmentName');
|
||||||
|
*
|
||||||
|
* @param url string Relative or absolute url of the controller.
|
||||||
|
* @param pjaxFragments string PJAX fragment(s), comma separated.
|
||||||
|
*/
|
||||||
|
loadFragment: function(url, pjaxFragments) {
|
||||||
|
|
||||||
|
var self = this,
|
||||||
|
xhr,
|
||||||
|
headers = {},
|
||||||
|
baseUrl = $('base').attr('href'),
|
||||||
|
fragmentXHR = this.getFragmentXHR();
|
||||||
|
|
||||||
|
// Make sure only one XHR for a specific fragment is currently in progress.
|
||||||
|
if(
|
||||||
|
typeof fragmentXHR[pjaxFragments]!=='undefined' &&
|
||||||
|
fragmentXHR[pjaxFragments]!==null
|
||||||
|
) {
|
||||||
|
fragmentXHR[pjaxFragments].abort();
|
||||||
|
fragmentXHR[pjaxFragments] = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
url = $.path.isAbsoluteUrl(url) ? url : $.path.makeUrlAbsolute(url, baseUrl);
|
||||||
|
headers['X-Pjax'] = pjaxFragments;
|
||||||
|
|
||||||
|
xhr = $.ajax({
|
||||||
|
headers: headers,
|
||||||
|
url: url,
|
||||||
|
success: function(data, status, xhr) {
|
||||||
|
var elements = self.handleAjaxResponse(data, status, xhr, null);
|
||||||
|
|
||||||
|
// We are fully done now, make it possible for others to hook in here.
|
||||||
|
self.trigger('afterloadfragment', { data: data, status: status, xhr: xhr, elements: elements });
|
||||||
|
},
|
||||||
|
error: function(xhr, status, error) {
|
||||||
|
self.trigger('loadfragmenterror', { xhr: xhr, status: status, error: error });
|
||||||
|
},
|
||||||
|
complete: function() {
|
||||||
|
// Reset the current XHR in tracking object.
|
||||||
|
var fragmentXHR = self.getFragmentXHR();
|
||||||
|
if(
|
||||||
|
typeof fragmentXHR[pjaxFragments]!=='undefined' &&
|
||||||
|
fragmentXHR[pjaxFragments]!==null
|
||||||
|
) {
|
||||||
|
fragmentXHR[pjaxFragments] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Store the fragment request so we can abort later, should we get a duplicate request.
|
||||||
|
fragmentXHR[pjaxFragments] = xhr;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -287,6 +287,47 @@ tracked in the browser history, use the `pjax` attribute on the state data.
|
|||||||
|
|
||||||
$('.cms-container').loadPanel('admin/pages', null, {pjax: 'Content'});
|
$('.cms-container').loadPanel('admin/pages', null, {pjax: 'Content'});
|
||||||
|
|
||||||
|
## Loading lightweight PJAX fragments
|
||||||
|
|
||||||
|
Normal navigation between URLs in the admin section of the Framework occurs through `loadPanel` and `submitForm`.
|
||||||
|
These calls make sure the HTML5 history is updated correctly and back and forward buttons work. They also take
|
||||||
|
care of some automation, for example restoring currently selected tabs.
|
||||||
|
|
||||||
|
However there are situations when you would like to only update a small area in the CMS, and when this operation should
|
||||||
|
not trigger a browser's history pushState. A good example here is reloading a dropdown that relies on backend session
|
||||||
|
information that could have been updated as part of action elsewhere, updates to sidebar status, or other areas
|
||||||
|
unrelated to the main flow.
|
||||||
|
|
||||||
|
In this case you can use the `loadFragment` call supplied by `LeftAndMain.js`. You can trigger as many of these in
|
||||||
|
parallel as you want. This will not disturb the main navigation.
|
||||||
|
|
||||||
|
$('.cms-container').loadFragment('admin/foobar/', 'Fragment1');
|
||||||
|
$('.cms-container').loadFragment('admin/foobar/', 'Fragment2');
|
||||||
|
$('.cms-container').loadFragment('admin/foobar/', 'Fragment3');
|
||||||
|
|
||||||
|
The ongoing requests are tracked by the PJAX fragment name (Fragment1, 2, and 3 above) - resubmission will
|
||||||
|
result in the prior request for this fragment to be aborted. Other parallel requests will continue undisturbed.
|
||||||
|
|
||||||
|
You can also load multiple fragments in one request, as long as they are to the same controller (i.e. URL):
|
||||||
|
|
||||||
|
$('.cms-container').loadFragment('admin/foobar/', 'Fragment2,Fragment3');
|
||||||
|
|
||||||
|
This counts as a separate request type from the perspective of the request tracking, so will not abort the singular
|
||||||
|
`Fragment2` nor `Fragment3`.
|
||||||
|
|
||||||
|
Upon the receipt of the response, the fragment will be injected into DOM where a matching `data-pjax-fragment` attribute
|
||||||
|
has been found on an element (this element will get completely replaced). Afterwards a `afterloadfragment` event
|
||||||
|
will be triggered. In case of a request error a `loadfragmenterror` will be raised and DOM will not be touched.
|
||||||
|
|
||||||
|
You can hook up a response handler that obtains all the details of the XHR request like this:
|
||||||
|
|
||||||
|
'from .cms-container': {
|
||||||
|
onafterloadfragment: function(e, data) {
|
||||||
|
// Say 'success'!
|
||||||
|
alert(data.status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
## Ajax Redirects
|
## Ajax Redirects
|
||||||
|
|
||||||
Sometimes, a server response represents a new URL state, e.g. when submitting an "add record" form,
|
Sometimes, a server response represents a new URL state, e.g. when submitting an "add record" form,
|
||||||
|
Loading…
Reference in New Issue
Block a user