qcobjects
Version:
QCObjects is an Open-source framework that empowers full-stack developers to make micro-services and micro-frontends into an N-Tier architecture.
253 lines (242 loc) • 12.4 kB
text/typescript
import { IComponent, TCacheController } from "types";
import { asyncLoad } from "./asyncLoad";
import { ComplexStorageCache } from "./ComplexStorageCache";
import { _DataStringify } from "./DataStringify";
import { logger } from "./Logger";
import { is_phonegap, isBrowser } from "./platform";
import { _top } from "./top";
/**
* Loads a simple component from a template
*
* @author: Jean Machuca <correojean@gmail.com>
* @param component a Component object
*/
export const componentLoader = function (component: IComponent, _async: boolean):Promise<any> {
let __promise__: Promise<any>;
const _componentLoaderInBrowser = function (component: IComponent) {
__promise__ = new Promise(function (resolve, reject) {
const _promise = component.__promise__;
const container = (Object.hasOwn(component, "container") && typeof component.container !== "undefined" && component.container !== null) ? (component.container) : (component.body);
if (container !== null) {
const _feedComponent_ = function (component: { feedComponent: () => void; }) {
component.feedComponent();
const standardResponse = {
"request": xhr,
component
};
resolve.call(_promise, standardResponse);
};
logger.debug("LOADING COMPONENT DATA {{DATA}} FROM {{URL}}".replace("{{DATA}}", _DataStringify(component.data)).replace("{{URL}}", component.url));
const _componentLoaded = function () {
const successStatus = (is_file) ? (0) : (200);
if (xhr.status === successStatus) {
const response = xhr.responseText;
logger.debug("Data received {{DATA}}".replace("{{DATA}}", _DataStringify(response)));
logger.debug("CREATING COMPONENT {{NAME}}".replace("{{NAME}}", component.name));
component.template = response;
if (component.cached && (typeof cache !== "undefined")) {
cache.save(component.name, component.template);
}
_feedComponent_(component);
} else {
const standardResponse = {
"request": xhr,
component
};
reject.call(_promise, standardResponse);
}
};
if (typeof component.template === "string" && component.template !== "") {
// component already has a template it does not need to be reloaded
_feedComponent_(component);
} else {
var is_file = !!(component.url.startsWith("file:"));
var xhr = new XMLHttpRequest();
if (!is_file) {
try {
logger.debug("Calling the url of component in async mode.");
xhr.open(component.method, component.url, true);
} catch (e:any) {
logger.debug(`An error ocurred: ${e}.`);
logger.debug("Last try has failed... The component cannot be loaded.");
}
} else {
if ("fetch" in _top) {
logger.debug("I can use fetch...");
logger.debug("It is a file to be loaded, so I will try to use fetch");
fetch(component.url).then(response => {
logger.debug("I got a response from fetch, so I'll feed the component");
response.text().then(text => {
component.template = text;
_feedComponent_(component);
})
.catch((e:any) => {throw new Error (`An error ocurred: ${e}`);});
}).catch ((e:any) => {throw new Error (`An error ocurred: ${e}`);});
}
}
if (!is_phonegap && !is_file) {
xhr.setRequestHeader("Content-Type", "text/html");
}
if (!is_file) {
xhr.onload = _componentLoaded;
}
const _directLoad = function (is_file: boolean) {
is_file = !((typeof is_file === "undefined" || !is_file));
logger.debug("SENDING THE NORMAL REQUEST ");
if (is_file) {
if (!("fetch" in _top)) {
logger.debug("I have to try to load the file using xhr... ");
xhr.send(null);
if (xhr.status === XMLHttpRequest.DONE) {
_componentLoaded();
}
}
} else {
logger.debug("Trying to send the data to the component... ");
xhr.send(_DataStringify(component.data));
}
};
if (component.cached && (!is_file)) {
logger.debug("USING CACHE FOR COMPONENT: " + component.name);
var cache = new ComplexStorageCache({
index: component.cacheIndex,
load() {
_directLoad.call(this, is_file);
},
alternate(cacheController: TCacheController) {
if (component.method === "GET") {
component.template = cacheController.cache.getCached(component.cacheIndex);
_feedComponent_.call(this, component);
} else {
_directLoad.call(this, is_file);
}
}
});
(_top as any).lastCache = cache;
} else {
logger.debug("NOT USING CACHE FOR COMPONENT: " + component.name);
_directLoad(is_file);
}
}
} else {
logger.debug("CONTAINER DOESNT EXIST");
}
});
__promise__.then(function (standardResponse) {
return component.__done__().then(function () {
let _ret_;
if (typeof component.done === "function") {
_ret_ = component.done.call(component, standardResponse);
}
return Promise.resolve(_ret_);
});
}, function (standardResponse) {
if (typeof component.fail === "function") {
component.fail.call(component, standardResponse)
.catch ((e:any)=> {throw new Error (`${e}`);});
}
return Promise.reject(new Error ("An error ocurred"));
}).catch(function (e:any) {
logger.debug("Something wrong loading the component");
throw new Error (`An error ocurred: ${e}`);
});
return __promise__;
};
const _componentLoaderInNode = function (component: IComponent) {
__promise__ = new Promise(function (resolve, reject) {
const _promise = __promise__;
const _feedComponent_ = function (component: IComponent) {
component.feedComponent()
.catch ((e:any) => {
throw new Error (`An error ocurred trying to feed the component: ${component.name}. Error: ${e}`);
});
const standardResponse = {
"request": null,
component
};
resolve.call(_promise, standardResponse);
};
logger.debug("LOADING COMPONENT DATA {{DATA}} FROM {{URL}}".replace("{{DATA}}", _DataStringify(component.data)).replace("{{URL}}", component.url));
const _componentLoaded = function (err: any, responseText: { toString: () => any; }) {
if (!err) {
const response = responseText.toString();
logger.debug("Data received {{DATA}}".replace("{{DATA}}", _DataStringify(response)));
logger.debug("CREATING COMPONENT {{NAME}}".replace("{{NAME}}", component.name));
component.template = response;
if (component.cached && (typeof cache !== "undefined")) {
cache.save(component.name, component.template);
}
_feedComponent_(component);
} else {
const standardResponse = {
"request": null,
component
};
reject.call(_promise, standardResponse);
}
};
if (typeof component.template === "string" && component.template !== "") {
// component already has a template it does not need to be reloaded
_feedComponent_(component);
} else {
logger.debug("Loading the component as a local file in server...");
const _directLoad = function () {
// eslint-disable-next-line @typescript-eslint/no-require-imports
const {readFile} = require("node:fs");
logger.debug("SENDING THE NORMAL REQUEST ");
readFile(component.url, _componentLoaded);
};
if (component.cached) {
logger.debug("USING CACHE FOR COMPONENT: " + component.name);
var cache = new ComplexStorageCache({
index: component.cacheIndex,
load() {
_directLoad();
},
alternate(cacheController: TCacheController) {
if (component.method === "GET") {
component.template = cacheController.cache.getCached(component.cacheIndex);
_feedComponent_.call(this, component);
} else {
_directLoad.call(this);
}
}
});
(_top as any).lastCache = cache;
} else {
logger.debug("NOT USING CACHE FOR COMPONENT: " + component.name);
_directLoad();
}
}
});
__promise__.then(function (standardResponse) {
return component.__done__().then(function () {
let _ret_;
if (typeof component.done === "function") {
_ret_ = component.done.call(component, standardResponse);
}
return Promise.resolve(_ret_);
});
}, function (standardResponse) {
if (typeof component.fail === "function") {
component.fail.call(component, standardResponse)
.catch((e:any) => {throw new Error (`An error ocurred: ${e}`);});
}
return Promise.reject(new Error ("An error ocurred."));
}).catch(function (e) {
logger.debug(`Something wrong loading the component: ${e}`);
});
return __promise__;
};
let _ret_;
if (isBrowser) {
if (typeof _async !== "undefined" && _async) {
_ret_ = asyncLoad(_componentLoaderInBrowser, [component, _async]);
} else {
_ret_ = _componentLoaderInBrowser(component);
}
} else {
_ret_ = _componentLoaderInNode(component);
}
return _ret_ as Promise<any>;
};