StaticApps/src/app/startup.js

174 lines
4.8 KiB
JavaScript

const EVENT_MODULE_LOADED = "module-loaded";
class Startup {
constructor(modules) {
this.modules = modules;
this.cb = null;
this.isErrored = false;
this.isAllLoadedFired = false;
document.addEventListener(EVENT_MODULE_LOADED, this.allModulesLoaded.bind(this));
}
setCb(cb) {
this.cb = cb;
}
setErrCb(cb) {
this.errCb = cb;
}
finishModule(name) {
name = Startup.getName(name);
this.modules[name] = !0;
PrettyConsole.debug(name, "Module Loading Done");
document.dispatchEvent(new CustomEvent(EVENT_MODULE_LOADED, {detail: name}));
}
moduleErrored(name, error) {
name = Startup.getName(name);
if (this.errCb) {
this.errCb(name, error);
}
this.isErrored = true;
document.dispatchEvent(new CustomEvent(`module-errored`, {
data: {name, error}
}));
}
isModuleLoaded(names, cb) {
let self = this;
if (typeof names === 'string') {
names = [names];
}
let pendingModules = names.filter(function (module) {
return !self.modules[Startup.getName(module)]
});
if (pendingModules.length > 0) {
function listener() {
document.removeEventListener(EVENT_MODULE_LOADED, listener);
self.isModuleLoaded.bind(self)(pendingModules, cb);
}
document.addEventListener(EVENT_MODULE_LOADED, listener);
} else {
cb();
}
}
registerModule(name) {
this.modules[Startup.getName(name)] = false;
}
allModulesLoaded() {
if (this.isErrored) {
return false;
}
if (this.isAllLoadedFired) {
return true;
}
for (let module in this.modules) {
if (this.modules.hasOwnProperty(module) && !this.modules[module]) {
return false;
}
}
this.isAllLoadedFired = true;
if (this.cb) {
this.cb();
}
document.dispatchEvent(new CustomEvent('startupFin'));
return true;
}
ignite() {
document.dispatchEvent(new CustomEvent('ignite'));
}
registerInit(onInit) {
document.addEventListener('ignite', onInit);
}
loadOtherJsFiles(files) {
for (let file of files) {
this.registerModule(file[1]);
let script = document.createElement('script');
script.onload = () => {
moduleLoader.finishModule(file[1]);
}
script.onerror = (err) => {
moduleLoader.moduleErrored(file[1], err);
}
script.src = file[0];
document.body.appendChild(script);
}
}
static getName(name) {
if (typeof name === 'function') {
return name.name;
}
return name;
}
}
class Loader {
constructor() {
document.addEventListener(EVENT_MODULE_LOADED, this.loadProgress.bind(this));
document.addEventListener('startupFin', this.finish.bind(this));
this.loadingText = document.querySelector('v-loading-text');
this.loadingPerc = document.querySelector('v-loading-stats');
this.loadingScreen = document.querySelector('v-loading-screen');
this.loaded = 0;
this.toLoad = 0;
this.isErrored = false;
}
addToLoadItem(i) {
this.toLoad += i;
}
addLoadedItems(i) {
this.loaded += i;
this.loadProgress();
}
loadProgress() {
if (this.isErrored) return;
let loaded = 0,
keys = Object.keys(moduleLoader.modules);
for (let key of keys) {
if (moduleLoader.modules[key]) {
loaded++;
}
}
loaded += this.loaded;
let toLoad = keys.length + this.toLoad;
const perc = ((loaded / toLoad) * 100).toFixed(2) + "%";
this.loadingScreen.style.setProperty('--loading-scale', perc);
this.loadingPerc.innerText = `${loaded} / ${toLoad} (${perc})`;
}
onError(module, error) {
this.isErrored = true;
this.loadingText.innerText = "Errored";
this.loadingPerc.innerHTML = `Module ${module} failed to load<br>${error}`;
this.loadingScreen.style.setProperty('--loading-color', '#fa0000');
PrettyConsole.error("Startup", `Module ${module} failed to load`)
}
finish() {
document.removeEventListener('module-loaded-progress', this.loadProgress.bind(this));
}
}
const moduleLoader = new Startup({
'Startup': false,
});
const loader = new Loader();
moduleLoader.setErrCb(loader.onError.bind(loader));
const preLoader = new PreLoader();
moduleLoader.isModuleLoaded('PreLoader', () => {
moduleLoader.loadOtherJsFiles([
['/out/app/app.min.js', 'app.js'],
]);
});