TeaWeb/shared/js/main.ts

316 lines
10 KiB
TypeScript
Raw Normal View History

2018-02-27 16:20:49 +00:00
/// <reference path="chat.ts" />
/// <reference path="client.ts" />
/// <reference path="utils/modal.ts" />
2018-03-07 18:06:52 +00:00
/// <reference path="ui/modal/ModalConnect.ts" />
2018-04-16 18:38:35 +00:00
/// <reference path="ui/modal/ModalCreateChannel.ts" />
/// <reference path="ui/modal/ModalBanCreate.ts" />
2018-04-30 21:57:21 +00:00
/// <reference path="ui/modal/ModalBanClient.ts" />
/// <reference path="ui/modal/ModalYesNo.ts" />
/// <reference path="ui/modal/ModalBanList.ts" />
2018-04-11 15:56:09 +00:00
/// <reference path="settings.ts" />
2018-04-16 18:38:35 +00:00
/// <reference path="log.ts" />
2018-02-27 16:20:49 +00:00
2018-04-16 18:38:35 +00:00
let settings: Settings;
2018-04-11 15:56:09 +00:00
let globalClient: TSClient;
let chat: ChatBox;
const js_render = window.jsrender || $;
2018-10-06 13:13:45 +00:00
const native_client = window.require !== undefined;
2018-10-28 22:01:09 +00:00
function getUserMediaFunction() {
2018-12-23 21:56:04 +00:00
if((navigator as any).mediaDevices && (navigator as any).mediaDevices.getUserMedia)
return (settings, success, fail) => { (navigator as any).mediaDevices.getUserMedia(settings).then(success).catch(fail); };
return (navigator as any).getUserMedia || (navigator as any).webkitGetUserMedia || (navigator as any).mozGetUserMedia;
2018-10-28 22:01:09 +00:00
}
2018-10-06 13:13:45 +00:00
function setup_close() {
window.onbeforeunload = event => {
if(profiles.requires_save())
profiles.save();
2018-10-06 13:13:45 +00:00
if(!settings.static(Settings.KEY_DISABLE_UNLOAD_DIALOG, false)) {
if(!globalClient.serverConnection || !globalClient.serverConnection.connected) return;
2018-10-06 13:13:45 +00:00
if(!native_client) {
event.returnValue = "Are you really sure?<br>You're still connected!";
} else {
event.preventDefault();
event.returnValue = "question";
2018-10-06 13:13:45 +00:00
const {remote} = require('electron');
const dialog = remote.dialog;
dialog.showMessageBox(remote.getCurrentWindow(), {
2018-10-06 13:13:45 +00:00
type: 'question',
buttons: ['Yes', 'No'],
title: 'Confirm',
message: 'Are you really sure?\nYou\'re still connected!'
}, choice => {
if(choice === 0) {
window.onbeforeunload = undefined;
remote.getCurrentWindow().close();
}
});
}
2018-10-06 13:13:45 +00:00
}
};
}
declare function moment(...arguments) : any;
function setup_jsrender() : boolean {
if(!js_render) {
displayCriticalError("Missing jsrender extension!");
return false;
}
2018-10-07 16:21:28 +00:00
if(!js_render.views) {
displayCriticalError("Missing jsrender viewer extension!");
return false;
2018-10-07 16:21:28 +00:00
}
js_render.views.settings.allowCode(true);
js_render.views.tags("rnd", (argument) => {
2018-06-24 11:38:53 +00:00
let min = parseInt(argument.substr(0, argument.indexOf('~')));
let max = parseInt(argument.substr(argument.indexOf('~') + 1));
return (Math.round(Math.random() * (min + max + 1) - min)).toString();
});
js_render.views.tags("fmt_date", (...args) => {
return moment(args[0]).format(args[1]);
});
js_render.views.tags("tr", (...args) => {
return tr(args[0]);
});
$(".jsrender-template").each((idx, _entry) => {
if(!js_render.templates(_entry.id, _entry.innerHTML)) { //, _entry.innerHTML
console.error("Failed to cache template " + _entry.id + " for js render!");
} else
console.debug("Successfully loaded jsrender template " + _entry.id);
});
return true;
}
async function initialize() {
const display_load_error = message => {
if(typeof(display_critical_load) !== "undefined")
display_critical_load(message);
else
displayCriticalError(message);
};
settings = new Settings();
try {
await i18n.initialize();
} catch(error) {
console.error(tr("Failed to initialized the translation system!\nError: %o"), error);
displayCriticalError("Failed to setup the translation system");
return;
}
try {
if(!setup_jsrender())
throw "invalid load";
} catch (error) {
display_load_error(tr("Failed to setup jsrender"));
console.error(tr("Failed to load jsrender! %o"), error);
return;
}
try { //Initialize main template
2019-01-19 12:03:51 +00:00
const main = $("#tmpl_main").renderTag().dividerfy();
$("body").append(main);
} catch(error) {
2018-12-30 00:38:13 +00:00
console.error(error);
display_load_error(tr("Failed to setup main page!"));
return;
}
2018-04-11 15:56:09 +00:00
AudioController.initializeAudioController();
await profiles.load();
2018-04-11 15:56:09 +00:00
try {
await ppt.initialize();
} catch(error) {
console.error(tr("Failed to initialize ppt!\nError: %o"), error);
displayCriticalError(tr("Failed to initialize ppt!"));
return;
}
Implemented the Material Design and fixed some bugs (#33) * cleaned up some files * Fundamental style update * Redesigned some style * fixed hostbanner popup * Removed old identity stuff * fixed close listener * Fixed changelog date * fixed release chat icons * fixed url * Fixed hostbanner * Uploaded missing images * Improved update handling * Improved script files * Fixed loading error and icon error * fixed Yes/No modal * Fixed loader issues with MS Edge * fixed modal style bug * Fixed control bar overflow for small devices * Improved error handling on identity creation * Logging generate error to terminal * fixed possible php error * fixed some possible loading errors when other files have'nt been already loaded. * removed debug message * Changed emsrcypten flags * Improved codec error handling * removed webassembly as required dependency * Improved and fixed channel tree issues * Improved the sliders * Removed unneeded files * fixed loader versions cache * second slight performance improved (dont animate elements anymore if they are not shown) * Fixed query visibility setting * not showing useless client infos for query clients * Added an auto reconnect system * Added a canceled message and increased reconnect interval * removed implemented todo * fixed repetitive channel names * Reworked the channel tree selected lines * Fixed channel tree names * Fixed name alignment * fixed the native client * added min width to the server select groups to avoid a disappearing effect on shrink * fixed bugged downloaded icons
2019-02-17 15:08:10 +00:00
setup_close();
}
function ab2str(buf) {
return String.fromCharCode.apply(null, new Uint16Array(buf));
}
function str2ab8(str) {
const buf = new ArrayBuffer(str.length);
const bufView = new Uint8Array(buf);
for (let i = 0, strLen = str.length; i < strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
}
/* FIXME Dont use atob, because it sucks for non UTF-8 tings */
function arrayBufferBase64(base64: string) {
base64 = atob(base64);
const buf = new ArrayBuffer(base64.length);
const bufView = new Uint8Array(buf);
for (let i = 0, strLen = base64.length; i < strLen; i++) {
bufView[i] = base64.charCodeAt(i);
}
return buf;
}
function base64ArrayBuffer(arrayBuffer) {
var base64 = ''
var encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
var bytes = new Uint8Array(arrayBuffer)
var byteLength = bytes.byteLength
var byteRemainder = byteLength % 3
var mainLength = byteLength - byteRemainder
var a, b, c, d
var chunk
// Main loop deals with bytes in chunks of 3
for (var i = 0; i < mainLength; i = i + 3) {
// Combine the three bytes into a single integer
chunk = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2]
// Use bitmasks to extract 6-bit segments from the triplet
a = (chunk & 16515072) >> 18 // 16515072 = (2^6 - 1) << 18
b = (chunk & 258048) >> 12 // 258048 = (2^6 - 1) << 12
c = (chunk & 4032) >> 6 // 4032 = (2^6 - 1) << 6
d = chunk & 63 // 63 = 2^6 - 1
// Convert the raw binary segments to the appropriate ASCII encoding
base64 += encodings[a] + encodings[b] + encodings[c] + encodings[d]
}
// Deal with the remaining bytes and padding
if (byteRemainder == 1) {
chunk = bytes[mainLength]
a = (chunk & 252) >> 2 // 252 = (2^6 - 1) << 2
// Set the 4 least significant bits to zero
b = (chunk & 3) << 4 // 3 = 2^2 - 1
base64 += encodings[a] + encodings[b] + '=='
} else if (byteRemainder == 2) {
chunk = (bytes[mainLength] << 8) | bytes[mainLength + 1]
a = (chunk & 64512) >> 10 // 64512 = (2^6 - 1) << 10
b = (chunk & 1008) >> 4 // 1008 = (2^6 - 1) << 4
// Set the 2 least significant bits to zero
c = (chunk & 15) << 2 // 15 = 2^4 - 1
base64 += encodings[a] + encodings[b] + encodings[c] + '='
}
return base64
}
function Base64EncodeUrl(str){
return str.replace(/\+/g, '-').replace(/\//g, '_').replace(/\=+$/, '');
}
function Base64DecodeUrl(str: string, pad?: boolean){
if(typeof(pad) === 'undefined' || pad)
str = (str + '===').slice(0, str.length + (str.length % 4));
return str.replace(/-/g, '+').replace(/_/g, '/');
}
function main() {
//http://localhost:63343/Web-Client/index.php?_ijt=omcpmt8b9hnjlfguh8ajgrgolr&default_connect_url=true&default_connect_type=teamspeak&default_connect_url=localhost%3A9987&disableUnloadDialog=1&loader_ignore_age=1
2018-03-24 22:38:01 +00:00
globalClient = new TSClient();
2018-04-11 15:56:09 +00:00
/** Setup the XF forum identity **/
profiles.identities.setup_forum();
2018-04-11 15:56:09 +00:00
2018-03-24 22:38:01 +00:00
chat = new ChatBox($("#chat"));
globalClient.setup();
2018-03-10 08:03:29 +00:00
2019-03-17 11:15:39 +00:00
if(settings.static(Settings.KEY_FLAG_CONNECT_DEFAULT, false) && settings.static(Settings.KEY_CONNECT_ADDRESS, "")) {
const profile_uuid = settings.static(Settings.KEY_CONNECT_PROFILE, (profiles.default_profile() || {id: 'default'}).id);
console.log("UUID: %s", profile_uuid);
2018-12-30 00:38:13 +00:00
const profile = profiles.find_profile(profile_uuid) || profiles.default_profile();
2019-03-17 11:15:39 +00:00
const address = settings.static(Settings.KEY_CONNECT_ADDRESS, "");
const username = settings.static(Settings.KEY_CONNECT_USERNAME, "Another TeaSpeak user");
2018-04-30 21:57:21 +00:00
2019-03-17 11:15:39 +00:00
const password = settings.static(Settings.KEY_CONNECT_PASSWORD, "");
const password_hashed = settings.static(Settings.KEY_FLAG_CONNECT_PASSWORD, false);
2019-01-20 17:43:14 +00:00
Implemented the Material Design and fixed some bugs (#33) * cleaned up some files * Fundamental style update * Redesigned some style * fixed hostbanner popup * Removed old identity stuff * fixed close listener * Fixed changelog date * fixed release chat icons * fixed url * Fixed hostbanner * Uploaded missing images * Improved update handling * Improved script files * Fixed loading error and icon error * fixed Yes/No modal * Fixed loader issues with MS Edge * fixed modal style bug * Fixed control bar overflow for small devices * Improved error handling on identity creation * Logging generate error to terminal * fixed possible php error * fixed some possible loading errors when other files have'nt been already loaded. * removed debug message * Changed emsrcypten flags * Improved codec error handling * removed webassembly as required dependency * Improved and fixed channel tree issues * Improved the sliders * Removed unneeded files * fixed loader versions cache * second slight performance improved (dont animate elements anymore if they are not shown) * Fixed query visibility setting * not showing useless client infos for query clients * Added an auto reconnect system * Added a canceled message and increased reconnect interval * removed implemented todo * fixed repetitive channel names * Reworked the channel tree selected lines * Fixed channel tree names * Fixed name alignment * fixed the native client * added min width to the server select groups to avoid a disappearing effect on shrink * fixed bugged downloaded icons
2019-02-17 15:08:10 +00:00
if(profile && profile.valid()) {
2019-01-20 17:43:14 +00:00
globalClient.startConnection(address, profile, username, password.length > 0 ? {
password: password,
hashed: password_hashed
} : undefined);
2018-12-30 00:51:34 +00:00
} else {
Modals.spawnConnectModal({
url: address,
enforce: true
}, {
profile: profile,
enforce: true
});
}
2018-12-30 00:38:13 +00:00
}
2018-11-03 23:39:29 +00:00
2019-01-26 17:06:42 +00:00
let _resize_timeout: NodeJS.Timer;
2018-10-06 13:13:45 +00:00
$(window).on('resize', () => {
2018-11-03 23:39:29 +00:00
if(_resize_timeout)
clearTimeout(_resize_timeout);
_resize_timeout = setTimeout(() => {
globalClient.channelTree.handle_resized();
2019-03-07 14:30:53 +00:00
globalClient.selectInfo.handle_resize();
2018-11-03 23:39:29 +00:00
}, 1000);
2018-10-06 13:13:45 +00:00
});
2019-02-25 14:59:42 +00:00
stats.initialize({
verbose: true,
anonymize_ip_addresses: true,
volatile_collection_only: false
});
stats.register_user_count_listener(status => {
console.log("Received user count update: %o", status);
});
2019-03-25 19:04:04 +00:00
/*
setTimeout(() => {
Modals.spawnAvatarList(globalClient);
}, 1000);
*/
2018-04-19 16:42:34 +00:00
}
2018-12-30 00:38:13 +00:00
loader.register_task(loader.Stage.LOADED, {
name: "async main invoke",
function: async () => {
try {
await initialize();
main();
if(!audio.player.initialized()) {
log.info(LogCategory.VOICE, tr("Initialize audio controller later!"));
if(!audio.player.initializeFromGesture) {
console.error(tr("Missing audio.player.initializeFromGesture"));
} else
$(document).one('click', event => audio.player.initializeFromGesture());
}
} catch (ex) {
console.error(ex.stack);
if(ex instanceof ReferenceError || ex instanceof TypeError)
ex = ex.name + ": " + ex.message;
displayCriticalError("Failed to invoke main function:<br>" + ex);
2018-09-25 15:39:38 +00:00
}
2018-12-30 00:38:13 +00:00
},
priority: 10
2018-10-06 13:13:45 +00:00
});
2018-12-30 00:38:13 +00:00