@kwiz/common
Version:
KWIZ common utilities and helpers for M365 platform
195 lines (171 loc) • 6.71 kB
text/typescript
import { isDebug } from "../helpers/debug";
import { getFromFullName, isFunction, isNullOrEmptyString, isNullOrUndefined, isString, isTypeofFullNameNullOrUndefined, typeofFullName } from "../helpers/typecheckers";
import { ksGlobal } from "../types/knownscript.types";
declare global {
interface Window {
g_kwizcom_sods: { [sodName: string]: Sod; };
}
}
interface ISodCallback {
called: boolean;
callback: () => void;
}
// eslint-disable-next-line no-shadow
enum SodState {
pending = "pending",
done = "done"
}
export default class Sod {
private sodName: string;
private url: string;
private script: HTMLScriptElement;
private state: string;
private notified: boolean;
private callbacks: ISodCallback[];
public constructor(url: string, sodName: string) {
this.url = url;
this.sodName = sodName;
this.state = SodState.pending;
this.notified = false;
this.callbacks = [];
this.script = null;
}
private error() {
if (isDebug()) console.log('unhandled error in sod');
}
private loadScript(scriptUrl: string, sync = false) {
let self = this;
var successCallback = () => {
self.load();
};
var errorCallback = () => {
self.error();
};
self.script = Sod.loadScript(scriptUrl, successCallback, errorCallback, sync);
self.state = SodState.pending;
}
private load() {
let self = this;
self.state = SodState.done;
if (!self.notified) {
self.notify();
}
}
private notify() {
let self = this;
var callbackLength = self.callbacks.length;
for (var i = 0; i < callbackLength; i++) {
var sodCallback = self.callbacks[i];
if (!sodCallback.called && typeof (sodCallback.callback) === "function") {
try {
sodCallback.callback();
sodCallback.called = true;
} catch (ex) {
if (isDebug()) console.log('unhandled error in sod');
}
}
}
self.notified = true;
}
private reset() {
let self = this;
var callbackLength = self.callbacks.length;
for (var i = 0; i < callbackLength; i++) {
this.callbacks[i].called = false;
}
self.notified = false;
}
private static loadScript(url: string, successCallback: () => void, errCallback: () => void, sync = false) {
let scriptElm = document.createElement("script");
if (sync === true) {
let req = new XMLHttpRequest();
req.open("GET", url, false);
req.send();
scriptElm.appendChild(document.createTextNode(req.responseText));
successCallback();
}
else {
let agt = navigator.userAgent.toLowerCase();
let ie8down = agt.indexOf("msie") !== -1 && parseInt(agt.substring(agt.indexOf("msie ") + 5), 10) <= 8;
let getCallback = (cb: () => void) => {
return () => {
var loaded = false;
if (ie8down && typeof (scriptElm as any).readyState !== "undefined") {
loaded = (scriptElm as any).readyState === "complete" || (scriptElm as any).readyState === "loaded";
} else {
loaded = true;
}
if (loaded) {
(scriptElm as any).onreadystatechange = null;
scriptElm.onload = null;
scriptElm.onerror = null;
cb();
}
};
};
scriptElm.type = "text/javascript";
scriptElm.src = url;
if (ie8down) {
(scriptElm as any).onreadystatechange = getCallback(successCallback);
} else {
scriptElm.onload = getCallback(successCallback);
scriptElm.onerror = getCallback(errCallback);
}
}
(document.head || document.getElementsByTagName("HEAD")[0]).appendChild(scriptElm);
return scriptElm;
}
public static getGlobal(global: ksGlobal) {
if (isString(global))
return getFromFullName(global);
else
return global.getter();
}
public static ensureScriptNoPromise(scriptUrl: string, global: ksGlobal, callback?: () => void, sodName?: string, sync = false) {
if (!isNullOrEmptyString(global) && typeofFullName(Sod.getGlobal(global)) !== "undefined") {
//this global object already exists, no need to reload this script.
if (isFunction(callback)) {
callback();
}
}
else {
sodName = (isNullOrEmptyString(sodName) === false && sodName || scriptUrl).toLowerCase();
var sod = Sod._getGlobalSod(sodName);
if (!sod) {
sod = Sod._addGlobalSod(sodName, scriptUrl);
}
if (!isNullOrUndefined(callback)) {
sod.callbacks.push({ "called": false, "callback": callback });
}
if (!sod.script) {
sod.loadScript(scriptUrl, sync);
} else if (sod.state === SodState.done || sod.notified) {
sod.notify();
}
}
}
public static async ensureScript(scriptUrl: string, global: ksGlobal, callback?: () => void, sodName?: string, sync = false): Promise<void> {
return new Promise<void>((resolve, reject) => {
let resolveCallback = () => {
if (!isNullOrUndefined(callback)) callback();
resolve();
};
Sod.ensureScriptNoPromise(scriptUrl, global, resolveCallback, sodName, sync);
});
}
private static _initGlobalSods() {
//static must be globally shared between all instances...
if (isTypeofFullNameNullOrUndefined("g_kwizcom_sods")) {
window.g_kwizcom_sods = {};
}
}
private static _getGlobalSod(name: string) {
Sod._initGlobalSods();
return window.g_kwizcom_sods[name];
}
private static _addGlobalSod(name: string, scriptUrl: string) {
Sod._initGlobalSods();
window.g_kwizcom_sods[name] = new Sod(scriptUrl, name);
return window.g_kwizcom_sods[name];
}
}