BUGFIX jQuery 1.5 compatibility for jQuery.ondemand, by using jQuery.Deferred and the 'beforeSend' callback instead of monkeypatching jQuery.ajax

This commit is contained in:
Ingo Schommer 2011-03-01 17:39:12 +13:00
parent 31d7a00eb7
commit c6af46f066

View File

@ -1,11 +1,17 @@
/** /**
* On-demand JavaScript handler * On-demand JavaScript handler
*
* Based on http://plugins.jquery.com/files/issues/jquery.ondemand.js_.txt * Based on http://plugins.jquery.com/files/issues/jquery.ondemand.js_.txt
* and heavily modified to integrate with SilverStripe and prototype.js. * and heavily modified to integrate with SilverStripe and prototype.js.
* Adds capabilities for custom X-Include-CSS and X-Include-JS HTTP headers * Adds capabilities for custom X-Include-CSS and X-Include-JS HTTP headers
* to request loading of externals alongside an ajax response. * to request loading of externals alongside an ajax response.
* *
* IMPORTANT: This plugin monkeypatches the jQuery.ajax() method. * Requires jQuery 1.5 ($.Deferred support)
*
* CAUTION: Relies on customization of the 'beforeSend' callback in jQuery.ajaxSetup()
*
* @author Ingo Schommer (ingo at silverstripe dot com)
* @author Sam Minnee (sam at silverstripe dot com)
*/ */
(function($){ (function($){
@ -74,12 +80,12 @@
/** /**
* Process the X-Include-CSS and X-Include-JS headers provided by the Requirements class * Process the X-Include-CSS and X-Include-JS headers provided by the Requirements class
*/ */
processOnDemandHeaders: function(xml, status, _ondemandComplete) { processOnDemandHeaders: function(xml, status, xhr) {
var self = this; var self = this, processDfd = new $.Deferred();
// CSS // CSS
if(xml.getResponseHeader('X-Include-CSS')) { if(xhr.getResponseHeader('X-Include-CSS')) {
var cssIncludes = xml.getResponseHeader('X-Include-CSS').split(','); var cssIncludes = xhr.getResponseHeader('X-Include-CSS').split(',');
for(var i=0;i<cssIncludes.length;i++) { for(var i=0;i<cssIncludes.length;i++) {
// Syntax: "URL:##:media" // Syntax: "URL:##:media"
if(cssIncludes[i].match(/^(.*):##:(.*)$/)) { if(cssIncludes[i].match(/^(.*):##:(.*)$/)) {
@ -93,8 +99,8 @@
// JavaScript // JavaScript
var newJsIncludes = []; var newJsIncludes = [];
if(xml.getResponseHeader('X-Include-JS')) { if(xhr.getResponseHeader('X-Include-JS')) {
var jsIncludes = xml.getResponseHeader('X-Include-JS').split(','); var jsIncludes = xhr.getResponseHeader('X-Include-JS').split(',');
for(var i=0;i<jsIncludes.length;i++) { for(var i=0;i<jsIncludes.length;i++) {
if(!$.isItemLoaded(jsIncludes[i])) { if(!$.isItemLoaded(jsIncludes[i])) {
newJsIncludes.push(jsIncludes[i]); newJsIncludes.push(jsIncludes[i]);
@ -121,7 +127,7 @@
async: false async: false
}); });
} else { } else {
_ondemandComplete(xml, status); processDfd.resolve(xml, status, xhr);
} }
} }
@ -129,44 +135,38 @@
getScriptQueue(); getScriptQueue();
} else { } else {
// If there aren't any new includes, then we can just call the callbacks ourselves // If there aren't any new includes, then we can just call the callbacks ourselves
_ondemandComplete(xml, status); processDfd.resolve(xml, status, xhr);
} }
return processDfd.promise();
} }
}); });
/** $.ajaxSetup({
* Ajax requests are amended to look for X-Include-JS and X-Include-CSS headers // beforeSend is the only place to access the XHR object before success handlers are added
*/ beforeSend: function(jqXHR, s) {
_originalAjax = $.ajax;
$.ajax = function(s) {
// Avoid recursion in ajax callbacks caused by getScript(), by not parsing // Avoid recursion in ajax callbacks caused by getScript(), by not parsing
// ondemand headers for 'script' datatypes // ondemand headers for 'script' datatypes
if(s.dataType == 'script') return _originalAjax(s); if(s.dataType == 'script') return;
var _complete = s.complete; var dfd = new $.Deferred();
var _success = s.success;
var _dataType = s.dataType;
// This replaces the usual ajax success & complete handlers. They are called after any on demand JS is loaded. // Register our own success handler (assumes no handlers are already registered)
var _ondemandComplete = function(data, status) { // 'success' is an alias for 'done', which is executed by the built-in deferred instance in $.ajax()
//var status = $.httpSuccess(xml) ? 'success' : 'error'; //rewrote success function as httpSuccess doesn't exist anymore in jQuery 1.5 jqXHR.success(function(success, statusText, jXHR) {
if (typeof status == 'undefined' || status != 'success') status = 'error'; $.processOnDemandHeaders(success, statusText, jXHR).done(function() {
dfd.resolveWith(s.context || this, [success, statusText, jXHR]);
});
});
if(status == 'success') { // Reroute all external success hanlders through our own deferred.
//var data = jQuery.httpData(xml, _dataType); //unnecessary as data type conversion is automatically done in jQuery 1.5 using the ajaxConvert method // Not overloading fail() as no event can cause the original request to fail.
if(_success) _success(data, status); jqXHR.success = function(callback) {
dfd.done(callback);
} }
if(_complete) _complete(data, status);
} }
});
// We remove the success handler and take care of calling it outselves within _ondemandComplete
s.success = null;
s.complete = function(xml, status) {
$.processOnDemandHeaders(xml, status, _ondemandComplete);
}
return _originalAjax(s);
}
})(jQuery); })(jQuery);