diff --git a/phpgwapi/js/jsapi/egw_files.js b/phpgwapi/js/jsapi/egw_files.js index 24f8d44e08..176c1a9541 100644 --- a/phpgwapi/js/jsapi/egw_files.js +++ b/phpgwapi/js/jsapi/egw_files.js @@ -21,18 +21,13 @@ /** * @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; - /** - * 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] - * + * * Examples: * /path/file.js --> /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(/\?$/, ''); } + /** + * 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 { /** * Load and execute javascript file(s) in order - * + * * @memberOf egw * @param string|array _jsFiles (array of) urls to include * @param function _callback called after JS files are loaded and executed * @param object _context * @param string _prefix prefix for _jsFiles */ - includeJS: function(_jsFiles, _callback, _context, _prefix) { - if (typeof _prefix === 'undefined') + includeJS: function(_jsFiles, _callback, _context, _prefix) + { + // 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 if (_prefix) { - // Also allow including a single javascript file - if (typeof _jsFiles === 'string') - { - _jsFiles = [_jsFiles]; - } for(var i=0; i < _jsFiles.length; ++i) { 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 (egw_LAB || $LAB.setOptions({AlwaysPreserveOrder:true,BasePath:_prefix})).script(_jsFiles).wait(function(){ _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 - * + * * @param _cssFile full url of file to include */ - includeCSS: function(_cssFile) { - //Check whether the requested file has already been included - var file = removeTS(_cssFile); - if (typeof files[file] === 'undefined') + includeCSS: function(_cssFile) + { + if (!this.included(_cssFile, true)) // check if included and marks as such if not { - files[file] = true; - - // Create the node which is used to include the css fiel + // Create the node which is used to include the css file var cssnode = _wnd.document.createElement('link'); cssnode.type = "text/css"; cssnode.rel = "stylesheet"; @@ -111,8 +220,7 @@ egw.extend('files', egw.MODULE_WND_LOCAL, function(_app, _wnd) } } } - } - + }; });