From bfea641321214399fc34be0ae9d1f91b281daf64 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Tue, 8 Jun 2021 17:13:30 +0200 Subject: [PATCH] fix async loading caused app.js not being loaded before et2.load() tried to instantiate it --- api/js/etemplate/etemplate2.js | 11 +++++-- api/js/etemplate/etemplate2.ts | 12 +++++--- api/js/jsapi/egw_files.js | 52 +++++++--------------------------- api/js/jsapi/egw_global.d.ts | 2 +- api/js/jsapi/egw_global.js | 2 +- api/js/jsapi/egw_json.js | 13 ++------- api/js/jsapi/egw_lang.js | 30 ++------------------ 7 files changed, 35 insertions(+), 87 deletions(-) diff --git a/api/js/etemplate/etemplate2.js b/api/js/etemplate/etemplate2.js index 1d1aa69b6f..463187f784 100644 --- a/api/js/etemplate/etemplate2.js +++ b/api/js/etemplate/etemplate2.js @@ -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 diff --git a/api/js/etemplate/etemplate2.ts b/api/js/etemplate/etemplate2.ts index 7303f0e987..79c6b013d8 100644 --- a/api/js/etemplate/etemplate2.ts +++ b/api/js/etemplate/etemplate2.ts @@ -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); + }); } /** diff --git a/api/js/jsapi/egw_files.js b/api/js/jsapi/egw_files.js index 07b7cf8374..d897978464 100644 --- a/api/js/jsapi/egw_files.js +++ b/api/js/jsapi/egw_files.js @@ -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)); }, /** diff --git a/api/js/jsapi/egw_global.d.ts b/api/js/jsapi/egw_global.d.ts index 516ac2bd9b..f333bc904a 100644 --- a/api/js/jsapi/egw_global.d.ts +++ b/api/js/jsapi/egw_global.d.ts @@ -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 * diff --git a/api/js/jsapi/egw_global.js b/api/js/jsapi/egw_global.js index 30ae89a676..2ecb1f2a1b 100644 --- a/api/js/jsapi/egw_global.js +++ b/api/js/jsapi/egw_global.js @@ -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; diff --git a/api/js/jsapi/egw_json.js b/api/js/jsapi/egw_json.js index 58e5ed948c..e6be183e65 100644 --- a/api/js/jsapi/egw_json.js +++ b/api/js/jsapi/egw_json.js @@ -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]](); diff --git a/api/js/jsapi/egw_lang.js b/api/js/jsapi/egw_lang.js index 1b2456a96c..8b544b2647 100644 --- a/api/js/jsapi/egw_lang.js +++ b/api/js/jsapi/egw_lang.js @@ -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; } };