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({
|
||||
|
||||
CurrentXHR: null,
|
||||
/**
|
||||
* Tracks current panel request.
|
||||
*/
|
||||
StateChangeXHR: null,
|
||||
|
||||
/**
|
||||
* Tracks current fragment-only parallel PJAX requests.
|
||||
*/
|
||||
FragmentXHR: {},
|
||||
|
||||
StateChangeCount: 0,
|
||||
|
||||
@ -419,7 +427,7 @@ jQuery.noConflict();
|
||||
*/
|
||||
handleStateChange: function() {
|
||||
// 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(),
|
||||
fragments = state.data.pjax || 'Content', headers = {},
|
||||
@ -455,7 +463,7 @@ jQuery.noConflict();
|
||||
headers: headers,
|
||||
url: state.url,
|
||||
complete: function() {
|
||||
self.setCurrentXHR(null);
|
||||
self.setStateChangeXHR(null);
|
||||
// Remove loading indication from old content els (regardless of which are replaced)
|
||||
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'});
|
||||
|
||||
## 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
|
||||
|
||||
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