import * as loader from "./loader";
declare global {
interface Window {
native_client: boolean;
}
}
const node_require: typeof require = window.require;
let _ui_version;
export function ui_version() {
if(typeof(_ui_version) !== "string") {
const version_node = document.getElementById("app_version");
if(!version_node) return undefined;
const version = version_node.hasAttribute("value") ? version_node.getAttribute("value") : undefined;
if(!version) return undefined;
return (_ui_version = version);
}
return _ui_version;
}
/* all javascript loaders */
const loader_javascript = {
detect_type: async () => {
//TODO: Detect real version!
loader.set_version({
backend: "-",
ui: ui_version(),
debug_mode: true,
type: "web"
});
window.native_client = false;
return;
if(window.require) {
const request = new Request("js/proto.js");
let file_path = request.url;
if(!file_path.startsWith("file://"))
throw "Invalid file path (" + file_path + ")";
file_path = file_path.substring(process.platform === "win32" ? 8 : 7);
const fs = node_require('fs');
if(fs.existsSync(file_path)) {
//type = Type.CLIENT_DEBUG;
} else {
//type = Type.CLIENT_RELEASE;
}
} else {
/* test if js/proto.js is available. If so we're in debug mode */
const request = new XMLHttpRequest();
request.open('GET', "js/proto.js?_ts=" + Date.now(), true);
await new Promise((resolve, reject) => {
request.onreadystatechange = () => {
if (request.readyState === 4){
if (request.status === 404) {
//type = Type.WEB_RELEASE;
} else {
//type = Type.WEB_DEBUG;
}
resolve();
}
};
request.onerror = () => {
reject("Failed to detect app type");
};
request.send();
});
}
},
load_scripts: async () => {
if(!window.require) {
await loader.load_script(["vendor/jquery/jquery.min.js"]);
} else {
/*
loader.register_task(loader.Stage.JAVASCRIPT_INITIALIZING, {
name: "forum sync",
priority: 10,
function: async () => {
forum.sync_main();
}
});
*/
}
await loader.load_script(["vendor/DOMPurify/purify.min.js"]);
await loader.load_script("vendor/jsrender/jsrender.min.js");
await loader.load_scripts([
["vendor/xbbcode/src/parser.js"],
["vendor/moment/moment.js"],
["vendor/twemoji/twemoji.min.js", ""], /* empty string means not required */
["vendor/highlight/highlight.pack.js", ""], /* empty string means not required */
["vendor/remarkable/remarkable.min.js", ""], /* empty string means not required */
["adapter/adapter-latest.js", "https://webrtc.github.io/adapter/adapter-latest.js"]
]);
await loader.load_scripts([
["vendor/emoji-picker/src/jquery.lsxemojipicker.js"]
]);
if(!loader.version().debug_mode) {
loader.register_task(loader.Stage.JAVASCRIPT, {
name: "scripts release",
priority: 20,
function: loader_javascript.load_release
});
} else {
loader.register_task(loader.Stage.JAVASCRIPT, {
name: "scripts debug",
priority: 20,
function: loader_javascript.load_scripts_debug
});
}
},
load_scripts_debug: async () => {
await loader.load_scripts(["js/shared-app.js"])
},
load_release: async () => {
console.log("Load for release!");
await loader.load_scripts([
//Load general API's
["js/client.min.js", "js/client.js"]
]);
}
};
const loader_webassembly = {
test_webassembly: async () => {
/* We dont required WebAssembly anymore for fundamental functions, only for auto decoding
if(typeof (WebAssembly) === "undefined" || typeof (WebAssembly.compile) === "undefined") {
console.log(navigator.browserSpecs);
if (navigator.browserSpecs.name == 'Safari') {
if (parseInt(navigator.browserSpecs.version) < 11) {
displayCriticalError("You require Safari 11 or higher to use the web client!
Safari " + navigator.browserSpecs.version + " does not support WebAssambly!");
return;
}
}
else {
// Do something for all other browsers.
}
displayCriticalError("You require WebAssembly for TeaSpeak-Web!");
throw "Missing web assembly";
}
*/
}
};
const loader_style = {
load_style: async () => {
await loader.load_styles([
"vendor/xbbcode/src/xbbcode.css"
]);
await loader.load_styles([
"vendor/emoji-picker/src/jquery.lsxemojipicker.css"
]);
await loader.load_styles([
["vendor/highlight/styles/darcula.css", ""], /* empty string means not required */
]);
if(loader.version().debug_mode) {
await loader_style.load_style_debug();
} else {
await loader_style.load_style_release();
}
},
load_style_debug: async () => {
await loader.load_styles([
"css/static/main.css",
"css/static/main-layout.css",
"css/static/helptag.css",
"css/static/scroll.css",
"css/static/channel-tree.css",
"css/static/ts/tab.css",
"css/static/ts/chat.css",
"css/static/ts/icons.css",
"css/static/ts/icons_em.css",
"css/static/ts/country.css",
"css/static/general.css",
"css/static/modal.css",
"css/static/modals.css",
"css/static/modal-about.css",
"css/static/modal-avatar.css",
"css/static/modal-icons.css",
"css/static/modal-bookmarks.css",
"css/static/modal-connect.css",
"css/static/modal-channel.css",
"css/static/modal-query.css",
"css/static/modal-volume.css",
"css/static/modal-latency.css",
"css/static/modal-invite.css",
"css/static/modal-playlist.css",
"css/static/modal-banlist.css",
"css/static/modal-banclient.css",
"css/static/modal-channelinfo.css",
"css/static/modal-clientinfo.css",
"css/static/modal-serverinfo.css",
"css/static/modal-musicmanage.css",
"css/static/modal-serverinfobandwidth.css",
"css/static/modal-identity.css",
"css/static/modal-newcomer.css",
"css/static/modal-settings.css",
"css/static/modal-poke.css",
"css/static/modal-server.css",
"css/static/modal-keyselect.css",
"css/static/modal-permissions.css",
"css/static/modal-group-assignment.css",
"css/static/overlay-image-preview.css",
"css/static/music/info_plate.css",
"css/static/frame/SelectInfo.css",
"css/static/control_bar.css",
"css/static/context_menu.css",
"css/static/frame-chat.css",
"css/static/connection_handlers.css",
"css/static/server-log.css",
"css/static/htmltags.css",
"css/static/hostbanner.css",
"css/static/menu-bar.css"
]);
},
load_style_release: async () => {
await loader.load_styles([
"css/static/base.css",
"css/static/main.css",
]);
}
};
/* register tasks */
loader.register_task(loader.Stage.INITIALIZING, {
name: "safari fix",
function: async () => {
/* safari remove "fix" */
if(Element.prototype.remove === undefined)
Object.defineProperty(Element.prototype, "remove", {
enumerable: false,
configurable: false,
writable: false,
value: function(){
this.parentElement.removeChild(this);
}
});
},
priority: 50
});
loader.register_task(loader.Stage.INITIALIZING, {
name: "Browser detection",
function: async () => {
navigator.browserSpecs = (function(){
let ua = navigator.userAgent, tem, M = ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
if(/trident/i.test(M[1])){
tem = /\brv[ :]+(\d+)/g.exec(ua) || [];
return {name:'IE',version:(tem[1] || '')};
}
if(M[1]=== 'Chrome'){
tem = ua.match(/\b(OPR|Edge)\/(\d+)/);
if(tem != null) return {name:tem[1].replace('OPR', 'Opera'),version:tem[2]};
}
M = M[2]? [M[1], M[2]]: [navigator.appName, navigator.appVersion, '-?'];
if((tem = ua.match(/version\/(\d+)/i))!= null)
M.splice(1, 1, tem[1]);
return {name:M[0], version:M[1]};
})();
console.log("Resolved browser manufacturer to \"%s\" version \"%s\"", navigator.browserSpecs.name, navigator.browserSpecs.version);
},
priority: 30
});
loader.register_task(loader.Stage.INITIALIZING, {
name: "secure tester",
function: async () => {
/* we need https or localhost to use some things like the storage API */
if(typeof isSecureContext === "undefined")
(window)["isSecureContext"] = location.protocol !== 'https:' && location.hostname !== 'localhost';
if(!isSecureContext) {
loader.critical_error("TeaWeb cant run on unsecured sides.", "App requires to be loaded via HTTPS!");
throw "App requires a secure context!"
}
},
priority: 20
});
loader.register_task(loader.Stage.INITIALIZING, {
name: "webassembly tester",
function: loader_webassembly.test_webassembly,
priority: 20
});
loader.register_task(loader.Stage.INITIALIZING, {
name: "app type test",
function: loader_javascript.detect_type,
priority: 20
});
loader.register_task(loader.Stage.JAVASCRIPT, {
name: "javascript",
function: loader_javascript.load_scripts,
priority: 10
});
loader.register_task(loader.Stage.STYLE, {
name: "style",
function: loader_style.load_style,
priority: 10
});
loader.register_task(loader.Stage.TEMPLATES, {
name: "templates",
function: async () => {
await loader.load_templates([
"templates.html",
"templates/modal/musicmanage.html",
"templates/modal/newcomer.html",
]);
},
priority: 10
});
loader.register_task(loader.Stage.LOADED, {
name: "loaded handler",
function: async () => loader.hide_overlay(),
priority: 5
});
loader.register_task(loader.Stage.JAVASCRIPT_INITIALIZING, {
name: "lsx emoji picker setup",
function: async () => await (window as any).setup_lsx_emoji_picker({twemoji: typeof(window.twemoji) !== "undefined"}),
priority: 10
});
loader.register_task(loader.Stage.SETUP, {
name: "page setup",
function: async () => {
const body = document.body;
/* top menu */
{
const container = document.createElement("div");
container.setAttribute('id', "top-menu-bar");
body.append(container);
}
/* template containers */
{
const container = document.createElement("div");
container.setAttribute('id', "templates");
body.append(container);
}
/* sounds container */
{
const container = document.createElement("div");
container.setAttribute('id', "sounds");
body.append(container);
}
/* mouse move container */
{
const container = document.createElement("div");
container.setAttribute('id', "mouse-move");
const inner_container = document.createElement("div");
inner_container.classList.add("container");
container.append(inner_container);
body.append(container);
}
/* tooltip container */
{
const container = document.createElement("div");
container.setAttribute('id', "global-tooltip");
container.append(document.createElement("a"));
body.append(container);
}
},
priority: 10
});
/* test if we're getting loaded within a TeaClient preview window */
loader.register_task(loader.Stage.SETUP, {
name: "TeaClient tester",
function: async () => {
//@ts-ignore
if(typeof __teaclient_preview_notice !== "undefined" && typeof __teaclient_preview_error !== "undefined") {
loader.critical_error("Why you're opening TeaWeb within the TeaSpeak client?!");
throw "we're already a TeaClient!";
}
},
priority: 100
});
export function run() {
window["Module"] = (window["Module"] || {}) as any;
/* TeaClient */
if(node_require) {
const path = node_require("path");
const remote = node_require('electron').remote;
module.paths.push(path.join(remote.app.getAppPath(), "/modules"));
module.paths.push(path.join(path.dirname(remote.getGlobal("browser-root")), "js"));
//TODO: HERE!
const connector = node_require("renderer");
loader.register_task(loader.Stage.INITIALIZING, {
name: "teaclient initialize",
function: connector.initialize,
priority: 40
});
}
if(!loader.running()) {
/* we know that we want to load the app */
loader.execute_managed();
}
}