extend egw.includeJS to support concatinated/bundled files included and not include contained files again

This commit is contained in:
Ralf Becker 2014-01-11 12:10:31 +00:00
parent 52ab3203bd
commit ab490eadc1

View File

@ -21,18 +21,13 @@
/** /**
* @augments Class * @augments Class
*/ */
egw.extend('files', egw.MODULE_WND_LOCAL, function(_app, _wnd) egw.extend('files', egw.MODULE_WND_LOCAL, function(_app, _wnd)
{ {
var egw = this; var egw = this;
/**
* Array which contains all currently bound in javascript and css files.
*/
var files = {};
/** /**
* Remove optional timestamp attached directly as first query parameter, eg. /path/name.js?12345678[&other=val] * Remove optional timestamp attached directly as first query parameter, eg. /path/name.js?12345678[&other=val]
* *
* Examples: * Examples:
* /path/file.js --> /path/file.js * /path/file.js --> /path/file.js
* /path/file.js?123456 --> /path/file.js * /path/file.js?123456 --> /path/file.js
@ -46,57 +41,171 @@ egw.extend('files', egw.MODULE_WND_LOCAL, function(_app, _wnd)
return _src.replace(/\?[0-9]+&?/, '?').replace(/\?$/, ''); return _src.replace(/\?[0-9]+&?/, '?').replace(/\?$/, '');
} }
/**
* RegExp to extract string with comma-separated files from a bundle-url
*
* @type RegExp
*/
var bundle2files_regexp = /phpgwapi\/inc\/min\/\?b=[^&]+&f=([^&]+)/;
/**
* Return array of files-sources from bundle(s) incl. bundle-src itself
*
* @param {string|Array} _srcs all url's have to be egw releativ!
* @returns {Array}
*/
function files_from_bundles(_srcs)
{
var files = [];
if (typeof _srcs == 'string') _srcs = [_srcs];
for(var n=0; n < _srcs.length; ++n)
{
var file = _srcs[n];
files.push(file);
var contains = file.match(bundle2files_regexp);
if (contains && contains.length > 1)
{
files = files.concat(contains[1].split(','));
}
}
return files;
}
/**
* Strip of egw_url from given urls (if containing it)
*
* @param {array} _urls absolute urls
* @returns {array} relativ urls
*/
function strip_egw_url(_urls)
{
var egw_url = egw.webserverUrl;
if (egw_url.charAt(egw_url.length-1) != '/') egw_url += '/';
for(var i=0; i < _urls.length; ++i)
{
var file = _urls[i];
// check if egw_url is only path and urls contains full url incl. protocol
// --> prefix it with our protocol and host, as eg. splitting by just '/' will fail!
var need_full_url = egw_url[0] == '/' && file.substr(4) == 'http' ? window.location.protocol+'://'+window.location.host : '';
var parts = file.split(need_full_url+egw_url,2);
if (parts.length == 2) _urls[i] = parts[1];
}
return _urls;
}
/**
* Array which contains all currently bound in javascript and css files.
*/
var files = [];
// add already included scripts
var tags = $j('script');
for(var i=0; i < tags.length; ++i)
{
files.push(removeTS(tags[i].src));
}
// add already included css
tags = $j('link[type="text/css"]');
for(var i=0; i < tags.length; ++i)
{
files.push(removeTS(tags[i].href));
}
// make urls egw-relative
files = strip_egw_url(files);
// resolve bundles
files = files_from_bundles(files);
return { return {
/** /**
* Load and execute javascript file(s) in order * Load and execute javascript file(s) in order
* *
* @memberOf egw * @memberOf egw
* @param string|array _jsFiles (array of) urls to include * @param string|array _jsFiles (array of) urls to include
* @param function _callback called after JS files are loaded and executed * @param function _callback called after JS files are loaded and executed
* @param object _context * @param object _context
* @param string _prefix prefix for _jsFiles * @param string _prefix prefix for _jsFiles
*/ */
includeJS: function(_jsFiles, _callback, _context, _prefix) { includeJS: function(_jsFiles, _callback, _context, _prefix)
if (typeof _prefix === 'undefined') {
// Also allow including a single javascript file
if (typeof _jsFiles === 'string')
{ {
_prefix = ''; _jsFiles = [_jsFiles];
} }
// LABjs uses prefix only if url is not absolute, so removing leading / if necessary and add it to prefix // LABjs uses prefix only if url is not absolute, so removing leading / if necessary and add it to prefix
if (_prefix) if (_prefix)
{ {
// Also allow including a single javascript file
if (typeof _jsFiles === 'string')
{
_jsFiles = [_jsFiles];
}
for(var i=0; i < _jsFiles.length; ++i) for(var i=0; i < _jsFiles.length; ++i)
{ {
if (_jsFiles[i].charAt(0) == '/') _jsFiles[i] = _jsFiles[i].substr(1); if (_jsFiles[i].charAt(0) == '/') _jsFiles[i] = _jsFiles[i].substr(1);
} }
if (_prefix.charAt(_prefix.length-1) != '/') }
// as all our included checks use egw relative url strip off egw-url and use it as prefix
else
{
_jsFiles = strip_egw_url(_jsFiles);
_prefix = egw.webserverUrl;
}
if (_prefix.charAt(_prefix.length-1) != '/')
{
_prefix += '/';
}
// search and NOT load files already included as part of a bundle
for(var i=0; i < _jsFiles.length; ++i)
{
var file = _jsFiles[i];
if (this.included(file, true)) // check if included and marks as such if not
{ {
_prefix += '/'; _jsFiles.splice(i, 1);
i--; // as index will be incr by for!
} }
} }
// check if all files already included --> call callback right away
if (!_jsFiles.length)
{
_callback.call(_context);
return;
}
// setting AlwaysPreserverOrder: true, 'til we have some other means of ensuring dependency resolution // setting AlwaysPreserverOrder: true, 'til we have some other means of ensuring dependency resolution
(egw_LAB || $LAB.setOptions({AlwaysPreserveOrder:true,BasePath:_prefix})).script(_jsFiles).wait(function(){ (egw_LAB || $LAB.setOptions({AlwaysPreserveOrder:true,BasePath:_prefix})).script(_jsFiles).wait(function(){
_callback.call(_context); _callback.call(_context);
}); });
}, },
/**
* Check if file is already included and optional mark it as included if not yet included
*
* @param {string} _file
* @param {boolean} _add_if_not if true mark file as included
* @return boolean true if file already included, false if not
*/
included: function(_file, _add_if_not)
{
var file = removeTS(_file);
var not_inc = files.indexOf(file) == -1;
if (not_inc && _add_if_not)
{
files = files.concat(files_from_bundles(file));
}
return !not_inc;
},
/** /**
* Include a CSS file * Include a CSS file
* *
* @param _cssFile full url of file to include * @param _cssFile full url of file to include
*/ */
includeCSS: function(_cssFile) { includeCSS: function(_cssFile)
//Check whether the requested file has already been included {
var file = removeTS(_cssFile); if (!this.included(_cssFile, true)) // check if included and marks as such if not
if (typeof files[file] === 'undefined')
{ {
files[file] = true; // Create the node which is used to include the css file
// Create the node which is used to include the css fiel
var cssnode = _wnd.document.createElement('link'); var cssnode = _wnd.document.createElement('link');
cssnode.type = "text/css"; cssnode.type = "text/css";
cssnode.rel = "stylesheet"; cssnode.rel = "stylesheet";
@ -111,8 +220,7 @@ egw.extend('files', egw.MODULE_WND_LOCAL, function(_app, _wnd)
} }
} }
} }
} };
}); });