diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html index ae3749c9..53464377 100644 --- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html +++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html @@ -1641,29 +1641,56 @@ SPDX-License-Identifier: GPL-2.0-or-later 'settings': ['/vchan.js', '/scheduler.js'] }; var loaded = new Set(); - function loadPlugins(tab) { - var scripts = pluginScripts[tab]; - if (!scripts) return; - scripts.forEach(function(src) { - if (loaded.has(src)) return; - loaded.add(src); + var loading = new Map(); + + function loadScript(src) { + if (loaded.has(src)) return Promise.resolve(); + if (loading.has(src)) return loading.get(src); + + var request = new Promise(function(resolve, reject) { var s = document.createElement('script'); s.src = src; - s.defer = true; + s.onload = function() { + loaded.add(src); + loading.delete(src); + resolve(); + }; + s.onerror = function() { + loading.delete(src); + reject(new Error('Failed to load plugin script: ' + src)); + }; document.body.appendChild(s); }); + loading.set(src, request); + return request; + } + + function loadPlugins(tab) { + var scripts = pluginScripts[tab]; + if (!scripts) return Promise.resolve(); + return scripts.reduce(function(sequence, src) { + return sequence.then(function() { return loadScript(src); }); + }, Promise.resolve()); + } + + function requestPlugins(tab) { + return loadPlugins(tab).catch(function(err) { + console.error(err); + }); } // Eager plugin loading is triggered by app.js (after window.trx is set up) // via window.loadEagerPlugins(). Dynamic scripts are effectively async, so // loading them before app.js would cause map-core.js to crash when // window.trx is not yet defined. window.loadEagerPlugins = function() { - ['digital-modes', 'map-data', 'bookmarks', 'settings'].forEach(loadPlugins); + return Promise.all( + ['digital-modes', 'map-data', 'bookmarks', 'settings'].map(requestPlugins) + ); }; // Load others on tab switch document.addEventListener('click', function(e) { var tab = e.target.closest('[data-tab]'); - if (tab) loadPlugins(tab.dataset.tab); + if (tab) requestPlugins(tab.dataset.tab); }); window.loadPluginsForTab = loadPlugins; })();