2020-07-13 11:29:16 +02:00
import "./shared" ;
2020-04-01 15:36:37 +02:00
import * as loader from "../loader/loader" ;
2020-07-13 11:29:16 +02:00
import { config , SourcePath } from "../loader/loader" ;
import { script_name } from "../loader/utils" ;
import { detect as detectBrowser } from "detect-browser" ;
2019-08-30 23:06:39 +02:00
2020-03-30 13:44:18 +02:00
declare global {
interface Window {
native_client : boolean ;
2019-08-30 23:06:39 +02:00
}
2020-03-30 13:44:18 +02:00
}
2019-08-30 23:06:39 +02:00
2020-03-30 13:44:18 +02:00
const node_require : typeof require = window . require ;
2019-08-30 23:06:39 +02:00
2020-03-31 01:27:59 +02:00
function cache_tag() {
const ui = ui_version ( ) ;
return "?_ts=" + ( ! ! ui && ui !== "unknown" ? ui : Date.now ( ) ) ;
}
2020-03-30 13:44:18 +02:00
let _ui_version ;
export function ui_version() {
if ( typeof ( _ui_version ) !== "string" ) {
const version_node = document . getElementById ( "app_version" ) ;
if ( ! version_node ) return undefined ;
2019-08-30 23:06:39 +02:00
2020-03-30 13:44:18 +02:00
const version = version_node . hasAttribute ( "value" ) ? version_node . getAttribute ( "value" ) : undefined ;
if ( ! version ) return undefined ;
2019-08-30 23:06:39 +02:00
2020-03-30 13:44:18 +02:00
return ( _ui_version = version ) ;
2019-08-30 23:06:39 +02:00
}
2020-03-30 13:44:18 +02:00
return _ui_version ;
2019-08-30 23:06:39 +02:00
}
2020-03-31 01:27:59 +02:00
interface Manifest {
version : number ;
chunks : { [ key : string ] : {
2020-04-01 21:47:33 +02:00
files : {
hash : string ,
file : string
} [ ] ,
modules : {
id : string ,
context : string ,
resource : string
} [ ]
} } ;
2020-04-01 15:36:37 +02:00
}
2020-07-13 11:29:16 +02:00
const LoaderTaskCallback = taskId = > ( script : SourcePath , state ) = > {
if ( state !== "loading" )
return ;
loader . setCurrentTaskName ( taskId , script_name ( script , false ) ) ;
} ;
2019-08-30 23:06:39 +02:00
/* all javascript loaders */
const loader_javascript = {
2020-07-13 11:29:16 +02:00
load_scripts : async taskId = > {
2019-08-30 23:06:39 +02:00
if ( ! window . require ) {
2020-07-13 11:29:16 +02:00
await loader . scripts . load_multiple ( [ "vendor/jquery/jquery.min.js" ] , { cache_tag : cache_tag ( ) } , LoaderTaskCallback ( taskId ) ) ;
2019-08-30 23:06:39 +02:00
}
2020-03-31 01:27:59 +02:00
await loader . scripts . load_multiple ( [
2020-03-31 16:43:21 +02:00
[ "vendor/jsrender/jsrender.min.js" ] ,
2019-08-30 23:06:39 +02:00
[ "vendor/remarkable/remarkable.min.js" , "" ] , /* empty string means not required */
2020-03-31 01:27:59 +02:00
] , {
cache_tag : cache_tag ( ) ,
max_parallel_requests : - 1
2020-07-13 11:29:16 +02:00
} , LoaderTaskCallback ( taskId ) ) ;
2020-03-31 01:27:59 +02:00
2020-07-13 11:29:16 +02:00
loader . setCurrentTaskName ( taskId , "manifest" ) ;
2020-03-31 01:27:59 +02:00
let manifest : Manifest ;
try {
2020-06-10 22:44:24 +02:00
const response = await fetch ( config . baseUrl + "js/manifest.json" ) ;
2020-03-31 01:27:59 +02:00
if ( ! response . ok ) throw response . status + " " + response . statusText ;
manifest = await response . json ( ) ;
} catch ( error ) {
console . error ( "Failed to load javascript manifest: %o" , error ) ;
loader . critical_error ( "Failed to load manifest.json" , error ) ;
throw "failed to load manifest.json" ;
2019-08-30 23:06:39 +02:00
}
2020-04-01 21:47:33 +02:00
if ( manifest . version !== 2 )
2020-03-31 01:27:59 +02:00
throw "invalid manifest version" ;
2019-08-30 23:06:39 +02:00
2020-04-01 21:47:33 +02:00
const chunk_name = __build . entry_chunk_name ;
if ( typeof manifest . chunks [ chunk_name ] !== "object" ) {
2020-04-01 15:36:37 +02:00
loader . critical_error ( "Missing entry chunk in manifest.json" , "Chunk " + chunk_name + " is missing." ) ;
throw "missing entry chunk" ;
}
2020-04-01 21:47:33 +02:00
loader . module_mapping ( ) . push ( {
application : chunk_name ,
modules : manifest.chunks [ chunk_name ] . modules
} ) ;
await loader . scripts . load_multiple ( manifest . chunks [ chunk_name ] . files . map ( e = > "js/" + e . file ) , {
2020-03-31 01:27:59 +02:00
cache_tag : undefined ,
max_parallel_requests : - 1
2020-07-13 11:29:16 +02:00
} , LoaderTaskCallback ( taskId ) ) ;
2019-08-30 23:06:39 +02:00
}
} ;
const loader_webassembly = {
test_webassembly : async ( ) = > {
/ * W e d o n t r e q u i r e d W e b A s s e m b l y a n y m o r e f o r f u n d a m e n t a l f u n c t i o n s , o n l y f o r a u t o d e c o d i n g
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!<br>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 = {
2020-07-13 11:29:16 +02:00
load_style : async taskId = > {
2020-04-01 21:47:33 +02:00
if ( __build . mode === "debug" ) {
2020-07-13 11:29:16 +02:00
await loader_style . load_style_debug ( taskId ) ;
2019-08-30 23:06:39 +02:00
} else {
2020-07-13 11:29:16 +02:00
await loader_style . load_style_release ( taskId ) ;
2019-08-30 23:06:39 +02:00
}
} ,
2020-07-13 11:29:16 +02:00
load_style_debug : async taskId = > {
2020-03-31 01:27:59 +02:00
await loader . style . load_multiple ( [
2019-08-30 23:06:39 +02:00
"css/static/main.css" ,
"css/static/main-layout.css" ,
"css/static/scroll.css" ,
"css/static/channel-tree.css" ,
"css/static/ts/tab.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" ,
2019-11-09 15:56:01 +01:00
"css/static/modal-latency.css" ,
2019-08-30 23:06:39 +02:00
"css/static/modal-invite.css" ,
"css/static/modal-banlist.css" ,
2019-09-19 01:25:57 +02:00
"css/static/modal-banclient.css" ,
"css/static/modal-channelinfo.css" ,
2019-08-30 23:06:39 +02:00
"css/static/modal-clientinfo.css" ,
"css/static/modal-serverinfo.css" ,
2020-02-22 14:30:17 +01:00
"css/static/modal-musicmanage.css" ,
2019-09-12 23:59:35 +02:00
"css/static/modal-serverinfobandwidth.css" ,
2019-08-30 23:06:39 +02:00
"css/static/modal-identity.css" ,
2020-03-27 16:15:15 +01:00
"css/static/modal-newcomer.css" ,
2019-08-30 23:06:39 +02:00
"css/static/modal-settings.css" ,
"css/static/modal-poke.css" ,
"css/static/modal-server.css" ,
"css/static/modal-keyselect.css" ,
"css/static/modal-group-assignment.css" ,
2020-03-19 14:31:45 +01:00
"css/static/overlay-image-preview.css" ,
2019-08-30 23:06:39 +02:00
"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"
2020-03-31 01:27:59 +02:00
] , {
cache_tag : cache_tag ( ) ,
max_parallel_requests : - 1
2020-07-13 11:29:16 +02:00
} , LoaderTaskCallback ( taskId ) ) ;
2019-08-30 23:06:39 +02:00
} ,
2020-07-13 11:29:16 +02:00
load_style_release : async taskId = > {
2020-03-31 01:27:59 +02:00
await loader . style . load_multiple ( [
2019-08-30 23:06:39 +02:00
"css/static/base.css" ,
"css/static/main.css" ,
2020-03-31 01:27:59 +02:00
] , {
cache_tag : cache_tag ( ) ,
max_parallel_requests : - 1
2020-07-13 11:29:16 +02:00
} , LoaderTaskCallback ( taskId ) ) ;
2019-08-30 23:06:39 +02:00
}
} ;
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" )
2020-07-13 11:29:16 +02:00
( < any > window ) [ "isSecureContext" ] = location . protocol !== 'https:' || location . hostname === 'localhost' ;
2019-08-30 23:06:39 +02:00
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 . JAVASCRIPT , {
2020-07-13 11:29:16 +02:00
name : "scripts" ,
2019-08-30 23:06:39 +02:00
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" ,
2020-07-13 11:29:16 +02:00
function : async taskId = > {
2020-03-31 01:27:59 +02:00
await loader . templates . load_multiple ( [
2020-02-22 14:30:17 +01:00
"templates.html" ,
2020-03-27 16:15:15 +01:00
"templates/modal/musicmanage.html" ,
"templates/modal/newcomer.html" ,
2020-03-31 01:27:59 +02:00
] , {
cache_tag : cache_tag ( ) ,
max_parallel_requests : - 1
2020-07-13 11:29:16 +02:00
} , LoaderTaskCallback ( taskId ) ) ;
2020-02-22 14:30:17 +01:00
} ,
2019-08-30 23:06:39 +02:00
priority : 10
} ) ;
2019-08-31 18:31:01 +02:00
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" ) ;
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
} ) ;
2019-09-19 01:25:57 +02:00
/* 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
} ) ;
2020-03-30 13:44:18 +02:00
export function run() {
/* TeaClient */
if ( node_require ) {
2020-04-01 21:47:33 +02:00
if ( __build . target !== "client" ) {
loader . critical_error ( "App seems not to be compiled for the client." , "This app has been compiled for " + __build . target ) ;
return ;
}
2020-04-01 15:36:37 +02:00
window . native_client = true ;
2020-03-30 13:44:18 +02:00
const path = node_require ( "path" ) ;
const remote = node_require ( 'electron' ) . remote ;
2020-04-01 15:36:37 +02:00
const render_entry = path . join ( remote . app . getAppPath ( ) , "/modules/" , "renderer" ) ;
const render = node_require ( render_entry ) ;
2020-03-30 13:44:18 +02:00
loader . register_task ( loader . Stage . INITIALIZING , {
name : "teaclient initialize" ,
2020-04-01 15:36:37 +02:00
function : render . initialize ,
2020-03-30 13:44:18 +02:00
priority : 40
} ) ;
2020-04-01 15:36:37 +02:00
} else {
2020-04-01 21:47:33 +02:00
if ( __build . target !== "web" ) {
loader . critical_error ( "App seems not to be compiled for the web." , "This app has been compiled for " + __build . target ) ;
return ;
}
2020-04-01 15:36:37 +02:00
window . native_client = false ;
2020-03-30 13:44:18 +02:00
}
2019-08-30 23:06:39 +02:00
2020-03-30 13:44:18 +02:00
if ( ! loader . running ( ) ) {
/* we know that we want to load the app */
loader . execute_managed ( ) ;
}
2019-08-30 23:06:39 +02:00
}