mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
ENHANCEMENT Using native jQuery.getScript() in customized jQuery.ondemand plugin. Moved processDemandHeaders() into jQuery namespace, and adjusted customized prototype.js library
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@92537 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
parent
b661b40865
commit
f60e94b1ca
@ -1,34 +1,18 @@
|
|||||||
/**
|
/**
|
||||||
* 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 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.
|
||||||
*
|
*
|
||||||
* Modified 2009-08-03 by Ingo Schommer, SilverStripe Ltd. - Renamed property "queue" to "ondemand_queue"
|
* IMPORTANT: This plugin monkeypatches the jQuery.ajax() method.
|
||||||
* to make compatible with jQuery 1.3
|
|
||||||
*/
|
*/
|
||||||
(function($){
|
(function($){
|
||||||
|
|
||||||
function isExternalScript(url){
|
|
||||||
re = new RegExp('(http|https)://');
|
|
||||||
return re.test(url);
|
|
||||||
};
|
|
||||||
|
|
||||||
$.extend({
|
$.extend({
|
||||||
|
|
||||||
requireConfig : {
|
|
||||||
// empty default paths give more flexibility and user has
|
|
||||||
routeJs : '',
|
|
||||||
// choice of using this config or full path in scriptUrl argument
|
|
||||||
// previously were useless for users which don't use '_js/' and '_css/' folders. (by PGA)
|
|
||||||
routeCss : ''
|
|
||||||
},
|
|
||||||
|
|
||||||
ondemand_queue : [],
|
|
||||||
pending : null,
|
|
||||||
// loaded files list - to protect against loading existed file again (by PGA)
|
// loaded files list - to protect against loading existed file again (by PGA)
|
||||||
loaded_list : null,
|
_ondemand_loaded_list : null,
|
||||||
|
|
||||||
// Added by SRM: Initialise the loaded_list with the scripts included on first load
|
// Added by SRM: Initialise the loaded_list with the scripts included on first load
|
||||||
initialiseItemLoadedList : function() {
|
initialiseItemLoadedList : function() {
|
||||||
@ -38,7 +22,7 @@
|
|||||||
$('script').each(function() {
|
$('script').each(function() {
|
||||||
if($(this).attr('src')) $this.loaded_list[ $(this).attr('src') ] = 1;
|
if($(this).attr('src')) $this.loaded_list[ $(this).attr('src') ] = 1;
|
||||||
});
|
});
|
||||||
$('link[@rel="stylesheet"]').each(function() {
|
$('link[rel="stylesheet"]').each(function() {
|
||||||
if($(this).attr('href')) $this.loaded_list[ $(this).attr('href') ] = 1;
|
if($(this).attr('href')) $this.loaded_list[ $(this).attr('href') ] = 1;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -48,180 +32,72 @@
|
|||||||
* Returns true if the given CSS or JS script has already been loaded
|
* Returns true if the given CSS or JS script has already been loaded
|
||||||
*/
|
*/
|
||||||
isItemLoaded : function(scriptUrl) {
|
isItemLoaded : function(scriptUrl) {
|
||||||
this.initialiseItemLoadedList();
|
var self = this;
|
||||||
return this.loaded_list[scriptUrl] != undefined;
|
|
||||||
},
|
|
||||||
|
|
||||||
requireJs : function(scriptUrl, callback, opts, obj, scope) {
|
if(this._ondemand_loaded_list == null) {
|
||||||
|
this._ondemand_loaded_list = {};
|
||||||
if(opts != undefined || opts == null){
|
$('script').each(function() {
|
||||||
$.extend($.requireConfig, opts);
|
if($(this).attr('src')) self._ondemand_loaded_list[ $(this).attr('src') ] = 1;
|
||||||
}
|
});
|
||||||
|
$('link[rel="stylesheet"]').each(function() {
|
||||||
var _request = {
|
if($(this).attr('href')) self._ondemand_loaded_list[ $(this).attr('href') ] = 1;
|
||||||
url : scriptUrl,
|
|
||||||
callback : callback,
|
|
||||||
opts : opts,
|
|
||||||
obj : obj,
|
|
||||||
scope : scope
|
|
||||||
}
|
|
||||||
|
|
||||||
if(this.pending) {
|
|
||||||
this.ondemand_queue.push(_request);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.pending = _request;
|
|
||||||
|
|
||||||
this.initialiseItemLoadedList();
|
|
||||||
|
|
||||||
// if required file exists (by PGA)
|
|
||||||
if (this.loaded_list[this.pending.url] != undefined) {
|
|
||||||
// => request complete
|
|
||||||
this.requestComplete();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var _this = this;
|
|
||||||
var _url = (isExternalScript(scriptUrl)) ? scriptUrl : $.requireConfig.routeJs + scriptUrl;
|
|
||||||
var _head = document.getElementsByTagName('head')[0];
|
|
||||||
var _scriptTag = document.createElement('script');
|
|
||||||
|
|
||||||
// Firefox, Opera
|
|
||||||
$(_scriptTag).bind('load', function(){
|
|
||||||
_this.requestComplete();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// IE
|
|
||||||
_scriptTag.onreadystatechange = function(){
|
|
||||||
if(this.readyState === 'loaded' || this.readyState === 'complete'){
|
|
||||||
_this.requestComplete();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_scriptTag.type = "text/javascript";
|
return (this._ondemand_loaded_list[scriptUrl] != undefined);
|
||||||
_scriptTag.src = _url;
|
|
||||||
|
|
||||||
_head.appendChild(_scriptTag);
|
|
||||||
},
|
|
||||||
|
|
||||||
requestComplete : function() {
|
|
||||||
|
|
||||||
if(this.pending.callback){
|
|
||||||
if(this.pending.obj){
|
|
||||||
if(this.pending.scope){
|
|
||||||
this.pending.callback.call(this.pending.obj);
|
|
||||||
} else {
|
|
||||||
this.pending.callback.call(window, this.pending.obj);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.pending.callback.call();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// adding loaded file to loaded list (by PGA)
|
|
||||||
this.loaded_list[this.pending.url] = 1;
|
|
||||||
this.pending = null;
|
|
||||||
|
|
||||||
if(this.ondemand_queue.length > 0) {
|
|
||||||
var request = this.ondemand_queue.shift();
|
|
||||||
this.requireJs(request.url, request.callback, request.opts, request.obj, request.scope);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
requireCss : function(styleUrl, media){
|
requireCss : function(styleUrl, media){
|
||||||
if(media == null) media = 'all';
|
if(media == null) media = 'all';
|
||||||
|
|
||||||
// Don't double up on loading scripts
|
// Don't double up on loading scripts
|
||||||
if(this.isItemLoaded(styleUrl)) return;
|
if($.isItemLoaded(styleUrl)) return;
|
||||||
|
|
||||||
if(document.createStyleSheet){
|
if(document.createStyleSheet){
|
||||||
var ss = document.createStyleSheet($.requireConfig.routeCss + styleUrl);
|
var ss = document.createStyleSheet(styleUrl);
|
||||||
ss.media = media;
|
ss.media = media;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
var styleTag = document.createElement('link');
|
var styleTag = document.createElement('link');
|
||||||
$(styleTag).attr({
|
$(styleTag).attr({
|
||||||
href : $.requireConfig.routeCss + styleUrl,
|
href : styleUrl,
|
||||||
type : 'text/css',
|
type : 'text/css',
|
||||||
media : media,
|
media : media,
|
||||||
rel : 'stylesheet'
|
rel : 'stylesheet'
|
||||||
}).appendTo($('head').get(0));
|
}).appendTo($('head').get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.loaded_list[styleUrl] = 1;
|
this._ondemand_loaded_list[styleUrl] = 1;
|
||||||
|
|
||||||
}
|
},
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sapphire extensions
|
|
||||||
* Ajax requests are amended to look for X-Include-JS and X-Include-CSS headers
|
|
||||||
*/
|
|
||||||
_originalAjax = $.ajax;
|
|
||||||
$.ajax = function(s) {
|
|
||||||
var _complete = s.complete;
|
|
||||||
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.
|
|
||||||
var _ondemandComplete = function(xml) {
|
|
||||||
var status = jQuery.httpSuccess(xml) ? 'success' : 'error';
|
|
||||||
if(status == 'success') {
|
|
||||||
data = jQuery.httpData(xml, _dataType);
|
|
||||||
if(_success) _success(data, status, xml);
|
|
||||||
}
|
|
||||||
if(_complete) _complete(xml, 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, _ondemandComplete);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _originalAjax(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
})(jQuery);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is the on-demand handler used by our patched version of prototype.
|
|
||||||
* once we get rid of all uses of prototype, we can remove this
|
|
||||||
*/
|
|
||||||
function prototypeOnDemandHandler(xml, callback) {
|
|
||||||
processOnDemandHeaders(xml, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
||||||
*/
|
*/
|
||||||
function processOnDemandHeaders(xml, _ondemandComplete) {
|
processOnDemandHeaders: function(xml, status, _ondemandComplete) {
|
||||||
var i;
|
var self = this;
|
||||||
|
|
||||||
// CSS
|
// CSS
|
||||||
if(xml.getResponseHeader('X-Include-CSS')) {
|
if(xml.getResponseHeader('X-Include-CSS')) {
|
||||||
var cssIncludes = xml.getResponseHeader('X-Include-CSS').split(',');
|
var cssIncludes = xml.getResponseHeader('X-Include-CSS').split(',');
|
||||||
for(i=0;i<cssIncludes.length;i++) {
|
for(var i=0;i<cssIncludes.length;i++) {
|
||||||
// Syntax 1: "URL:##:media"
|
// Syntax: "URL:##:media"
|
||||||
if(cssIncludes[i].match(/^(.*):##:(.*)$/)) {
|
if(cssIncludes[i].match(/^(.*):##:(.*)$/)) {
|
||||||
jQuery.requireCss(RegExp.$1, RegExp.$2);
|
$.requireCss(RegExp.$1, RegExp.$2);
|
||||||
|
// Syntax: "URL"
|
||||||
// Syntax 2: "URL"
|
|
||||||
} else {
|
} else {
|
||||||
jQuery.requireCss(cssIncludes[i]);
|
$.requireCss(cssIncludes[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// JavaScript
|
// JavaScript
|
||||||
var newIncludes = [];
|
var newJsIncludes = [];
|
||||||
if(xml.getResponseHeader('X-Include-JS')) {
|
if(xml.getResponseHeader('X-Include-JS')) {
|
||||||
var jsIncludes = xml.getResponseHeader('X-Include-JS').split(',');
|
var jsIncludes = xml.getResponseHeader('X-Include-JS').split(',');
|
||||||
for(i=0;i<jsIncludes.length;i++) {
|
for(var i=0;i<jsIncludes.length;i++) {
|
||||||
if(!jQuery.isItemLoaded(jsIncludes[i])) {
|
if(!$.isItemLoaded(jsIncludes[i])) {
|
||||||
newIncludes.push(jsIncludes[i]);
|
newJsIncludes.push(jsIncludes[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -229,13 +105,66 @@ function processOnDemandHeaders(xml, _ondemandComplete) {
|
|||||||
// We make an array of the includes that are actually new, and attach the callback to the last one
|
// We make an array of the includes that are actually new, and attach the callback to the last one
|
||||||
// They are placed in a queue and will be included in order. This means that the callback will
|
// They are placed in a queue and will be included in order. This means that the callback will
|
||||||
// be able to execute script in the new includes (such as a livequery update)
|
// be able to execute script in the new includes (such as a livequery update)
|
||||||
if(newIncludes.length > 0) {
|
var getScriptQueue = function() {
|
||||||
for(i=0;i<jsIncludes.length;i++) {
|
if(newJsIncludes.length) {
|
||||||
jQuery.requireJs(jsIncludes[i], (i == jsIncludes.length-1) ? function() { _ondemandComplete(xml); } : null);
|
var newJsInclude = newJsIncludes.shift();
|
||||||
}
|
// emulates getScript() with addtl. setting
|
||||||
|
$.ajax({
|
||||||
// If there aren't any new includes, then we can just call the callbacks ourselves
|
dataType: 'script',
|
||||||
|
url: newJsInclude,
|
||||||
|
success: function() {
|
||||||
|
self._ondemand_loaded_list[newJsInclude] = 1;
|
||||||
|
getScriptQueue();
|
||||||
|
},
|
||||||
|
cache: false,
|
||||||
|
// jQuery seems to override the XHR objects if used in async mode
|
||||||
|
async: false
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
_ondemandComplete(xml, status);
|
_ondemandComplete(xml, status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(newJsIncludes.length) {
|
||||||
|
getScriptQueue();
|
||||||
|
} else {
|
||||||
|
// If there aren't any new includes, then we can just call the callbacks ourselves
|
||||||
|
_ondemandComplete(xml, status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ajax requests are amended to look for X-Include-JS and X-Include-CSS headers
|
||||||
|
*/
|
||||||
|
_originalAjax = $.ajax;
|
||||||
|
$.ajax = function(s) {
|
||||||
|
// Avoid recursion in ajax callbacks caused by getScript(), by not parsing
|
||||||
|
// ondemand headers for 'script' datatypes
|
||||||
|
if(s.dataType == 'script') return _originalAjax(s);
|
||||||
|
|
||||||
|
var _complete = s.complete;
|
||||||
|
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.
|
||||||
|
var _ondemandComplete = function(xml, status) {
|
||||||
|
var status = $.httpSuccess(xml) ? 'success' : 'error';
|
||||||
|
if(status == 'success') {
|
||||||
|
var data = jQuery.httpData(xml, _dataType);
|
||||||
|
if(_success) _success(data, status);
|
||||||
|
}
|
||||||
|
if(_complete) _complete(xml, 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);
|
4
thirdparty/prototype/prototype.js
vendored
4
thirdparty/prototype/prototype.js
vendored
@ -852,8 +852,8 @@ Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// jquery ondemand integration patch
|
// jquery ondemand integration patch
|
||||||
if(typeof prototypeOnDemandHandler != 'undefined') {
|
if(typeof jQuery != 'undefined' && typeof jQuery.processOnDemandHeaders != 'undefined') {
|
||||||
prototypeOnDemandHandler(this.transport, completeHandler);
|
jQuery.processOnDemandHeaders(this.transport, prototypeAjax.transport.status, completeHandler);
|
||||||
} else {
|
} else {
|
||||||
completeHandler();
|
completeHandler();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user