fix async loading caused app.js not being loaded before et2.load() tried to instantiate it

This commit is contained in:
Ralf Becker 2021-06-08 17:13:30 +02:00
parent 8fa2bb466b
commit bfea641321
7 changed files with 35 additions and 87 deletions

View File

@ -374,10 +374,15 @@ export class etemplate2 {
}
var start_time = (new Date).getTime();
}
// require necessary translations from server, if not already loaded
// require necessary translations from server AND the app.js file, if not already loaded
if (!jQuery.isArray(_data.langRequire))
_data.langRequire = [];
egw(currentapp, window).langRequire(window, _data.langRequire, function () {
Promise.all([
egw(currentapp, window).langRequire(window, _data.langRequire),
egw(currentapp, window).includeJS('/' + appname + '/js/app.js', undefined, undefined, egw.webserverUrl)
]).catch((err) => {
console.log("et2.load(): error loading lang-files and app.js: " + err.message);
}).then(() => {
this.clear();
// Initialize application js
let app_callback = null;
@ -546,7 +551,7 @@ export class etemplate2 {
// Split the given data into array manager objects and pass those to the
// widget container - do this here because file is loaded async
this._widgetContainer.setArrayMgrs(this._createArrayManagers(_data));
}, this);
});
}
/**
* Check if template contains any dirty (unsaved) content

View File

@ -563,10 +563,14 @@ export class etemplate2
var start_time = (new Date).getTime();
}
// require necessary translations from server, if not already loaded
// require necessary translations from server AND the app.js file, if not already loaded
if (!jQuery.isArray(_data.langRequire)) _data.langRequire = [];
egw(currentapp, window).langRequire(window, _data.langRequire, function ()
{
Promise.all([
egw(currentapp, window).langRequire(window, _data.langRequire),
egw(currentapp, window).includeJS('/'+appname+'/js/app.js', undefined, undefined, egw.webserverUrl)
]).catch((err) => {
console.log("et2.load(): error loading lang-files and app.js: "+err.message);
}).then(() => {
this.clear();
// Initialize application js
@ -784,7 +788,7 @@ export class etemplate2
// Split the given data into array manager objects and pass those to the
// widget container - do this here because file is loaded async
this._widgetContainer.setArrayMgrs(this._createArrayManagers(_data));
}, this);
});
}
/**

View File

@ -156,52 +156,22 @@ egw.extend('files', egw.MODULE_WND_LOCAL, function(_app, _wnd)
{
_jsFiles = [_jsFiles];
}
const promise = Promise.all(_jsFiles.map((src) => import(_prefix ? _prefix+src : src)));
return typeof _callback === 'undefined' ? promise : promise.then(_callback.call(_context));
// @todo check the prefix stuff
// LABjs uses prefix only if url is not absolute, so removing leading / if necessary and add it to prefix
if (_prefix)
let promise;
if (_jsFiles.length === 1) // running this in below case fails when loading app.js from etemplate.load()
{
for(var i=0; i < _jsFiles.length; ++i)
{
if (_jsFiles[i].charAt(0) == '/') _jsFiles[i] = _jsFiles[i].substr(1);
}
const src = _jsFiles[0];
promise = import(_prefix ? _prefix+src : src);
}
// 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;
promise = Promise.all(_jsFiles.map((src) => {
import(_prefix ? _prefix+src : src)
.catch((err) => {
console.log(src+":\n\n"+err.message);
})
}));
}
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
{
_jsFiles.splice(i, 1);
i--; // as index will be incr by for!
}
}
// check if all files already included or sheduled to be included --> call callback via egw_LAB.wait
if (!_jsFiles.length)
{
egw_LAB.wait(function(){
_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);
});
return typeof _callback === 'undefined' ? promise : promise.then(_callback.call(_context));
},
/**

View File

@ -854,7 +854,7 @@ declare interface IegwWndLocal extends IegwGlobal
* @param {object} _context
* @param {string} _prefix prefix for _jsFiles
*/
includeJS(_jsFiles : string|string[], _callback : Function, _context? : object, _prefix? : string);
includeJS(_jsFiles : string|string[], _callback? : Function, _context? : object, _prefix? : string);
/**
* Check if file is already included and optional mark it as included if not yet included
*

View File

@ -1,4 +1,4 @@
export var app = window.app;
//export var app = window.app;
export var egw = window.egw;
export var framework = window.framework;
export var egw_get_file_editor_prefered_mimes = window.egw_get_file_editor_prefered_mimes;

View File

@ -521,17 +521,10 @@ egw.extend('json', egw.MODULE_WND_LOCAL, function(_app, _wnd)
// check if we need a not yet included app.js object --> include it now and return a Promise
else if (i == 1 && parts[0] == 'app' && typeof app.classes[parts[1]] === 'undefined')
{
const self = this;
return new Promise(function(resolve, reject)
{
// cache for a day, better then no invalidation
self.includeJS('/'+parts[1]+'/js/app.js?'+((new Date).valueOf()/86400|0).toString(), function ()
{
resolve(self.applyFunc(_func, args, _context));
}, self, self.webserverUrl);
});
this.includeJS('/'+parts[1]+'/js/app.js', undefined, undefined, this.webserverUrl)
.then(() => this.applyFunc(_func, args, _context));
}
// check if we need a not yet instanciated app.js object --> instanciate it now
// check if we need a not yet instantiated app.js object --> instantiate it now
else if (i == 1 && parts[0] == 'app' && typeof app.classes[parts[1]] === 'function')
{
parent = parent[parts[1]] = new app.classes[parts[1]]();

View File

@ -134,7 +134,7 @@ egw.extend('lang', egw.MODULE_GLOBAL, function()
* }
* @param {function} _callback called after loading, if not given ready event will be postponed instead
* @param {object} _context for callback
* @return Promise if no _callback specified
* @return Promise
*/
langRequire: function(_window, _apps, _callback, _context) {
// Get the ready and the files module for the given window
@ -161,32 +161,8 @@ egw.extend('lang', egw.MODULE_GLOBAL, function()
this.lang_order = apps.reverse();
}
// Only continue if we need to include a language
if (jss.length > 0)
{
if (typeof _callback == 'function')
{
files.includeJS(jss, _callback, _context || null);
}
else
{
// Require a "ready postpone token"
var token = ready.readyWaitFor();
return new Promise(function(resolve)
{
// Call "readyDone" once all js files have been included.
files.includeJS(jss, function () {
ready.readyDone(token);
resolve();
}, this);
});
}
}
else if (typeof _callback == 'function')
{
_callback.call(_context || null);
}
const promise = files.includeJS(jss, _callback, _context || null);
return typeof _callback === 'function' ? promise.then(_callback.call(_context)) : promise;
}
};