diff --git a/ChangeLog.md b/ChangeLog.md index d45b80c1..67d290ab 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,4 +1,25 @@ # Changelog: +* **17.03.19** + - Using VAD by default instead of PPT + - Improved mobile experience: + - Double touch join channel + - Removed the info bar for devices smaller than 500px + - Added country flags and names + - Added favicon, which change when you're recording + - Fixed double cache loading + - Fixed modal sizing scroll bug + - Added a channel subscribe all button + - Added individual channel subscribe settings + - Improved chat switch performance + - Added a chat message URL finder + - Escape URL detection with `!` + - Improved chat experience + - Displaying offline chats as offline + - Notify when user closes the chat + - Notify when user disconnect/reconnects + - Preloading hostbanners to prevent flickering + - Fixed empty channel and server kick messages + * **17.02.19** - Removed WebAssembly as dependency (Now working with MS Edge as well (but without audio)) - Improved channel tree performance diff --git a/TeaWeb-release-ad43894.zip b/TeaWeb-release-ad43894.zip new file mode 100644 index 00000000..26ea335d Binary files /dev/null and b/TeaWeb-release-ad43894.zip differ diff --git a/files.php b/files.php index 4e1645dc..dec1bd59 100644 --- a/files.php +++ b/files.php @@ -258,9 +258,97 @@ ], ]; - function list_dir($base_dir, $match = null, $depth = -1, &$results = array(), $dir = "") { + function systemify_path($path) { + return str_replace("/", DIRECTORY_SEPARATOR, $path); + } + + function join_path(...$paths) { + $result_path = ""; + foreach ($paths as $path) { + if(strlen($result_path) > 0) + $result_path .= DIRECTORY_SEPARATOR . $path; + else + $result_path = $path; + } + + return $result_path; + } + + function create_directories(&$error, $path, $dry_run = false) { + if(strpos(PHP_OS, "Linux") !== false) { + $command = "mkdir -p " . $path; + } else if(strpos(PHP_OS, "WINNT") !== false) { + $command = "mkdir " . $path; /* default path tree */ + } else { + $error = "unsupported system"; + return false; + } + + echo $command . PHP_EOL; + if(!$dry_run) { + exec($command, $error, $state); + if($state) { + $error = "Command execution results in " . $state . ": " . implode(' ', $error); + return false; + } + } + return true; + } + + function delete_directories(&$error, $path, $dry_run = false) { + if(strpos(PHP_OS, "Linux") !== false) { + $command = "rm -r " . $path; + } else if(strpos(PHP_OS, "WINNT") !== false) { + $command = "rm -r " . $path; + } else { + $error = "unsupported system"; + return false; + } + + echo $command . PHP_EOL; + if(!$dry_run) { + $state = 0; + exec($command, $output, $state); + + if($state !== 0) { + $error = "Command execution results in " . $state . ": " . implode(' ', $output); + return false; + } + } + return true; + } + + function create_link(&$error, $source, $target, $dry_run = false) { + if(strpos(PHP_OS, "Linux") !== false) { + $command = "ln -s " . $source . " " . $target; + } else if(strpos(PHP_OS, "WINNT") !== false) { + $command = "mklink " . (is_dir($target) ? "/D " : "") . " " . $target . " " . $source; + } else { + $error = "unsupported system"; + return false; + } + + echo $command . PHP_EOL; + if(!$dry_run) { + $state = 0; + exec($command, $output, $state); + + if($state !== 0) { + $error = "Command execution results in " . $state . ": " . implode(' ', $output); + return false; + } + } + return true; + } + + + function list_dir($base_dir, $match = null, $depth = -1, &$results = array(), $dir = "") { if($depth == 0) return $results; + if(!is_dir($base_dir . $dir)) { + echo "Skipping directory " . $base_dir . $dir . PHP_EOL; + return $results; + } $files = scandir($base_dir . $dir); foreach($files as $key => $value){ @@ -279,12 +367,14 @@ class AppFile { public $type; public $name; - public $path; - public $local_path; + + public $target_path; /* relative path to the target file viewed from the file root */ + public $local_path; /* absolute path to local file */ + public $hash; } - function find_files($flag = 0b11, $local_path_prefix = "./", $type = "dev", $args = []) { //TODO Use cache here! + function find_files($flag = 0b11, $local_path_prefix = "." . DIRECTORY_SEPARATOR, $type = "dev", $args = []) { //TODO Use cache here! global $APP_FILE_LIST; $result = []; @@ -303,23 +393,22 @@ if(!$valid) continue; } - $entries = list_dir($local_path_prefix . $entry["local-path"], $entry["search-pattern"], isset($entry["search-depth"]) ? $entry["search-depth"] : -1); + $entries = list_dir( + systemify_path($local_path_prefix . $entry["local-path"]), + $entry["search-pattern"], + isset($entry["search-depth"]) ? $entry["search-depth"] : -1 + ); foreach ($entries as $f_entry) { if(isset($entry["search-exclude"]) && preg_match($entry["search-exclude"], $f_entry)) continue; $file = new AppFile; - $idx_sep = strrpos($f_entry, DIRECTORY_SEPARATOR); - $file->path = "./" . $entry["path"] . "/"; - if($idx_sep > 0) { - $file->name = substr($f_entry, strrpos($f_entry, DIRECTORY_SEPARATOR) + 1); - $file->path = $file->path . substr($f_entry, 0, strrpos($f_entry, DIRECTORY_SEPARATOR)); - } else { - $file->name = $f_entry; - } + $f_info = pathinfo($f_entry); + $file->target_path = systemify_path($entry["path"]) . DIRECTORY_SEPARATOR . $f_info["dirname"] . DIRECTORY_SEPARATOR; + $file->local_path = getcwd() . DIRECTORY_SEPARATOR . systemify_path($entry["local-path"]) . DIRECTORY_SEPARATOR . $f_info["dirname"] . DIRECTORY_SEPARATOR; - $file->local_path = $local_path_prefix . $entry["local-path"] . DIRECTORY_SEPARATOR . $f_entry; + $file->name = $f_info["basename"]; $file->type = $entry["type"]; - $file->hash = sha1_file($file->local_path); + $file->hash = sha1_file($file->local_path . DIRECTORY_SEPARATOR . $file->name); if(strlen($file->hash) > 0) { foreach ($result as $e) @@ -334,10 +423,17 @@ } if(isset($_SERVER["argv"])) { //Executed by command line - if(strpos(PHP_OS, "Linux") == -1) { - error_log("Invalid operating system! Help tool only available under linux!"); - exit(1); - } + $supported = false; + if(strpos(PHP_OS, "Linux") !== false) { + $supported = true; + } else if(strpos(PHP_OS, "WIN") !== false) { + $supported = true; + } + if(!$supported) { + error_log("Invalid operating system (" . PHP_OS . ")! Help tool only available under linux!"); + exit(1); + } + if(count($_SERVER["argv"]) < 2) { error_log("Invalid parameters!"); goto help; @@ -358,10 +454,10 @@ if($_SERVER["argv"][3] == "dev" || $_SERVER["argv"][3] == "development") { if ($_SERVER["argv"][2] == "web") { $flagset = 0b01; - $environment = "web/environment/development"; + $environment = join_path("web", "environment", "development"); } else if ($_SERVER["argv"][2] == "client") { $flagset = 0b10; - $environment = "client-api/environment/ui-files/raw"; + $environment = join_path("client-api", "environment", "ui-files", "raw"); } else { error_log("Invalid type!"); goto help; @@ -370,10 +466,10 @@ $type = "rel"; if ($_SERVER["argv"][2] == "web") { $flagset = 0b01; - $environment = "web/environment/release"; + $environment = join_path("web", "environment", "release"); } else if ($_SERVER["argv"][2] == "client") { $flagset = 0b10; - $environment = "client-api/environment/ui-files/raw"; + $environment = join_path("client-api", "environment", "ui-files", "raw"); } else { error_log("Invalid type!"); goto help; @@ -385,37 +481,29 @@ { if(!$dry_run) { - exec($command = "rm -r " . $environment, $output, $state); - exec($command = "mkdir -p " . $environment, $output, $state); if($state) goto handle_error; + if(delete_directories($error, $environment) === false) + goto handle_error; + + if(create_directories($error, $environment) === false) + goto handle_error; } - $files = find_files($flagset, "./", $type, array_slice($_SERVER["argv"], 4)); + $files = find_files($flagset, "." . DIRECTORY_SEPARATOR, $type, array_slice($_SERVER["argv"], 4)); $original_path = realpath("."); if(!chdir($environment)) { error_log("Failed to enter directory " . $environment . "!"); exit(1); } - foreach($files as $file) { - if(!$dry_run && !is_dir($file->path)) { - exec($command = "mkdir -p " . $file->path, $output, $state); - if($state) goto handle_error; + /** @var AppFile $file */ + foreach($files as $file) { + if(!$dry_run && !is_dir($file->target_path) && strlen($file->target_path) > 0) { + if(create_directories($error, $file->target_path, $dry_run) === false) + goto handle_error; } - $parent_base = substr_count(realpath($file->path), DIRECTORY_SEPARATOR) - substr_count(realpath('.'), DIRECTORY_SEPARATOR); - $parent_file = substr_count(realpath("."), DIRECTORY_SEPARATOR) - substr_count($original_path, DIRECTORY_SEPARATOR); //Current to parent - $parent = $parent_base + $parent_file; - - $path = ""; - for($index = 0; $index < $parent; $index++) - $path = $path . "../"; - - $command = "ln -s " . $path . $file->local_path . " " . $file->path; - if(!$dry_run) { - exec($command, $output, $state); - if($state) goto handle_error; - } - echo $command . PHP_EOL; + if(create_link($output, $file->local_path . $file->name, $file->target_path . $file->name, $dry_run) === false) + goto handle_error; } if(!chdir($original_path)) { error_log("Failed to reset directory!"); @@ -425,18 +513,20 @@ } if(!$dry_run) { - exec("./scripts/git_index.sh sort-tag", $output, $state); + exec("." . DIRECTORY_SEPARATOR . "scripts" . DIRECTORY_SEPARATOR . "git_index.sh sort-tag", $output, $state); file_put_contents($environment . DIRECTORY_SEPARATOR . "version", $output); if ($_SERVER["argv"][2] == "client") { - if(!chdir("client-api/environment")) { + if(!chdir("client-api" . DIRECTORY_SEPARATOR . "environment")) { error_log("Failed to enter directory client-api/environment!"); exit(1); } - if(!is_dir("versions/beta")) - exec($command = "mkdir -p versions/beta", $output, $state); if($state) goto handle_error; - if(!is_dir("versions/stable")) - exec($command = "mkdir -p versions/beta", $output, $state); if($state) goto handle_error; + if(!is_dir("versions" . DIRECTORY_SEPARATOR . "beta")) { + exec($command = "mkdir -p versions/beta", $output, $state); if($state) goto handle_error; + } + if(!is_dir("versions/stable")) { + exec($command = "mkdir -p versions/beta", $output, $state); if($state) goto handle_error; + } exec($command = "ln -s ../api.php ./", $output, $state); $state = 0; //Dont handle an error here! if($state) goto handle_error; @@ -445,10 +535,8 @@ exit(0); handle_error: - error_log("Failed to execute command '" . $command . "'!"); - error_log("Command returned code " . $state . ". Output: " . PHP_EOL); - foreach ($output as $line) - error_log($line); + error_log("Command execution failed!"); + error_log("Error message: " . $error); exit(1); } } \ No newline at end of file diff --git a/package.json b/package.json index b0abb3d9..7b2decef 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,9 @@ "directories": {}, "scripts": { "compile-sass": "sass --update .:.", - "build-worker": "tsc -p shared/js/workers/tsconfig_worker_codec.json", + "build-worker-codec": "tsc -p shared/js/workers/tsconfig_worker_codec.json", + "build-worker-pow": "tsc -p shared/js/workers/tsconfig_worker_pow.json", + "build-worker": "npm run build-worker-codec; npm run build-worker-pow;", "dtsgen": "node tools/dtsgen/index.js", "trgen": "node tools/trgen/index.js", "ttsc": "ttsc", diff --git a/scripts/web_build.sh b/scripts/web_build.sh index f06d1336..9fda09ea 100755 --- a/scripts/web_build.sh +++ b/scripts/web_build.sh @@ -28,9 +28,14 @@ if [[ $? -ne 0 ]]; then fi echo "Generating web workers" -npm run build-worker +npm run build-worker-codec if [[ $? -ne 0 ]]; then - echo "Failed to build web workers" + echo "Failed to build web worker codec" + exit 1 +fi +npm run build-worker-pow +if [[ $? -ne 0 ]]; then + echo "Failed to build web worker pow" exit 1 fi diff --git a/setup_windows.md b/setup_windows.md new file mode 100644 index 00000000..e637c140 --- /dev/null +++ b/setup_windows.md @@ -0,0 +1,35 @@ +# Setup the develop environment on windows +## 1.0 Requirements +The following tools or applications are required to develop the web client: +- [1.1 IDE](#11-ide) +- [1.2 XAMPP (apache & php)](#12-xampp-with-a-web-server-and-php) +- [1.3 NPM](#13-npm) +- [1.4 Git bash](#14-git-bash) + +### 1.1 IDE +For developing TeaWeb you require and IDE. +Preferable is PHPStorm from Jetbrains because the've already build in compiling on changes. +Else you've to run the compiler to compile the TS or SCSS files to js e.g. css files. + +### 1.2 XAMPP with a web server and PHP +You require PHP (grater than 5) to setup and manage the project files. +PHP is required for the index page as well. +The web server is required for browsing your final environment and watch your result. +The final environment will be found at `web/environemnt/development/`. More information about +the file structure could be found [here (TODO: link me!)](). + +### 1.3 NPM +NPM min 6.X is required to develop this project. +With NPM you could easily download all required dependencies by just typing `npm install`. +IMPORTANT: NPM must be available within the PATH environment variable! + +### 1.4 Git bash +For using the `.sh` build scripts you require Git Bash. +A minimum of 4.2 is recommend, but in general every version should work. + +## 2.0 Development environment setup +### 2.1 Native code (codecs) (Not required) +If you dont want to develop the codec part or something related to the native +webassembly part of TeaWeb you could skip this step and follow the steps in [2.1-b](#21-b-skip-native-code-setup) + +### 2.1-b Skip native code setup diff --git a/shared/css/static/channel-tree.scss b/shared/css/static/channel-tree.scss index 21c92257..ee2eb2f4 100644 --- a/shared/css/static/channel-tree.scss +++ b/shared/css/static/channel-tree.scss @@ -37,6 +37,7 @@ flex-direction: row; justify-content: stretch; + cursor: pointer; margin-left: 0; .server_type { @@ -134,6 +135,10 @@ display: block; } } + + .icon_no_sound { + display: flex; + } } .container-clients { @@ -193,7 +198,15 @@ } /* all icons related to basic_icons */ -.clicon {width:16px;height:16px;background:url('../../img/ts/basic_icons.png') no-repeat;background-size: 16px 608px;} +.clicon { + width:16px; + height:16px; + background:url('../../img/ts/basic_icons.png') no-repeat; + background-size: 16px 608px; + + flex-grow: 0; + flex-shrink: 0; +} .host {background-position: 0 -448px} diff --git a/shared/css/static/control_bar.scss b/shared/css/static/control_bar.scss index 8f4abda1..2ec3a444 100644 --- a/shared/css/static/control_bar.scss +++ b/shared/css/static/control_bar.scss @@ -47,13 +47,11 @@ $background:lightgray; .button-dropdown { .buttons { - display: grid; - grid-template-columns: auto auto; - grid-template-rows: 100%; - grid-gap: 2px; + display: flex; + flex-direction: row; .button { - margin-right: 0px; + margin-right: 0; } .button-dropdown { @@ -83,6 +81,7 @@ $background:lightgray; background-color: rgba(0,0,0,0.4); border-color: rgba(255, 255, 255, .75); /*box-shadow: 0 12px 16px 0 rgba(0,0,0,0.24), 0 17px 50px 0 rgba(0,0,0,0.19);*/ + border-left: 2px solid rgba(255, 255, 255, .75); } } } @@ -103,6 +102,11 @@ $background:lightgray; z-index: 1000; /*box-shadow: 0 12px 16px 0 rgba(0,0,0,0.24), 0 17px 50px 0 rgba(0,0,0,0.19);*/ + + &.right { + + } + .icon { vertical-align: middle; margin-right: 5px; @@ -131,8 +135,8 @@ $background:lightgray; } } - &:hover { - .dropdown.displayed { + &:hover.displayed { + .dropdown { display: block; } } diff --git a/shared/css/static/frame/SelectInfo.scss b/shared/css/static/frame/SelectInfo.scss index bcf52dff..2a98df19 100644 --- a/shared/css/static/frame/SelectInfo.scss +++ b/shared/css/static/frame/SelectInfo.scss @@ -1,11 +1,18 @@ -.select_info_table { } -.select_info_table tr { } -.select_info_table tr td { } +.select_info_table { + tr { + td { + &:nth-child(1) { + font-weight: bold; + padding-right: 5px; + //min-width: max(35%, 20px); + } -.select_info_table tr td:nth-child(1) { - font-weight: bold; - padding-right: 5px; - min-width: 20%; + &:nth-child(2) { + //min-width: max(75%, 40px); + word-break: break-word; + } + } + } } .select_server { @@ -17,21 +24,18 @@ .button-update { width: 100%; - height: 23px; &:disabled { - color: red; pointer-events: none; } - &:not(:disabled) { - color: green; - } } .container { max-height: 100%; display: flex; flex-direction: column; + padding-right: 0; + padding-left: 0; .hostbanner { overflow: hidden; @@ -39,23 +43,27 @@ } } -/* -
-
-
-
- */ .select_info { display: flex; flex-direction: column; justify-content: stretch; width: 100%; + > .close { + z-index: 500; + display: none; + position: absolute; + right: 5px; + top: 5px; + } + > div { width: 100%; } .container-banner { + position: relative; + flex-grow: 1; flex-shrink: 2; max-height: 25%; @@ -74,9 +82,29 @@ position: relative; flex-grow: 1; - img { - position: absolute; - } + .image-container { + display: flex; + flex-direction: row; + justify-content: center; + height: 100%; + + div { + background-position: center; + + &.hostbanner-mode-0 { } + + &.hostbanner-mode-1 { + width: 100%; + height: auto; + } + + &.hostbanner-mode-2 { + background-size: contain!important; + width:100%; + height:100% + } + } + } } } @@ -105,4 +133,13 @@ } } } + + .button-browser-info { + vertical-align: bottom; + cursor: pointer; + + &:hover { + background-color: gray; + } + } } \ No newline at end of file diff --git a/shared/css/static/general.scss b/shared/css/static/general.scss index 8217371c..c0d474b8 100644 --- a/shared/css/static/general.scss +++ b/shared/css/static/general.scss @@ -228,8 +228,14 @@ footer .container { } $separator_thickness: 4px; +$small_device: 650px; +$animation_length: .5s; + .app { + min-width: 350px; + .container-app-main { + position: relative; display: flex; flex-direction: row; justify-content: stretch; @@ -301,8 +307,78 @@ $separator_thickness: 4px; flex-direction: row; justify-content: stretch; } + + + .hide-small { + opacity: 1; + transition: opacity $animation_length linear; + } + + .show-small { + display: none; + + opacity: 0; + transition: opacity $animation_length linear; + } } +@media only screen and (max-width: $small_device) { + .app-container { + right: 0; + left: 0; + bottom: 25px; + top: 0; + + transition: all $animation_length linear; + overflow: auto; + } + + .app { + .container-app-main { + .container-info { + display: none; + position: absolute; + + width: 100%!important; /* override the seperator property */ + height: 100%; + + z-index: 1000; + + &.shown { + display: block; + } + + .select_info { + > .close { + display: block; + } + } + } + + .container-channel-chat + .container-seperator { + display: none; + animation: fadeout $animation_length linear; + } + + .container-channel-chat { + width: 100%!important; /* override the seperator property */ + } + } + } + + .hide-small { + display: none; + opacity: 0; + transition: opacity $animation_length linear; + } + + .show-small { + display: block!important; + + opacity: 1!important; + transition: opacity $animation_length linear; + } +} .container-seperator { background: lightgray; flex-grow: 0; @@ -328,6 +404,7 @@ $separator_thickness: 4px; } .icon-container { + position: relative; display: inline-block; height: 16px; width: 16px; @@ -354,8 +431,6 @@ $separator_thickness: 4px; } html, body { - min-height: 500px; - min-width: 500px; overflow: hidden; } @@ -365,13 +440,24 @@ body { } .icon-playlist-manage { - display: inline-block; - width: 32px; - height: 32px; + &.icon { + width: 16px; + height: 16px; + background-position: -5px -5px; + background-size: 25px; + } + + &.icon_x32 { + width: 32px; + height: 32px; + + background-position: -11px -9px; + background-size: 50px; + } + + display: inline-block; background: url('../../img/music/playlist.svg') no-repeat; - background-position: -11px -9px; - background-size: 50px; } x-content { diff --git a/shared/css/static/ts/chat.scss b/shared/css/static/ts/chat.scss index 51a68352..9fd2d806 100644 --- a/shared/css/static/ts/chat.scss +++ b/shared/css/static/ts/chat.scss @@ -35,6 +35,20 @@ display: inline-block; vertical-align: top; } + + .event-message { /* special formated messages */ + &.event-partner-disconnect { + color: red; + } + + &.event-partner-connect { + color: green; + } + + &.event-partner-closed { + color: orange; + } + } } } } @@ -62,11 +76,9 @@ cursor: pointer; height: 18px; - &.active { - background: #11111111; - } - .btn_close { + display: none; + float: none; margin-right: -5px; margin-left: 8px; @@ -78,9 +90,34 @@ } } - .name, .chatIcon { + .name, .chat-type { display: inline-block; } + + .name { + color: black; + } + + &.closeable { + .btn_close { + display: inline-block; + } + } + + &.active { + background: #11111111; + } + + &.offline { + .name { + color: gray; + } + } + &.unread { + .name { + color: blue; + } + } } } diff --git a/shared/css/static/ts/country.scss b/shared/css/static/ts/country.scss new file mode 100644 index 00000000..4515f67b --- /dev/null +++ b/shared/css/static/ts/country.scss @@ -0,0 +1,1008 @@ +.country { + width: 16px; + height: 11px; + background: url('../../../img/ts/country_icons.png'), url('../../img/ts/country_icons.png') no-repeat; + + flex-shrink: 0; + flex-grow: 0; +} + +.country.flag-ad { + background-position: 0 -11px +} + +.country.flag-ae { + background-position: 0 -22px +} + +.country.flag-af { + background-position: 0 -33px +} + +.country.flag-ag { + background-position: 0 -44px +} + +.country.flag-ai { + background-position: 0 -55px +} + +.country.flag-al { + background-position: 0 -66px +} + +.country.flag-am { + background-position: 0 -77px +} + +.country.flag-an { + background-position: 0 -88px +} + +.country.flag-ao { + background-position: 0 -99px +} + +.country.flag-ar { + background-position: 0 -110px +} + +.country.flag-as { + background-position: 0 -121px +} + +.country.flag-at { + background-position: 0 -132px +} + +.country.flag-au { + background-position: 0 -143px +} + +.country.flag-aw { + background-position: 0 -154px +} + +.country.flag-ax { + background-position: 0 -165px +} + +.country.flag-az { + background-position: 0 -176px +} + +.country.flag-ba { + background-position: 0 -187px +} + +.country.flag-bb { + background-position: 0 -198px +} + +.country.flag-bd { + background-position: 0 -209px +} + +.country.flag-be { + background-position: 0 -220px +} + +.country.flag-bf { + background-position: 0 -231px +} + +.country.flag-bg { + background-position: 0 -242px +} + +.country.flag-bh { + background-position: 0 -253px +} + +.country.flag-bi { + background-position: 0 -264px +} + +.country.flag-bj { + background-position: 0 -275px +} + +.country.flag-bl { + background-position: 0 -286px +} + +.country.flag-bm { + background-position: 0 -297px +} + +.country.flag-bn { + background-position: 0 -308px +} + +.country.flag-bo { + background-position: 0 -319px +} + +.country.flag-br { + background-position: 0 -330px +} + +.country.flag-bs { + background-position: 0 -341px +} + +.country.flag-bt { + background-position: 0 -352px +} + +.country.flag-bv { + background-position: 0 -363px +} + +.country.flag-bw { + background-position: 0 -374px +} + +.country.flag-by { + background-position: 0 -385px +} + +.country.flag-bz { + background-position: 0 -396px +} + +.country.flag-ca { + background-position: 0 -407px +} + +.country.flag-cc { + background-position: 0 -418px +} + +.country.flag-cd { + background-position: 0 -429px +} + +.country.flag-cf { + background-position: 0 -440px +} + +.country.flag-cg { + background-position: 0 -451px +} + +.country.flag-ch { + background-position: 0 -462px +} + +.country.flag-ci { + background-position: 0 -473px +} + +.country.flag-ck { + background-position: 0 -484px +} + +.country.flag-cl { + background-position: 0 -495px +} + +.country.flag-cm { + background-position: 0 -506px +} + +.country.flag-cn { + background-position: 0 -517px +} + +.country.flag-co { + background-position: 0 -528px +} + +.country.flag-cr { + background-position: 0 -539px +} + +.country.flag-cs { + background-position: 0 -550px +} + +.country.flag-cu { + background-position: 0 -561px +} + +.country.flag-cv { + background-position: 0 -572px +} + +.country.flag-cx { + background-position: 0 -583px +} + +.country.flag-cy { + background-position: 0 -594px +} + +.country.flag-cz { + background-position: 0 -605px +} + +.country.flag-de { + background-position: 0 -616px +} + +.country.flag-dj { + background-position: 0 -627px +} + +.country.flag-dk { + background-position: 0 -638px +} + +.country.flag-dm { + background-position: 0 -649px +} + +.country.flag-do { + background-position: 0 -660px +} + +.country.flag-dz { + background-position: 0 -671px +} + +.country.flag-ec { + background-position: 0 -682px +} + +.country.flag-ee { + background-position: 0 -693px +} + +.country.flag-eg { + background-position: 0 -704px +} + +.country.flag-eh { + background-position: 0 -715px +} + +.country.flag-er { + background-position: 0 -726px +} + +.country.flag-es { + background-position: 0 -737px +} + +.country.flag-et { + background-position: 0 -748px +} + +.country.flag-fi { + background-position: 0 -759px +} + +.country.flag-fj { + background-position: 0 -770px +} + +.country.flag-fk { + background-position: 0 -781px +} + +.country.flag-fm { + background-position: 0 -792px +} + +.country.flag-fo { + background-position: 0 -803px +} + +.country.flag-fr { + background-position: 0 -814px +} + +.country.flag-ga { + background-position: 0 -825px +} + +.country.flag-gb { + background-position: 0 -836px +} + +.country.flag-gd { + background-position: 0 -847px +} + +.country.flag-ge { + background-position: 0 -858px +} + +.country.flag-gf { + background-position: 0 -869px +} + +.country.flag-gg { + background-position: 0 -880px +} + +.country.flag-gh { + background-position: 0 -891px +} + +.country.flag-gi { + background-position: 0 -902px +} + +.country.flag-gl { + background-position: 0 -913px +} + +.country.flag-gm { + background-position: 0 -924px +} + +.country.flag-gn { + background-position: 0 -935px +} + +.country.flag-gp { + background-position: 0 -946px +} + +.country.flag-gq { + background-position: 0 -957px +} + +.country.flag-gr { + background-position: 0 -968px +} + +.country.flag-gs { + background-position: 0 -979px +} + +.country.flag-gt { + background-position: 0 -990px +} + +.country.flag-gu { + background-position: 0 -1001px +} + +.country.flag-gw { + background-position: 0 -1012px +} + +.country.flag-gy { + background-position: 0 -1023px +} + +.country.flag-hk { + background-position: 0 -1034px +} + +.country.flag-hm { + background-position: 0 -1045px +} + +.country.flag-hn { + background-position: 0 -1056px +} + +.country.flag-hr { + background-position: 0 -1067px +} + +.country.flag-ht { + background-position: 0 -1078px +} + +.country.flag-hu { + background-position: 0 -1089px +} + +.country.flag-id { + background-position: 0 -1100px +} + +.country.flag-ie { + background-position: 0 -1111px +} + +.country.flag-il { + background-position: 0 -1122px +} + +.country.flag-im { + background-position: 0 -1133px +} + +.country.flag-in { + background-position: 0 -1144px +} + +.country.flag-io { + background-position: 0 -1155px +} + +.country.flag-iq { + background-position: 0 -1166px +} + +.country.flag-ir { + background-position: 0 -1177px +} + +.country.flag-is { + background-position: 0 -1188px +} + +.country.flag-it { + background-position: 0 -1199px +} + +.country.flag-je { + background-position: 0 -1210px +} + +.country.flag-jm { + background-position: 0 -1221px +} + +.country.flag-jo { + background-position: 0 -1232px +} + +.country.flag-jp { + background-position: 0 -1243px +} + +.country.flag-ke { + background-position: 0 -1254px +} + +.country.flag-kg { + background-position: 0 -1265px +} + +.country.flag-kh { + background-position: 0 -1276px +} + +.country.flag-ki { + background-position: 0 -1287px +} + +.country.flag-km { + background-position: 0 -1298px +} + +.country.flag-kn { + background-position: 0 -1309px +} + +.country.flag-kp { + background-position: 0 -1320px +} + +.country.flag-kr { + background-position: 0 -1331px +} + +.country.flag-kw { + background-position: 0 -1342px +} + +.country.flag-ky { + background-position: 0 -1353px +} + +.country.flag-kz { + background-position: 0 -1364px +} + +.country.flag-la { + background-position: 0 -1375px +} + +.country.flag-lb { + background-position: 0 -1386px +} + +.country.flag-lc { + background-position: 0 -1397px +} + +.country.flag-li { + background-position: 0 -1408px +} + +.country.flag-lk { + background-position: 0 -1419px +} + +.country.flag-lr { + background-position: 0 -1430px +} + +.country.flag-ls { + background-position: 0 -1441px +} + +.country.flag-lt { + background-position: 0 -1452px +} + +.country.flag-lu { + background-position: 0 -1463px +} + +.country.flag-lv { + background-position: 0 -1474px +} + +.country.flag-ly { + background-position: 0 -1485px +} + +.country.flag-ma { + background-position: 0 -1496px +} + +.country.flag-mc { + background-position: 0 -1507px +} + +.country.flag-md { + background-position: 0 -1518px +} + +.country.flag-me { + background-position: 0 -1529px +} + +.country.flag-mg { + background-position: 0 -1540px +} + +.country.flag-mh { + background-position: 0 -1551px +} + +.country.flag-mk { + background-position: 0 -1562px +} + +.country.flag-ml { + background-position: 0 -1573px +} + +.country.flag-mm { + background-position: 0 -1584px +} + +.country.flag-mn { + background-position: 0 -1595px +} + +.country.flag-mo { + background-position: 0 -1606px +} + +.country.flag-mp { + background-position: 0 -1617px +} + +.country.flag-mq { + background-position: 0 -1628px +} + +.country.flag-mr { + background-position: 0 -1639px +} + +.country.flag-ms { + background-position: 0 -1650px +} + +.country.flag-mt { + background-position: 0 -1661px +} + +.country.flag-mu { + background-position: 0 -1672px +} + +.country.flag-mv { + background-position: 0 -1683px +} + +.country.flag-mw { + background-position: 0 -1694px +} + +.country.flag-mx { + background-position: 0 -1705px +} + +.country.flag-my { + background-position: 0 -1716px +} + +.country.flag-mz { + background-position: 0 -1727px +} + +.country.flag-na { + background-position: 0 -1738px +} + +.country.flag-nc { + background-position: 0 -1749px +} + +.country.flag-ne { + background-position: 0 -1760px +} + +.country.flag-nf { + background-position: 0 -1771px +} + +.country.flag-ng { + background-position: 0 -1782px +} + +.country.flag-ni { + background-position: 0 -1793px +} + +.country.flag-nl { + background-position: 0 -1804px +} + +.country.flag-no { + background-position: 0 -1815px +} + +.country.flag-np { + background-position: 0 -1826px +} + +.country.flag-nr { + background-position: 0 -1837px +} + +.country.flag-nu { + background-position: 0 -1848px +} + +.country.flag-nz { + background-position: 0 -1859px +} + +.country.flag-om { + background-position: 0 -1870px +} + +.country.flag-pa { + background-position: 0 -1881px +} + +.country.flag-pe { + background-position: 0 -1892px +} + +.country.flag-pf { + background-position: 0 -1903px +} + +.country.flag-pg { + background-position: 0 -1914px +} + +.country.flag-ph { + background-position: 0 -1925px +} + +.country.flag-pk { + background-position: 0 -1936px +} + +.country.flag-pl { + background-position: 0 -1947px +} + +.country.flag-pm { + background-position: 0 -1958px +} + +.country.flag-pn { + background-position: 0 -1969px +} + +.country.flag-pr { + background-position: 0 -1980px +} + +.country.flag-ps { + background-position: 0 -1991px +} + +.country.flag-pt { + background-position: 0 -2002px +} + +.country.flag-pw { + background-position: 0 -2013px +} + +.country.flag-py { + background-position: 0 -2024px +} + +.country.flag-qa { + background-position: 0 -2035px +} + +.country.flag-re { + background-position: 0 -2046px +} + +.country.flag-ro { + background-position: 0 -2057px +} + +.country.flag-rs { + background-position: 0 -2068px +} + +.country.flag-ru { + background-position: 0 -2079px +} + +.country.flag-rw { + background-position: 0 -2090px +} + +.country.flag-sa { + background-position: 0 -2101px +} + +.country.flag-sb { + background-position: 0 -2112px +} + +.country.flag-sc { + background-position: 0 -2123px +} + +.country.flag-sd { + background-position: 0 -2134px +} + +.country.flag-se { + background-position: 0 -2145px +} + +.country.flag-sg { + background-position: 0 -2156px +} + +.country.flag-sh { + background-position: 0 -2167px +} + +.country.flag-si { + background-position: 0 -2178px +} + +.country.flag-sj { + background-position: 0 -2189px +} + +.country.flag-sk { + background-position: 0 -2200px +} + +.country.flag-sl { + background-position: 0 -2211px +} + +.country.flag-sm { + background-position: 0 -2222px +} + +.country.flag-sn { + background-position: 0 -2233px +} + +.country.flag-so { + background-position: 0 -2244px +} + +.country.flag-sr { + background-position: 0 -2255px +} + +.country.flag-st { + background-position: 0 -2266px +} + +.country.flag-sv { + background-position: 0 -2277px +} + +.country.flag-sy { + background-position: 0 -2288px +} + +.country.flag-sz { + background-position: 0 -2299px +} + +.country.flag-tc { + background-position: 0 -2310px +} + +.country.flag-td { + background-position: 0 -2321px +} + +.country.flag-tf { + background-position: 0 -2332px +} + +.country.flag-tg { + background-position: 0 -2343px +} + +.country.flag-th { + background-position: 0 -2354px +} + +.country.flag-tj { + background-position: 0 -2365px +} + +.country.flag-tk { + background-position: 0 -2376px +} + +.country.flag-tl { + background-position: 0 -2387px +} + +.country.flag-tm { + background-position: 0 -2398px +} + +.country.flag-tn { + background-position: 0 -2409px +} + +.country.flag-to { + background-position: 0 -2420px +} + +.country.flag-tr { + background-position: 0 -2431px +} + +.country.flag-tt { + background-position: 0 -2442px +} + +.country.flag-tv { + background-position: 0 -2453px +} + +.country.flag-tw { + background-position: 0 -2464px +} + +.country.flag-tz { + background-position: 0 -2475px +} + +.country.flag-ua { + background-position: 0 -2486px +} + +.country.flag-ug { + background-position: 0 -2497px +} + +.country.flag-uk { + background-position: 0 -2508px +} + +.country.flag-um { + background-position: 0 -2519px +} + +.country.flag-us { + background-position: 0 -2530px +} + +.country.flag-uy { + background-position: 0 -2541px +} + +.country.flag-uz { + background-position: 0 -2552px +} + +.country.flag-va { + background-position: 0 -2563px +} + +.country.flag-vc { + background-position: 0 -2574px +} + +.country.flag-ve { + background-position: 0 -2585px +} + +.country.flag-vg { + background-position: 0 -2596px +} + +.country.flag-vi { + background-position: 0 -2607px +} + +.country.flag-vn { + background-position: 0 -2618px +} + +.country.flag-vu { + background-position: 0 -2629px +} + +.country.flag-wf { + background-position: 0 -2640px +} + +.country.flag-ws { + background-position: 0 -2651px +} + +.country.flag-ye { + background-position: 0 -2662px +} + +.country.flag-yt { + background-position: 0 -2673px +} + +.country.flag-za { + background-position: 0 -2684px +} + +.country.flag-zm { + background-position: 0 -2695px +} + +.country.flag-zw { + background-position: 0 -2706px +} + +.country.flag-en { + background-position: 0 -2717px +} + +.country.flag-eu { + background-position: 0 -2728px +} + +.country.flag-uk { + background-position: 0 -2739px +} + +.country.flag-unknown { + background-position: 0 -2750px +} diff --git a/shared/css/static/ts/icons.scss b/shared/css/static/ts/icons.scss index 58c69698..5dafecdc 100644 --- a/shared/css/static/ts/icons.scss +++ b/shared/css/static/ts/icons.scss @@ -8,6 +8,9 @@ width: 16px; height: 16px; + flex-shrink: 0; + flex-grow: 0; + background: url('../../../img/client_icon_sprite.svg'), url('../../img/client_icon_sprite.svg') no-repeat; } @@ -1028,7 +1031,7 @@ } .icon_x32.client-refresh { background-position: calc(-224px * 2) calc(-256px * 2); -}pe the key you wish +} .icon_x32.client-register { background-position: calc(-256px * 2) calc(-256px * 2); } diff --git a/shared/css/static/ts/tab.scss b/shared/css/static/ts/tab.scss index 0f6c28e9..a312ae96 100644 --- a/shared/css/static/ts/tab.scss +++ b/shared/css/static/ts/tab.scss @@ -1,7 +1,4 @@ x-tab { display:none } -x-content { - width: 100%; -} .tab { padding: 2px; @@ -18,15 +15,19 @@ x-content { .tab .tab-content { min-height: 200px; - border-color: #6f6f6f; - border-radius: 0px 2px 2px 2px; - border-style: solid; - overflow-y: auto; + border-radius: 0 2px 2px 2px; + border: solid #6f6f6f; + overflow-y: hidden; height: 100%; padding: 2px; display: flex; flex-grow: 1; + + x-content { + overflow-y: auto; + width: 100%; + } } /* @@ -39,7 +40,7 @@ x-content { */ .tab .tab-header { - font-family: Arial; + font-family: Arial, serif; font-size: 12px; /*white-space: pre;*/ line-height: 1; @@ -64,14 +65,10 @@ x-content { .tab .tab-header .entry { background: #5f5f5f5f; display: inline-block; - border: #6f6f6f; - border-width: 1px; - border-style: solid; + border: 1px solid #6f6f6f; border-radius: 2px 2px 0px 0px; vertical-align: middle; - padding: 2px; - padding-left: 5px; - padding-right: 5px; + padding: 2px 5px; cursor: pointer; flex-grow: 1; } diff --git a/shared/html/index.php b/shared/html/index.php index 8a0d60c3..b382804f 100644 --- a/shared/html/index.php +++ b/shared/html/index.php @@ -37,6 +37,7 @@ + ">
-
Open source on github.com
-
TeaSpeak Web client () by WolverinDEV
-
+
Open source on github.com
+
TeaSpeak Web () by WolverinDEV
+
\ No newline at end of file diff --git a/shared/html/templates.html b/shared/html/templates.html index 76903b09..d5beca49 100644 --- a/shared/html/templates.html +++ b/shared/html/templates.html @@ -6,7 +6,6 @@ TeaSpeak-Web client templates - + + + + + +
+ +
+
+ +
+ + + +
+
+ +

Please enable JavaScript

+

TeaSpeak web could not run without it!

+

Its like you, without coffee

+
+
+ + + +
+
+
+
+
    +
  • +
  • +
  • +
  • +
  • +
  • +
+
+
+
+ + +
+
+ +

Ooops, we encountered some trouble while loading important files!

+

+
+
+ +
+
+
+
+
+
+
+ + + logout"; + } else { + $footer_forum = "Login via the TeaSpeak forum."; + } + } + ?> + + + \ No newline at end of file diff --git a/test/js/client.js b/test/js/client.js new file mode 100644 index 00000000..5fe526e9 --- /dev/null +++ b/test/js/client.js @@ -0,0 +1,19226 @@ +/// +var ppt; +(function (ppt) { + let key_listener = []; + function listener_key(type, event) { + const key_event = { + type: type, + key: event.key, + key_code: event.code, + key_ctrl: event.ctrlKey, + key_shift: event.shiftKey, + key_alt: event.altKey, + key_windows: event.metaKey, + canceled: event.defaultPrevented + }; + //console.debug("Trigger key event %o", key_event); + for (const listener of key_listener) + listener(key_event); + if (key_event.canceled) + event.preventDefault(); + } + const proxy_key_press = event => listener_key(ppt.EventType.KEY_PRESS, event); + const proxy_key_release = event => listener_key(ppt.EventType.KEY_RELEASE, event); + const proxy_key_typed = event => listener_key(ppt.EventType.KEY_TYPED, event); + function initialize() { + document.addEventListener('keypress', proxy_key_typed); + document.addEventListener('keydown', proxy_key_press); + document.addEventListener('keyup', proxy_key_release); + register_key_listener(listener_hook); + return Promise.resolve(); + } + ppt.initialize = initialize; + function finalize() { + document.removeEventListener("keypress", proxy_key_typed); + document.removeEventListener("keydown", proxy_key_press); + document.removeEventListener("keyup", proxy_key_release); + unregister_key_listener(listener_hook); + } + ppt.finalize = finalize; + function register_key_listener(listener) { + key_listener.push(listener); + } + ppt.register_key_listener = register_key_listener; + function unregister_key_listener(listener) { + key_listener.remove(listener); + } + ppt.unregister_key_listener = unregister_key_listener; + let key_hooks = []; + let current_state = { + special: [] + }; + let key_hooks_active = []; + function listener_hook(event) { + if (event.type == ppt.EventType.KEY_TYPED) + return; + let old_hooks = [...key_hooks_active]; + let new_hooks = []; + current_state.special[ppt.SpecialKey.ALT] = event.key_alt; + current_state.special[ppt.SpecialKey.CTRL] = event.key_ctrl; + current_state.special[ppt.SpecialKey.SHIFT] = event.key_shift; + current_state.special[ppt.SpecialKey.WINDOWS] = event.key_windows; + current_state.code = undefined; + current_state.event = undefined; + if (event.type == ppt.EventType.KEY_PRESS) { + current_state.event = event; + current_state.code = event.key_code; + for (const hook of key_hooks) { + if (hook.key_code != event.key_code) + continue; + if (hook.key_alt != event.key_alt) + continue; + if (hook.key_ctrl != event.key_ctrl) + continue; + if (hook.key_shift != event.key_shift) + continue; + if (hook.key_windows != event.key_windows) + continue; + new_hooks.push(hook); + if (!old_hooks.remove(hook) && hook.callback_press) { + hook.callback_press(); + console.debug("Trigger key press for %o!", hook); + } + } + } + //We have a new situation + for (const hook of old_hooks) + if (hook.callback_release) { + hook.callback_release(); + console.debug("Trigger key release for %o!", hook); + } + key_hooks_active = new_hooks; + } + function register_key_hook(hook) { + key_hooks.push(hook); + } + ppt.register_key_hook = register_key_hook; + function unregister_key_hook(hook) { + key_hooks.remove(hook); + } + ppt.unregister_key_hook = unregister_key_hook; + function key_pressed(code) { + if (typeof (code) === 'string') + return current_state.code == code; + return current_state.special[code]; + } + ppt.key_pressed = key_pressed; +})(ppt || (ppt = {})); +var audio; +(function (audio) { + var player; + (function (player) { + let _globalContext; + let _globalContextPromise; + let _initialized_listener = []; + function initialize() { + context(); + return true; + } + player.initialize = initialize; + function initialized() { + return !!_globalContext && _globalContext.state === 'running'; + } + player.initialized = initialized; + function fire_initialized() { + console.log("Fire initialized: %o", _initialized_listener); + while (_initialized_listener.length > 0) + _initialized_listener.pop_front()(); + } + function context() { + if (_globalContext && _globalContext.state != "suspended") + return _globalContext; + if (!_globalContext) + _globalContext = new (window.webkitAudioContext || window.AudioContext)(); + if (_globalContext.state == "suspended") { + if (!_globalContextPromise) { + (_globalContextPromise = _globalContext.resume()).then(() => { + fire_initialized(); + }).catch(error => { + displayCriticalError("Failed to initialize global audio context! (" + error + ")"); + }); + } + _globalContext.resume(); //We already have our listener + return undefined; + } + if (_globalContext.state == "running") { + fire_initialized(); + return _globalContext; + } + return undefined; + } + player.context = context; + function destination() { + const ctx = context(); + if (!ctx) + throw tr("Audio player isn't initialized yet!"); + return ctx.destination; + } + player.destination = destination; + function on_ready(cb) { + if (initialized()) + cb(); + else + _initialized_listener.push(cb); + } + player.on_ready = on_ready; + player.WEB_DEVICE = { device_id: "", name: "default playback" }; + function available_devices() { + return Promise.resolve([player.WEB_DEVICE]); + } + player.available_devices = available_devices; + function set_device(device_id) { + return Promise.resolve(); + } + player.set_device = set_device; + function current_device() { + return player.WEB_DEVICE; + } + player.current_device = current_device; + function initializeFromGesture() { + context(); + } + player.initializeFromGesture = initializeFromGesture; + })(player = audio.player || (audio.player = {})); +})(audio || (audio = {})); +/// +var audio; +(function (audio) { + var codec; + (function (codec) { + function new_instance(type) { + return new CodecWrapperWorker(type); + } + codec.new_instance = new_instance; + function supported(type) { + return type == CodecType.OPUS_MUSIC || type == CodecType.OPUS_VOICE; + } + codec.supported = supported; + })(codec = audio.codec || (audio.codec = {})); +})(audio || (audio = {})); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { + step(generator.next(value)); + } + catch (e) { + reject(e); + } } + function rejected(value) { try { + step(generator["throw"](value)); + } + catch (e) { + reject(e); + } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["d73415969dab3133f6dd0be5e80d3da9f44d28315f6483e40a8a245397d1600a"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["d73415969dab3133f6dd0be5e80d3da9f44d28315f6483e40a8a245397d1600a"] = "d73415969dab3133f6dd0be5e80d3da9f44d28315f6483e40a8a245397d1600a"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of []) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +var LogCategory; +(function (LogCategory) { + LogCategory[LogCategory["CHANNEL"] = 0] = "CHANNEL"; + LogCategory[LogCategory["CHANNEL_PROPERTIES"] = 1] = "CHANNEL_PROPERTIES"; + LogCategory[LogCategory["CLIENT"] = 2] = "CLIENT"; + LogCategory[LogCategory["SERVER"] = 3] = "SERVER"; + LogCategory[LogCategory["PERMISSIONS"] = 4] = "PERMISSIONS"; + LogCategory[LogCategory["GENERAL"] = 5] = "GENERAL"; + LogCategory[LogCategory["NETWORKING"] = 6] = "NETWORKING"; + LogCategory[LogCategory["VOICE"] = 7] = "VOICE"; + LogCategory[LogCategory["I18N"] = 8] = "I18N"; +})(LogCategory || (LogCategory = {})); +var log; +(function (log_1) { + let LogType; + (function (LogType) { + LogType[LogType["TRACE"] = 0] = "TRACE"; + LogType[LogType["DEBUG"] = 1] = "DEBUG"; + LogType[LogType["INFO"] = 2] = "INFO"; + LogType[LogType["WARNING"] = 3] = "WARNING"; + LogType[LogType["ERROR"] = 4] = "ERROR"; + })(LogType = log_1.LogType || (log_1.LogType = {})); + let category_mapping = new Map([ + [LogCategory.CHANNEL, "Channel "], + [LogCategory.CLIENT, "Channel "], + [LogCategory.CHANNEL_PROPERTIES, "Client "], + [LogCategory.SERVER, "Server "], + [LogCategory.PERMISSIONS, "Permission "], + [LogCategory.GENERAL, "General "], + [LogCategory.NETWORKING, "Network "], + [LogCategory.VOICE, "Voice "], + [LogCategory.I18N, "I18N "] + ]); + log_1.enabled_mapping = new Map([ + [LogCategory.CHANNEL, true], + [LogCategory.CHANNEL_PROPERTIES, false], + [LogCategory.CLIENT, true], + [LogCategory.SERVER, true], + [LogCategory.PERMISSIONS, true], + [LogCategory.GENERAL, true], + [LogCategory.NETWORKING, true], + [LogCategory.VOICE, true], + [LogCategory.I18N, false] + ]); + loader.register_task(loader.Stage.LOADED, { + name: "log enabled initialisation", + function: () => __awaiter(this, void 0, void 0, function* () { return initialize(); }), + priority: 10 + }); + //Example: ?log.i18n.enabled=0 + function initialize() { + for (const category of Object.keys(LogCategory).map(e => parseInt(e))) { + if (isNaN(category)) + continue; + const category_name = LogCategory[category]; + log_1.enabled_mapping[category] = settings.static_global("log." + category_name.toLowerCase() + ".enabled", log_1.enabled_mapping.get(category)); + } + } + log_1.initialize = initialize; + function logDirect(type, message, ...optionalParams) { + switch (type) { + case LogType.TRACE: + case LogType.DEBUG: + console.debug(message, ...optionalParams); + break; + case LogType.INFO: + console.log(message, ...optionalParams); + break; + case LogType.WARNING: + console.warn(message, ...optionalParams); + break; + case LogType.ERROR: + console.error(message, ...optionalParams); + break; + } + //console.log("This is %cMy stylish message", "color: yellow; font-style: italic; background-color: blue;padding: 2px"); + } + function log(type, category, message, ...optionalParams) { + if (!log_1.enabled_mapping[category]) + return; + optionalParams.unshift(category_mapping.get(category)); + message = "[%s] " + message; + logDirect(type, message, ...optionalParams); + } + log_1.log = log; + function trace(category, message, ...optionalParams) { + log(LogType.TRACE, category, message, ...optionalParams); + } + log_1.trace = trace; + function debug(category, message, ...optionalParams) { + log(LogType.DEBUG, category, message, ...optionalParams); + } + log_1.debug = debug; + function info(category, message, ...optionalParams) { + log(LogType.INFO, category, message, ...optionalParams); + } + log_1.info = info; + function warn(category, message, ...optionalParams) { + log(LogType.WARNING, category, message, ...optionalParams); + } + log_1.warn = warn; + function error(category, message, ...optionalParams) { + log(LogType.ERROR, category, message, ...optionalParams); + } + log_1.error = error; + function group(level, category, name, ...optionalParams) { + name = "[%s] " + name; + optionalParams.unshift(category_mapping.get(category)); + return new Group(level, category, name, optionalParams); + } + log_1.group = group; + class Group { + constructor(level, category, name, optionalParams, owner = undefined) { + this.owner = undefined; + this._collapsed = true; + this.initialized = false; + this.level = level; + this.category = category; + this.name = name; + this.optionalParams = optionalParams; + this.enabled = log_1.enabled_mapping[category]; + } + group(level, name, ...optionalParams) { + return new Group(level, this.category, name, optionalParams, this); + } + collapsed(flag = true) { + this._collapsed = flag; + return this; + } + log(message, ...optionalParams) { + if (!this.enabled) + return this; + if (!this.initialized) { + if (this._collapsed && console.groupCollapsed) + console.groupCollapsed(this.name, ...this.optionalParams); + else + console.group(this.name, ...this.optionalParams); + this.initialized = true; + } + logDirect(this.level, message, ...optionalParams); + return this; + } + end() { + if (this.initialized) + console.groupEnd(); + } + } + log_1.Group = Group; +})(log || (log = {})); +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["aa4820e2170bccb4c9023974e9ced073b8bc94597aa84bfaf8d5885df8b2ea72"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["aa4820e2170bccb4c9023974e9ced073b8bc94597aa84bfaf8d5885df8b2ea72"] = "aa4820e2170bccb4c9023974e9ced073b8bc94597aa84bfaf8d5885df8b2ea72"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "VS9hwtrt", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/AudioController.ts (17,26)" }, { name: "sQGbUuVV", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/AudioController.ts (19,25)" }, { name: "nYG7F2p3", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/AudioController.ts (108,26)" }, { name: "_Yf07RsH", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/AudioController.ts (112,26)" }, { name: "aWefC7hp", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/AudioController.ts (116,26)" }, { name: "AB2K3e04", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/AudioController.ts (121,25)" }, { name: "gFg5nk4c", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/AudioController.ts (137,33)" }, { name: "TyzWyl9j", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/AudioController.ts (141,37)" }, { name: "_W4xu8ar", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/AudioController.ts (156,29)" }, { name: "FMs8xfPn", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/AudioController.ts (199,34)" }, { name: "JNe36jh0", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/AudioController.ts (214,34)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +var PlayerState; +(function (PlayerState) { + PlayerState[PlayerState["PREBUFFERING"] = 0] = "PREBUFFERING"; + PlayerState[PlayerState["PLAYING"] = 1] = "PLAYING"; + PlayerState[PlayerState["BUFFERING"] = 2] = "BUFFERING"; + PlayerState[PlayerState["STOPPING"] = 3] = "STOPPING"; + PlayerState[PlayerState["STOPPED"] = 4] = "STOPPED"; +})(PlayerState || (PlayerState = {})); +class AudioController { + constructor() { + this.playerState = PlayerState.STOPPED; + this.audioCache = []; + this.playingAudioCache = []; + this._volume = 1; + this._codecCache = []; + this._timeIndex = 0; + this._latencyBufferLength = 3; + this.allowBuffering = true; + audio.player.on_ready(() => this.speakerContext = audio.player.context()); + this.onSpeaking = function () { }; + this.onSilence = function () { }; + } + static initializeAudioController() { + if (!audio.player.initialize()) + console.warn(_translations.VS9hwtrt || (_translations.VS9hwtrt = tr("Failed to initialize audio controller!"))); + sound.initialize().then(() => { + console.log(_translations.sQGbUuVV || (_translations.sQGbUuVV = tr("Sounds initialitzed"))); + }); + //this._globalReplayScheduler = setInterval(() => { AudioController.invokeNextReplay(); }, 20); //Fix me + } + initialize() { + AudioController._audioInstances.push(this); + } + close() { + AudioController._audioInstances.remove(this); + } + playBuffer(buffer) { + if (!buffer) { + console.warn(_translations.nYG7F2p3 || (_translations.nYG7F2p3 = tr("[AudioController] Got empty or undefined buffer! Dropping it"))); + return; + } + if (!this.speakerContext) { + console.warn(_translations._Yf07RsH || (_translations._Yf07RsH = tr("[AudioController] Failed to replay audio. Global audio context not initialized yet!"))); + return; + } + if (buffer.sampleRate != this.speakerContext.sampleRate) + console.warn(_translations.aWefC7hp || (_translations.aWefC7hp = tr("[AudioController] Source sample rate isn't equal to playback sample rate! (%o | %o)")), buffer.sampleRate, this.speakerContext.sampleRate); + this.applyVolume(buffer); + this.audioCache.push(buffer); + if (this.playerState == PlayerState.STOPPED || this.playerState == PlayerState.STOPPING) { + console.log(_translations.AB2K3e04 || (_translations.AB2K3e04 = tr("[Audio] Starting new playback"))); + this.playerState = PlayerState.PREBUFFERING; + //New audio + } + switch (this.playerState) { + case PlayerState.PREBUFFERING: + case PlayerState.BUFFERING: + this.reset_buffer_timeout(true); //Reset timeout, we got a new buffer + if (this.audioCache.length <= this._latencyBufferLength) { + if (this.playerState == PlayerState.BUFFERING) { + if (this.allowBuffering) + break; + } + else + break; + } + if (this.playerState == PlayerState.PREBUFFERING) { + console.log(_translations.gFg5nk4c || (_translations.gFg5nk4c = tr("[Audio] Prebuffering succeeded (Replaying now)"))); + this.onSpeaking(); + } + else { + if (this.allowBuffering) + console.log(_translations.TyzWyl9j || (_translations.TyzWyl9j = tr("[Audio] Buffering succeeded (Replaying now)"))); + } + this.playerState = PlayerState.PLAYING; + case PlayerState.PLAYING: + this.playQueue(); + break; + default: + break; + } + } + playQueue() { + let buffer; + while ((buffer = this.audioCache.pop_front())) { + if (this.playingAudioCache.length >= this._latencyBufferLength * 1.5 + 3) { + console.log(_translations._W4xu8ar || (_translations._W4xu8ar = tr("Dropping buffer because playing queue grows to much"))); + continue; /* drop the data (we're behind) */ + } + if (this._timeIndex < this.speakerContext.currentTime) + this._timeIndex = this.speakerContext.currentTime; + let player = this.speakerContext.createBufferSource(); + player.buffer = buffer; + player.onended = () => this.removeNode(player); + this.playingAudioCache.push(player); + player.connect(audio.player.destination()); + player.start(this._timeIndex); + this._timeIndex += buffer.duration; + } + } + removeNode(node) { + this.playingAudioCache.remove(node); + this.testBufferQueue(); + } + stopAudio(now = false) { + this.playerState = PlayerState.STOPPING; + if (now) { + this.playerState = PlayerState.STOPPED; + this.audioCache = []; + for (let entry of this.playingAudioCache) + entry.stop(0); + this.playingAudioCache = []; + } + this.testBufferQueue(); + this.playQueue(); //Flush queue + } + testBufferQueue() { + if (this.audioCache.length == 0 && this.playingAudioCache.length == 0) { + if (this.playerState != PlayerState.STOPPING && this.playerState != PlayerState.STOPPED) { + if (this.playerState == PlayerState.BUFFERING) + return; //We're already buffering + this.playerState = PlayerState.BUFFERING; + if (!this.allowBuffering) + console.warn(_translations.FMs8xfPn || (_translations.FMs8xfPn = tr("[Audio] Detected a buffer underflow!"))); + this.reset_buffer_timeout(true); + } + else { + this.playerState = PlayerState.STOPPED; + this.onSilence(); + } + } + } + reset_buffer_timeout(restart) { + if (this._buffer_timeout) + clearTimeout(this._buffer_timeout); + if (restart) + this._buffer_timeout = setTimeout(() => { + if (this.playerState == PlayerState.PREBUFFERING || this.playerState == PlayerState.BUFFERING) { + console.warn(_translations.JNe36jh0 || (_translations.JNe36jh0 = tr("[Audio] Buffering exceeded timeout. Flushing and stopping replay"))); + this.stopAudio(); + } + this._buffer_timeout = undefined; + }, 1000); + } + get volume() { return this._volume; } + set volume(val) { + if (this._volume == val) + return; + this._volume = val; + for (let buffer of this.audioCache) + this.applyVolume(buffer); + } + applyVolume(buffer) { + if (this._volume == 1) + return; + for (let channel = 0; channel < buffer.numberOfChannels; channel++) { + let data = buffer.getChannelData(channel); + for (let sample = 0; sample < data.length; sample++) { + let lane = data[sample]; + lane *= this._volume; + data[sample] = lane; + } + } + } + codecCache(codec) { + while (this._codecCache.length <= codec) + this._codecCache.push(new CodecClientCache()); + return this._codecCache[codec]; + } +} +AudioController._audioInstances = []; +AudioController._timeIndex = 0; +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["73175f3c3c475118e7753855dc9a37dcbff17356792cb5f958da725f26fef61d"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["73175f3c3c475118e7753855dc9a37dcbff17356792cb5f958da725f26fef61d"] = "73175f3c3c475118e7753855dc9a37dcbff17356792cb5f958da725f26fef61d"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "xXDTVFqp", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/proto.ts (58,31)" }, { name: "VmE4po4t", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/proto.ts (62,31)" }, { name: "jM1uWylR", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/proto.ts (81,27)" }, { name: "X3Guusa0", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/proto.ts (208,33)" }, { name: "WzItbAWP", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/proto.ts (210,32)" }, { name: "Yn6EHaG_", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/proto.ts (212,33)" }, { name: "_Pmw_Iot", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/proto.ts (214,35)" }, { name: "gULlVp9g", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/proto.ts (216,35)" }, { name: "lZCpWdXL", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/proto.ts (218,18)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +if (!JSON.map_to) { + JSON.map_to = function (object, json, variables, validator, variable_direction) { + if (!validator) + validator = (a, b) => true; + if (!variables) { + variables = []; + if (!variable_direction || variable_direction == 0) { + for (let field in json) + variables.push(field); + } + else if (variable_direction == 1) { + for (let field in object) + variables.push(field); + } + } + else if (!Array.isArray(variables)) { + variables = [variables]; + } + for (let field of variables) { + if (!json[field]) { + console.trace(_translations.xXDTVFqp || (_translations.xXDTVFqp = tr("Json does not contains %s")), field); + continue; + } + if (!validator(field, json[field])) { + console.trace(_translations.VmE4po4t || (_translations.VmE4po4t = tr("Validator results in false for %s")), field); + continue; + } + JSON.map_field_to(object, json[field], field); + } + return object; + }; +} +if (!JSON.map_field_to) { + JSON.map_field_to = function (object, value, field) { + let field_type = typeof (object[field]); + if (field_type == "string" || field_type == "object" || field_type == "undefined") + object[field] = value; + else if (field_type == "number") + object[field] = parseFloat(value); + else if (field_type == "boolean") + object[field] = value == "1" || value == "true"; + else + console.warn(_translations.jM1uWylR || (_translations.jM1uWylR = tr("Invalid object type %s for entry %s")), field_type, field); + return object; + }; +} +if (!Array.prototype.remove) { + Array.prototype.remove = function (elem) { + const index = this.indexOf(elem, 0); + if (index > -1) { + this.splice(index, 1); + return true; + } + return false; + }; +} +if (!Array.prototype.pop_front) { + Array.prototype.pop_front = function () { + if (this.length == 0) + return undefined; + return this.splice(0, 1)[0]; + }; +} +if (!Array.prototype.last) { + Array.prototype.last = function () { + if (this.length == 0) + return undefined; + return this[this.length - 1]; + }; +} +if (typeof ($) !== "undefined") { + if (!$.spawn) { + $.spawn = function (tagName) { + return $(document.createElement(tagName)); + }; + } + if (!$.fn.renderTag) { + $.fn.renderTag = function (values) { + let result; + if (this.render) { + result = $(this.render(values)); + } + else { + const template = window.jsrender.render[this.attr("id")]; + /* + result = window.jsrender.templates("tmpl_permission_entry", $("#tmpl_permission_entry").html()); + result = window.jsrender.templates("xxx", this.html()); + */ + result = template(values); + result = $(result); + } + result.find("node").each((index, element) => { + $(element).replaceWith(values[$(element).attr("key")] || (values[0] || [])[$(element).attr("key")]); + }); + return result; + }; + } + if (!$.fn.hasScrollBar) + $.fn.hasScrollBar = function () { + if (this.length <= 0) + return false; + return this.get(0).scrollHeight > this.height(); + }; + if (!$.fn.visible_height) + $.fn.visible_height = function () { + const original_style = this.attr("style"); + this.css({ + position: 'absolute!important', + visibility: 'hidden!important', + display: 'block!important' + }); + const result = this.height(); + this.attr("style", original_style || ""); + return result; + }; + if (!$.fn.visible_width) + $.fn.visible_width = function () { + const original_style = this.attr("style"); + this.css({ + position: 'absolute!important', + visibility: 'hidden!important', + display: 'block!important' + }); + const result = this.width(); + this.attr("style", original_style || ""); + return result; + }; +} +if (!String.prototype.format) { + String.prototype.format = function () { + const args = arguments; + let array = args.length == 1 && $.isArray(args[0]); + return this.replace(/\{\{|\}\}|\{(\d+)\}/g, function (m, n) { + if (m == "{{") { + return "{"; + } + if (m == "}}") { + return "}"; + } + return array ? args[0][n] : args[n]; + }); + }; +} +function concatenate(resultConstructor, ...arrays) { + let totalLength = 0; + for (const arr of arrays) { + totalLength += arr.length; + } + const result = new resultConstructor(totalLength); + let offset = 0; + for (const arr of arrays) { + result.set(arr, offset); + offset += arr.length; + } + return result; +} +function formatDate(secs) { + let years = Math.floor(secs / (60 * 60 * 24 * 365)); + let days = Math.floor(secs / (60 * 60 * 24)) % 365; + let hours = Math.floor(secs / (60 * 60)) % 24; + let minutes = Math.floor(secs / 60) % 60; + let seconds = Math.floor(secs % 60); + let result = ""; + if (years > 0) + result += years + " " + (_translations.X3Guusa0 || (_translations.X3Guusa0 = tr("years"))) + " "; + if (years > 0 || days > 0) + result += days + " " + (_translations.WzItbAWP || (_translations.WzItbAWP = tr("days"))) + " "; + if (years > 0 || days > 0 || hours > 0) + result += hours + " " + (_translations.Yn6EHaG_ || (_translations.Yn6EHaG_ = tr("hours"))) + " "; + if (years > 0 || days > 0 || hours > 0 || minutes > 0) + result += minutes + " " + (_translations._Pmw_Iot || (_translations._Pmw_Iot = tr("minutes"))) + " "; + if (years > 0 || days > 0 || hours > 0 || minutes > 0 || seconds > 0) + result += seconds + " " + (_translations.gULlVp9g || (_translations.gULlVp9g = tr("seconds"))) + " "; + else + result = (_translations.lZCpWdXL || (_translations.lZCpWdXL = tr("now"))) + " "; + return result.substr(0, result.length - 1); +} +function calculate_width(text) { + let element = $.spawn("div"); + element.text(text) + .css("display", "none") + .css("margin", 0); + $("body").append(element); + let size = element.width(); + element.detach(); + return size; +} +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["8bea2622f41d7017b839dd7842376dc7712df60e8b96482e914df09124e9c503"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["8bea2622f41d7017b839dd7842376dc7712df60e8b96482e914df09124e9c503"] = "8bea2622f41d7017b839dd7842376dc7712df60e8b96482e914df09124e9c503"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of []) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +var CodecType; +(function (CodecType) { + CodecType[CodecType["OPUS_VOICE"] = 0] = "OPUS_VOICE"; + CodecType[CodecType["OPUS_MUSIC"] = 1] = "OPUS_MUSIC"; + CodecType[CodecType["SPEEX_NARROWBAND"] = 2] = "SPEEX_NARROWBAND"; + CodecType[CodecType["SPEEX_WIDEBAND"] = 3] = "SPEEX_WIDEBAND"; + CodecType[CodecType["SPEEX_ULTRA_WIDEBAND"] = 4] = "SPEEX_ULTRA_WIDEBAND"; + CodecType[CodecType["CELT_MONO"] = 5] = "CELT_MONO"; +})(CodecType || (CodecType = {})); +class BufferChunk { + constructor(buffer) { + this.buffer = buffer; + this.index = 0; + } + copyRangeTo(target, maxLength, offset) { + let copy = Math.min(this.buffer.length - this.index, maxLength); + //TODO may warning if channel counts are not queal? + for (let channel = 0; channel < Math.min(target.numberOfChannels, this.buffer.numberOfChannels); channel++) { + target.getChannelData(channel).set(this.buffer.getChannelData(channel).subarray(this.index, this.index + copy), offset); + } + return copy; + } +} +class CodecClientCache { + constructor() { + this._chunks = []; + } + bufferedSamples(max = 0) { + let value = 0; + for (let i = 0; i < this._chunks.length && value < max; i++) + value += this._chunks[i].buffer.length - this._chunks[i].index; + return value; + } +} +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["5df58f3b6832f7418213f7d08bb001f9be22c31798af6163595e1be5d1baa0b9"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["5df58f3b6832f7418213f7d08bb001f9be22c31798af6163595e1be5d1baa0b9"] = "5df58f3b6832f7418213f7d08bb001f9be22c31798af6163595e1be5d1baa0b9"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of []) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +var ElementType; +(function (ElementType) { + ElementType[ElementType["HEADER"] = 0] = "HEADER"; + ElementType[ElementType["BODY"] = 1] = "BODY"; + ElementType[ElementType["FOOTER"] = 2] = "FOOTER"; +})(ElementType || (ElementType = {})); +const ModalFunctions = { + divify: function (val) { + if (val.length > 1) + return $.spawn("div").append(val); + return val; + }, + jqueriefy: function (val, type) { + if ($.isFunction(val)) + val = val(); + if ($.isArray(val)) { + let result = $.spawn("div"); + for (let element of val) + this.jqueriefy(element, type).appendTo(result); + return result; + } + switch (typeof val) { + case "string": + if (type == ElementType.HEADER) + return $.spawn("h5").addClass("modal-title").text(val); + return $("
" + val + "
"); + case "object": return val; + case "undefined": + return undefined; + default: + console.error(("Invalid type %o"), typeof val); + return $(); + } + }, + warpProperties(data) { + if (data instanceof ModalProperties) + return data; + else { + const props = new ModalProperties(); + for (const key of Object.keys(data)) + props[key] = data[key]; + return props; + } + } +}; +class ModalProperties { + constructor() { + this.header = () => "HEADER"; + this.body = () => "BODY"; + this.footer = () => "FOOTER"; + this.closeListener = () => { }; + this.width = "60%"; + this.height = "auto"; + this.closeable = true; + this.template_properties = {}; + this.trigger_tab = true; + this.full_size = false; + } + registerCloseListener(listener) { + if (this.closeListener) { + if ($.isArray(this.closeListener)) + this.closeListener.push(listener); + else + this.closeListener = [this.closeListener, listener]; + } + else + this.closeListener = listener; + return this; + } + triggerClose() { + if ($.isArray(this.closeListener)) + for (let listener of this.closeListener) + listener(); + else + this.closeListener(); + } +} +class Modal { + constructor(props) { + this.close_listener = []; + this.properties = props; + this.shown = false; + } + get htmlTag() { + if (!this._htmlTag) + this._create(); + return this._htmlTag; + } + _create() { + const header = ModalFunctions.jqueriefy(this.properties.header, ElementType.HEADER); + const body = ModalFunctions.jqueriefy(this.properties.body, ElementType.BODY); + const footer = ModalFunctions.jqueriefy(this.properties.footer, ElementType.FOOTER); + //FIXME: cache template + const template = $(this.properties.template || "#tmpl_modal"); + const properties = { + modal_header: header, + modal_body: body, + modal_footer: footer, + closeable: this.properties.closeable, + full_size: this.properties.full_size + }; + if (this.properties.template_properties) + Object.assign(properties, this.properties.template_properties); + const tag = template.renderTag(properties); + this._htmlTag = tag; + this._htmlTag.on('hide.bs.modal', event => !this.properties.closeable || this.close()); + this._htmlTag.on('hidden.bs.modal', event => this._htmlTag.detach()); + } + open() { + this.shown = true; + this.htmlTag.appendTo($("body")); + this.htmlTag.bootstrapMaterialDesign().modal(this.properties.closeable ? 'show' : { + backdrop: 'static', + keyboard: false, + }); + if (this.properties.trigger_tab) + this.htmlTag.one('shown.bs.modal', () => this.htmlTag.find(".tab").trigger('tab.resize')); + } + close() { + if (!this.shown) + return; + this.shown = false; + this.htmlTag.modal('hide'); + this.properties.triggerClose(); + for (const listener of this.close_listener) + listener(); + } +} +function createModal(data) { + return new Modal(ModalFunctions.warpProperties(data)); +} +class InputModalProperties extends ModalProperties { +} +function createInputModal(headMessage, question, validator, callback, props = {}) { + props = ModalFunctions.warpProperties(props); + props.template_properties || (props.template_properties = {}); + props.template_properties.field_title = props.field_title; + props.template_properties.field_label = props.field_label; + props.template_properties.field_placeholder = props.field_placeholder; + props.template_properties.error_message = props.error_message; + props.template = "#tmpl_modal_input"; + props.header = headMessage; + props.template_properties.question = ModalFunctions.jqueriefy(question); + const modal = createModal(props); + const input = modal.htmlTag.find(".container-value input"); + const button_cancel = modal.htmlTag.find(".button-cancel"); + const button_submit = modal.htmlTag.find(".button-submit"); + let submited = false; + input.on('keyup change', event => { + const str = input.val(); + const valid = str !== undefined && validator(str); + input.attr("pattern", valid ? null : "^[a]{1000}$").toggleClass("is-invalid", !valid); + button_submit.prop("disabled", !valid); + }); + button_submit.on('click', event => { + if (!submited) { + submited = true; + const str = input.val(); + if (str !== undefined && validator(str)) + callback(str); + else + callback(false); + } + modal.close(); + }).prop("disabled", !validator("")); /* disabled if empty input isn't allowed */ + button_cancel.on('click', event => { + if (!submited) { + submited = true; + callback(false); + } + modal.close(); + }); + modal.close_listener.push(() => button_cancel.trigger('click')); + return modal; +} +function createErrorModal(header, message, props = { footer: undefined }) { + props = ModalFunctions.warpProperties(props); + (props.template_properties || (props.template_properties = {})).header_class = "modal-header-error"; + props.header = header; + props.body = message; + return createModal(props); +} +function createInfoModal(header, message, props = { footer: undefined }) { + props = ModalFunctions.warpProperties(props); + (props.template_properties || (props.template_properties = {})).header_class = "modal-header-info"; + props.header = header; + props.body = message; + return createModal(props); +} +$.fn.modalize = function (entry_callback, properties) { + properties = properties || {}; + entry_callback = entry_callback || ((a, b, c) => undefined); + let tag_modal = this[0].tagName.toLowerCase() == "modal" ? this : undefined; /* TODO may throw exception? */ + let tag_head = tag_modal ? tag_modal.find("modal-header") : ModalFunctions.jqueriefy(properties.header); + let tag_body = tag_modal ? tag_modal.find("modal-body") : this; + let tag_footer = tag_modal ? tag_modal.find("modal-footer") : ModalFunctions.jqueriefy(properties.footer); + const result = entry_callback(tag_head, tag_body, tag_footer) || {}; + properties.header = result.header || tag_head; + properties.body = result.body || tag_body; + properties.footer = result.footer || tag_footer; + return createModal(properties); +}; +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["5fd9db372c787bbb778707708e77bfa5f651f4080dfc1637351e827593055aa8"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["5fd9db372c787bbb778707708e77bfa5f651f4080dfc1637351e827593055aa8"] = "5fd9db372c787bbb778707708e77bfa5f651f4080dfc1637351e827593055aa8"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "rylmoMRv", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceRecorder.ts (125,34)" }, { name: "xETnJw_h", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceRecorder.ts (125,54)" }, { name: "UXHjTt3O", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceRecorder.ts (162,26)" }, { name: "P0Yq63W0", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceRecorder.ts (211,21)" }, { name: "wE38NthB", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceRecorder.ts (223,30)" }, { name: "Haajz6fY", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceRecorder.ts (223,67)" }, { name: "JzoHoA05", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceRecorder.ts (224,27)" }, { name: "ZAgN8FTN", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceRecorder.ts (230,21)" }, { name: "HvtFBzv8", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceRecorder.ts (256,25)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +/// +/// +class VoiceActivityDetector { + initialise() { } + finalize() { } + initialiseNewStream(old, _new) { } + changeHandle(handle, triggerNewStream) { + const oldStream = !this.handle ? undefined : this.handle.getMicrophoneStream(); + this.handle = handle; + if (triggerNewStream) + this.initialiseNewStream(oldStream, !handle ? undefined : handle.getMicrophoneStream()); + } +} +if (!AudioBuffer.prototype.copyToChannel) { //Webkit does not implement this function + AudioBuffer.prototype.copyToChannel = function (source, channelNumber, startInChannel) { + if (!startInChannel) + startInChannel = 0; + let destination = this.getChannelData(channelNumber); + for (let index = 0; index < source.length; index++) + if (destination.length < index + startInChannel) + destination[index + startInChannel] = source[index]; + }; +} +class VoiceRecorder { + constructor(handle) { + this.on_data = undefined; + this._recording = false; + this.microphoneStream = undefined; + this.mediaStream = undefined; + this._chunkCount = 0; + this.handle = handle; + this._deviceId = settings.global("microphone_device_id", "default"); + this._deviceGroup = settings.global("microphone_device_group", "default"); + audio.player.on_ready(() => { + this.audioContext = audio.player.context(); + this.processor = this.audioContext.createScriptProcessor(VoiceRecorder.BUFFER_SIZE, VoiceRecorder.CHANNELS, VoiceRecorder.CHANNELS); + const empty_buffer = this.audioContext.createBuffer(VoiceRecorder.CHANNELS, VoiceRecorder.BUFFER_SIZE, 48000); + this.processor.addEventListener('audioprocess', ev => { + if (this.microphoneStream && this.vadHandler.shouldRecord(ev.inputBuffer)) { + if (this._chunkCount == 0 && this.on_start) + this.on_start(); + if (this.on_data) + this.on_data(ev.inputBuffer, this._chunkCount == 0); + else { + for (let channel = 0; channel < ev.inputBuffer.numberOfChannels; channel++) + ev.outputBuffer.copyToChannel(ev.inputBuffer.getChannelData(channel), channel); + } + this._chunkCount++; + } + else { + if (this._chunkCount != 0 && this.on_end) + this.on_end(); + this._chunkCount = 0; + for (let channel = 0; channel < ev.inputBuffer.numberOfChannels; channel++) + ev.outputBuffer.copyToChannel(empty_buffer.getChannelData(channel), channel); + } + }); + this.processor.connect(this.audioContext.destination); + if (this.vadHandler) + this.vadHandler.initialise(); + this.on_microphone(this.mediaStream); + }); + this.setVADHandler(new PassThroughVAD()); + } + get_output_stream() { return this.processor; } + available() { + return !!getUserMediaFunction() && !!getUserMediaFunction(); + } + recording() { + return this._recording; + } + getMediaStream() { + return this.mediaStream; + } + getMicrophoneStream() { + return this.microphoneStream; + } + reinitialiseVAD() { + let type = settings.global("vad_type", "vad"); + if (type == "ppt") { + if (settings.global('vad_ppt_key', undefined)) { + //TODO remove that because its legacy shit + createErrorModal(_translations.rylmoMRv || (_translations.rylmoMRv = tr("VAD changed!")), _translations.xETnJw_h || (_translations.xETnJw_h = tr("VAD key detection changed.
Please reset your PPT key!"))).open(); + } + let ppt_settings = settings.global('vad_ppt_settings', undefined); + ppt_settings = ppt_settings ? JSON.parse(ppt_settings) : {}; + if (ppt_settings.version === undefined) + ppt_settings.version = 1; + if (ppt_settings.key_code === undefined) + ppt_settings.key_code = "KeyT"; + if (ppt_settings.key_ctrl === undefined) + ppt_settings.key_ctrl = false; + if (ppt_settings.key_shift === undefined) + ppt_settings.key_shift = false; + if (ppt_settings.key_alt === undefined) + ppt_settings.key_alt = false; + if (ppt_settings.key_windows === undefined) + ppt_settings.key_windows = false; + if (ppt_settings.delay === undefined) + ppt_settings.delay = 300; + if (!(this.getVADHandler() instanceof PushToTalkVAD)) + this.setVADHandler(new PushToTalkVAD(ppt_settings)); + else + this.getVADHandler().settings = ppt_settings; + } + else if (type == "pt") { + if (!(this.getVADHandler() instanceof PassThroughVAD)) + this.setVADHandler(new PassThroughVAD()); + } + else if (type == "vad") { + if (!(this.getVADHandler() instanceof VoiceActivityDetectorVAD)) + this.setVADHandler(new VoiceActivityDetectorVAD()); + this.getVADHandler().percentageThreshold = settings.global("vad_threshold", 50); + } + else { + console.warn(_translations.UXHjTt3O || (_translations.UXHjTt3O = tr("Invalid VAD (Voice activation detector) handler! (%o)")), type); + } + } + setVADHandler(handler) { + if (this.vadHandler) { + this.vadHandler.changeHandle(null, true); + this.vadHandler.finalize(); + } + this.vadHandler = handler; + this.vadHandler.changeHandle(this, false); + if (this.audioContext) { + this.vadHandler.initialise(); + if (this.microphoneStream) + this.vadHandler.initialiseNewStream(undefined, this.microphoneStream); + } + } + getVADHandler() { + return this.vadHandler; + } + update(flag) { + if (this._recording == flag) + return; + if (flag) + this.start(this._deviceId, this._deviceGroup); + else + this.stop(); + } + device_group_id() { return this._deviceGroup; } + device_id() { return this._deviceId; } + change_device(device, group) { + if (this._deviceId == device && this._deviceGroup == group) + return; + this._deviceId = device; + this._deviceGroup = group; + settings.changeGlobal("microphone_device_id", device); + settings.changeGlobal("microphone_device_group", group); + if (this._recording) { + this.stop(); + this.start(device, group); + } + } + start(device, groupId) { + this._deviceId = device; + this._deviceGroup = groupId; + console.log(_translations.P0Yq63W0 || (_translations.P0Yq63W0 = tr("[VoiceRecorder] Start recording! (Device: %o | Group: %o)")), device, groupId); + this._recording = true; + //FIXME Implement that here for thew client as well + getUserMediaFunction()({ + audio: { + deviceId: device, + groupId: groupId, + echoCancellation: true, + echoCancellationType: 'browser' + } + }, this.on_microphone.bind(this), error => { + createErrorModal(_translations.wE38NthB || (_translations.wE38NthB = tr("Could not resolve microphone!")), (_translations.Haajz6fY || (_translations.Haajz6fY = tr("Could not resolve microphone!
Message: "))) + error).open(); + console.error(_translations.JzoHoA05 || (_translations.JzoHoA05 = tr("Could not get microphone!"))); + console.error(error); + }); + } + stop(stop_media_stream = true) { + console.log(_translations.ZAgN8FTN || (_translations.ZAgN8FTN = tr("Stop recording!"))); + this._recording = false; + if (this.microphoneStream) + this.microphoneStream.disconnect(); + this.microphoneStream = undefined; + if (stop_media_stream && this.mediaStream) { + if (this.mediaStream.stop) + this.mediaStream.stop(); + else + this.mediaStream.getTracks().forEach(value => { + value.stop(); + }); + this.mediaStream = undefined; + } + } + on_microphone(stream) { + const old_microphone_stream = this.microphoneStream; + if (old_microphone_stream) + this.stop(this.mediaStream != stream); //Disconnect old stream + this.mediaStream = stream; + if (!this.mediaStream) + return; + if (!this.audioContext) { + console.log(_translations.HvtFBzv8 || (_translations.HvtFBzv8 = tr("[VoiceRecorder] Got microphone stream, but havn't a audio context. Waiting until its initialized"))); + return; + } + this.microphoneStream = this.audioContext.createMediaStreamSource(stream); + this.microphoneStream.connect(this.processor); + if (this.vadHandler) + this.vadHandler.initialiseNewStream(old_microphone_stream, this.microphoneStream); + } +} +VoiceRecorder.CHANNEL = 0; +VoiceRecorder.CHANNELS = 2; +VoiceRecorder.BUFFER_SIZE = 1024 * 4; +class MuteVAD extends VoiceActivityDetector { + shouldRecord(buffer) { + return false; + } +} +class PassThroughVAD extends VoiceActivityDetector { + shouldRecord(buffer) { + return true; + } +} +class VoiceActivityDetectorVAD extends VoiceActivityDetector { + constructor() { + super(...arguments); + this.continuesCount = 0; + this.maxContinuesCount = 12; + this.percentageThreshold = 50; + this.percentage_listener = ($) => { }; + } + initialise() { + this.analyzer = audio.player.context().createAnalyser(); + this.analyzer.smoothingTimeConstant = 1; //TODO test + this.buffer = new Uint8Array(this.analyzer.fftSize); + return super.initialise(); + } + initialiseNewStream(old, _new) { + if (this.analyzer) + this.analyzer.disconnect(); + if (_new) + _new.connect(this.analyzer); + } + shouldRecord(buffer) { + let usage = this.calculateUsage(); + if ($.isFunction(this.percentage_listener)) + this.percentage_listener(usage); + if (usage >= this.percentageThreshold) { + this.continuesCount = 0; + } + else + this.continuesCount++; + return this.continuesCount < this.maxContinuesCount; + } + calculateUsage() { + let total = 0, float, rms; + this.analyzer.getByteTimeDomainData(this.buffer); + for (let index = 0; index < this.analyzer.fftSize; index++) { + float = (this.buffer[index++] / 0x7f) - 1; + total += (float * float); + } + rms = Math.sqrt(total / this.analyzer.fftSize); + let db = 20 * (Math.log(rms) / Math.log(10)); + // sanity check + db = Math.max(-192, Math.min(db, 0)); + let percentage = 100 + (db * 1.92); + return percentage; + } +} +class PushToTalkVAD extends VoiceActivityDetector { + constructor(settings) { + super(); + this._pushed = false; + this._settings = settings; + this._key_hook = { + callback_release: () => { + if (this._timeout) + clearTimeout(this._timeout); + if (this._settings.delay > 0) + this._timeout = setTimeout(() => this._pushed = false, this._settings.delay); + else + this._pushed = false; + }, + callback_press: () => { + if (this._timeout) + clearTimeout(this._timeout); + this._pushed = true; + }, + cancel: false + }; + this.initialize_hook(); + } + initialize_hook() { + this._key_hook.key_code = this._settings.key_code; + this._key_hook.key_alt = this._settings.key_alt; + this._key_hook.key_ctrl = this._settings.key_ctrl; + this._key_hook.key_shift = this._settings.key_shift; + this._key_hook.key_windows = this._settings.key_windows; + } + initialise() { + ppt.register_key_hook(this._key_hook); + return super.initialise(); + } + finalize() { + ppt.unregister_key_hook(this._key_hook); + return super.finalize(); + } + set pushed(flag) { + this._pushed = flag; + } + set settings(settings) { + ppt.unregister_key_hook(this._key_hook); + this._settings = settings; + this.initialize_hook(); + this._pushed = false; + ppt.register_key_hook(this._key_hook); + } + shouldRecord(buffer) { + return this._pushed; + } +} +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["a56b051f4149c533919f4d7866c06de89650bb402337b0eef46443058cd37914"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["a56b051f4149c533919f4d7866c06de89650bb402337b0eef46443058cd37914"] = "a56b051f4149c533919f4d7866c06de89650bb402337b0eef46443058cd37914"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "t8oqO1lc", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (28,25)" }, { name: "mIUPETWo", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (32,30)" }, { name: "chRtM0Ti", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (33,34)" }, { name: "TGT0SBXJ", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (33,69)" }, { name: "PHQN4qwo", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (35,31)" }, { name: "ysFQ3wS5", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (37,31)" }, { name: "yAAdD7jC", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (48,24)" }, { name: "tjJfo7Dk", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (62,43)" }, { name: "E0WsEWiE", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (63,73)" }, { name: "YSTA_3JN", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (136,30)" }, { name: "nn0gTahg", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (137,30)" }, { name: "YzErO11B", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (138,30)" }, { name: "JlimUN5_", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (139,30)" }, { name: "INHTsvO8", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (140,30)" }, { name: "SKGjM2fl", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (141,30)" }, { name: "gtVYEggq", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (157,41)" }, { name: "mU7ZAmC6", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (197,37)" }, { name: "F7kOnJnp", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (199,41)" }, { name: "FBBcXTnB", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (274,26)" }, { name: "QTx3nvcX", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (281,25)" }, { name: "z0mKdtjN", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (312,25)" }, { name: "DTf5g1uR", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (315,27)" }, { name: "A1ka3yfu", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (329,25)" }, { name: "BNCVcnv7", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (331,29)" }, { name: "B7EYIlQD", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (336,33)" }, { name: "j7WFGiPM", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (341,29)" }, { name: "Y1UQmWiM", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (343,33)" }, { name: "XOmIStjD", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (346,29)" }, { name: "ythe3GnZ", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (351,47)" }, { name: "_vnSXilG", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (352,51)" }, { name: "sHVFQdqt", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (363,21)" }, { name: "R64I2bL6", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (382,21)" }, { name: "rpGfb5bB", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (384,25)" }, { name: "sUrbL8F8", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (388,21)" }, { name: "aCeDkOq4", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (393,21)" }, { name: "u9oEsZpv", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (407,27)" }, { name: "sQ8Ba2oR", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (413,27)" }, { name: "vH2yGkAk", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (429,35)" }, { name: "S2lnS5ls", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (462,21)" }, { name: "PXSYJ5v0", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/VoiceHandler.ts (469,21)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +/// +/// +/// +class CodecPoolEntry { +} +class CodecPool { + constructor(handle, index, name, type) { + this.entries = []; + this.maxInstances = 2; + this._supported = true; + this.handle = handle; + this.codecIndex = index; + this.name = name; + this.type = type; + this._supported = this.type !== undefined && audio.codec.supported(this.type); + } + initialize(cached) { + /* test if we're able to use this codec */ + const dummy_client_id = 0xFFEF; + this.ownCodec(dummy_client_id).then(codec => { + console.log(_translations.t8oqO1lc || (_translations.t8oqO1lc = tr("Release again! (%o)")), codec); + this.releaseCodec(dummy_client_id); + }).catch(error => { + if (this._supported) { + console.warn(_translations.mIUPETWo || (_translations.mIUPETWo = tr("Disabling codec support for ")), this.name); + createErrorModal(_translations.chRtM0Ti || (_translations.chRtM0Ti = tr("Could not load codec driver")), (_translations.TGT0SBXJ || (_translations.TGT0SBXJ = tr("Could not load or initialize codec "))) + this.name + "
" + + "Error: " + JSON.stringify(error) + "").open(); + console.error(_translations.PHQN4qwo || (_translations.PHQN4qwo = tr("Failed to initialize the opus codec. Error: %o")), error); + } + else { + console.debug(_translations.ysFQ3wS5 || (_translations.ysFQ3wS5 = tr("Failed to initialize already disabled codec. Error: %o")), error); + } + this._supported = false; + }); + } + supported() { return this._supported; } + ownCodec(clientId, create = true) { + return new Promise((resolve, reject) => { + if (!this._supported) { + reject(_translations.yAAdD7jC || (_translations.yAAdD7jC = tr("unsupported codec!"))); + return; + } + let freeSlot = 0; + for (let index = 0; index < this.entries.length; index++) { + if (this.entries[index].owner == clientId) { + this.entries[index].last_access = new Date().getTime(); + if (this.entries[index].instance.initialized()) + resolve(this.entries[index].instance); + else { + this.entries[index].instance.initialise().then((flag) => { + //TODO test success flag + this.ownCodec(clientId, false).then(resolve).catch(reject); + }).catch(error => { + console.error(_translations.tjJfo7Dk || (_translations.tjJfo7Dk = tr("Could not initialize codec!\nError: %o")), error); + reject(typeof (error) === 'string' ? error : _translations.E0WsEWiE || (_translations.E0WsEWiE = tr("Could not initialize codec!"))); + }); + } + return; + } + else if (freeSlot == 0 && this.entries[index].owner == 0) { + freeSlot = index; + } + } + if (!create) { + resolve(undefined); + return; + } + if (freeSlot == 0) { + freeSlot = this.entries.length; + let entry = new CodecPoolEntry(); + entry.instance = audio.codec.new_instance(this.type); + entry.instance.on_encoded_data = buffer => this.handle.handleEncodedVoicePacket(buffer, this.codecIndex); + this.entries.push(entry); + } + this.entries[freeSlot].owner = clientId; + this.entries[freeSlot].last_access = new Date().getTime(); + if (this.entries[freeSlot].instance.initialized()) + this.entries[freeSlot].instance.reset(); + else { + this.ownCodec(clientId, false).then(resolve).catch(reject); + return; + } + resolve(this.entries[freeSlot].instance); + }); + } + releaseCodec(clientId) { + for (let index = 0; index < this.entries.length; index++) + if (this.entries[index].owner == clientId) + this.entries[index].owner = 0; + } +} +var VoiceConnectionType; +(function (VoiceConnectionType) { + VoiceConnectionType[VoiceConnectionType["JS_ENCODE"] = 0] = "JS_ENCODE"; + VoiceConnectionType[VoiceConnectionType["NATIVE_ENCODE"] = 1] = "NATIVE_ENCODE"; +})(VoiceConnectionType || (VoiceConnectionType = {})); +class VoiceConnection { + constructor(client) { + this._type = VoiceConnectionType.NATIVE_ENCODE; + this.codec_pool = [ + new CodecPool(this, 0, _translations.YSTA_3JN || (_translations.YSTA_3JN = tr("Speex Narrowband")), CodecType.SPEEX_NARROWBAND), + new CodecPool(this, 1, _translations.nn0gTahg || (_translations.nn0gTahg = tr("Speex Wideband")), CodecType.SPEEX_WIDEBAND), + new CodecPool(this, 2, _translations.YzErO11B || (_translations.YzErO11B = tr("Speex Ultra Wideband")), CodecType.SPEEX_ULTRA_WIDEBAND), + new CodecPool(this, 3, _translations.JlimUN5_ || (_translations.JlimUN5_ = tr("CELT Mono")), CodecType.CELT_MONO), + new CodecPool(this, 4, _translations.INHTsvO8 || (_translations.INHTsvO8 = tr("Opus Voice")), CodecType.OPUS_VOICE), + new CodecPool(this, 5, _translations.SKGjM2fl || (_translations.SKGjM2fl = tr("Opus Music")), CodecType.OPUS_MUSIC) + ]; + this.vpacketId = 0; + this.chunkVPacketId = 0; + this.voice_send_queue = []; + this._ice_use_cache = true; + this._ice_cache = []; + this.client = client; + this._type = settings.static_global("voice_connection_type", this._type); + this.voiceRecorder = new VoiceRecorder(this); + this.voiceRecorder.on_end = this.handleVoiceEnded.bind(this); + this.voiceRecorder.on_start = this.handleVoiceStarted.bind(this); + this.voiceRecorder.reinitialiseVAD(); + audio.player.on_ready(() => { + log.info(LogCategory.VOICE, _translations.gtVYEggq || (_translations.gtVYEggq = tr("Initializing voice handler after AudioController has been initialized!"))); + if (native_client) { + this.codec_pool[0].initialize(2); + this.codec_pool[1].initialize(2); + this.codec_pool[2].initialize(2); + this.codec_pool[3].initialize(2); + } + this.codec_pool[4].initialize(2); + this.codec_pool[5].initialize(2); + if (this.type == VoiceConnectionType.NATIVE_ENCODE) + this.setup_native(); + else + this.setup_js(); + }); + this.send_task = setInterval(this.sendNextVoicePacket.bind(this), 20); + } + native_encoding_supported() { + if (!(window.webkitAudioContext || window.AudioContext || { prototype: {} }).prototype.createMediaStreamDestination) + return false; //Required, but not available within edge + return true; + } + javascript_encoding_supported() { + if (!(window.RTCPeerConnection || { prototype: {} }).prototype.createDataChannel) + return false; + return true; + } + current_encoding_supported() { + switch (this._type) { + case VoiceConnectionType.JS_ENCODE: + return this.javascript_encoding_supported(); + case VoiceConnectionType.NATIVE_ENCODE: + return this.native_encoding_supported(); + } + return false; + } + setup_native() { + log.info(LogCategory.VOICE, _translations.mU7ZAmC6 || (_translations.mU7ZAmC6 = tr("Setting up native voice stream!"))); + if (!this.native_encoding_supported()) { + log.warn(LogCategory.VOICE, _translations.F7kOnJnp || (_translations.F7kOnJnp = tr("Native codec isnt supported!"))); + return; + } + this.voiceRecorder.on_data = undefined; + let stream = this.voiceRecorder.get_output_stream(); + stream.disconnect(); + if (!this.local_audio_stream) + this.local_audio_stream = audio.player.context().createMediaStreamDestination(); + stream.connect(this.local_audio_stream); + } + setup_js() { + if (!this.javascript_encoding_supported()) + return; + this.voiceRecorder.on_data = this.handleVoiceData.bind(this); + } + get type() { return this._type; } + set type(target) { + if (target == this.type) + return; + this._type = target; + if (this.type == VoiceConnectionType.NATIVE_ENCODE) + this.setup_native(); + else + this.setup_js(); + this.createSession(); + } + codecSupported(type) { + return this.codec_pool.length > type && this.codec_pool[type].supported(); + } + voice_playback_support() { + return this.dataChannel && this.dataChannel.readyState == "open"; + } + voice_send_support() { + if (this.type == VoiceConnectionType.NATIVE_ENCODE) + return this.native_encoding_supported() && this.rtcPeerConnection.getLocalStreams().length > 0; + else + return this.voice_playback_support(); + } + handleEncodedVoicePacket(data, codec) { + this.voice_send_queue.push({ data: data, codec: codec }); + } + sendNextVoicePacket() { + let buffer = this.voice_send_queue.pop_front(); + if (!buffer) + return; + this.sendVoicePacket(buffer.data, buffer.codec); + } + sendVoicePacket(data, codec) { + if (this.dataChannel) { + this.vpacketId++; + if (this.vpacketId > 65535) + this.vpacketId = 0; + let packet = new Uint8Array(data.byteLength + 2 + 3); + packet[0] = this.chunkVPacketId++ < 5 ? 1 : 0; //Flag header + packet[1] = 0; //Flag fragmented + packet[2] = (this.vpacketId >> 8) & 0xFF; //HIGHT (voiceID) + packet[3] = (this.vpacketId >> 0) & 0xFF; //LOW (voiceID) + packet[4] = codec; //Codec + packet.set(data, 5); + try { + this.dataChannel.send(packet); + } + catch (e) { + //TODO may handle error? + } + } + else { + console.warn(_translations.FBBcXTnB || (_translations.FBBcXTnB = tr("Could not transfer audio (not connected)"))); + } + } + createSession() { + if (!audio.player.initialized()) { + console.log(_translations.QTx3nvcX || (_translations.QTx3nvcX = tr("Audio player isn't initialized yet. Waiting for gesture."))); + audio.player.on_ready(() => this.createSession()); + return; + } + if (!this.current_encoding_supported()) + return false; + if (this.rtcPeerConnection) { + this.dropSession(); + } + this._ice_use_cache = true; + let config = {}; + config.iceServers = []; + config.iceServers.push({ urls: 'stun:stun.l.google.com:19302' }); + this.rtcPeerConnection = new RTCPeerConnection(config); + const dataChannelConfig = { ordered: true, maxRetransmits: 0 }; + this.dataChannel = this.rtcPeerConnection.createDataChannel('main', dataChannelConfig); + this.dataChannel.onmessage = this.onDataChannelMessage.bind(this); + this.dataChannel.onopen = this.onDataChannelOpen.bind(this); + this.dataChannel.binaryType = "arraybuffer"; + let sdpConstraints = {}; + sdpConstraints.offerToReceiveAudio = this._type == VoiceConnectionType.NATIVE_ENCODE; + sdpConstraints.offerToReceiveVideo = false; + this.rtcPeerConnection.onicecandidate = this.onIceCandidate.bind(this); + if (this.local_audio_stream) { //May a typecheck? + this.rtcPeerConnection.addStream(this.local_audio_stream.stream); + console.log(_translations.z0mKdtjN || (_translations.z0mKdtjN = tr("Adding stream (%o)!")), this.local_audio_stream.stream); + } + this.rtcPeerConnection.createOffer(this.onOfferCreated.bind(this), () => { + console.error(_translations.DTf5g1uR || (_translations.DTf5g1uR = tr("Could not create ice offer!"))); + }, sdpConstraints); + } + dropSession() { + if (this.dataChannel) + this.dataChannel.close(); + if (this.rtcPeerConnection) + this.rtcPeerConnection.close(); + //TODO here! + } + handleControlPacket(json) { + if (json["request"] === "answer") { + console.log(_translations.A1ka3yfu || (_translations.A1ka3yfu = tr("Set remote sdp! (%o)")), json["msg"]); + this.rtcPeerConnection.setRemoteDescription(new RTCSessionDescription(json["msg"])).catch(error => { + console.log(_translations.BNCVcnv7 || (_translations.BNCVcnv7 = tr("Failed to apply remote description: %o")), error); //FIXME error handling! + }); + this._ice_use_cache = false; + for (let msg of this._ice_cache) { + this.rtcPeerConnection.addIceCandidate(new RTCIceCandidate(msg)).catch(error => { + console.log(_translations.B7EYIlQD || (_translations.B7EYIlQD = tr("Failed to add remote cached ice candidate %s: %o")), msg, error); + }); + } + } + else if (json["request"] === "ice") { + if (!this._ice_use_cache) { + console.log(_translations.j7WFGiPM || (_translations.j7WFGiPM = tr("Add remote ice! (%s | %o)")), json["msg"], json); + this.rtcPeerConnection.addIceCandidate(new RTCIceCandidate(json["msg"])).catch(error => { + console.log(_translations.Y1UQmWiM || (_translations.Y1UQmWiM = tr("Failed to add remote ice candidate %s: %o")), json["msg"], error); + }); + } + else { + console.log(_translations.XOmIStjD || (_translations.XOmIStjD = tr("Cache remote ice! (%s | %o)")), json["msg"], json); + this._ice_cache.push(json["msg"]); + } + } + else if (json["request"] == "status") { + if (json["state"] == "failed") { + chat.serverChat().appendError(_translations.ythe3GnZ || (_translations.ythe3GnZ = tr("Failed to setup voice bridge ({}). Allow reconnect: {}")), json["reason"], json["allow_reconnect"]); + log.error(LogCategory.NETWORKING, _translations._vnSXilG || (_translations._vnSXilG = tr("Failed to setup voice bridge (%s). Allow reconnect: %s")), json["reason"], json["allow_reconnect"]); + if (json["allow_reconnect"] == true) { + this.createSession(); + } + //TODO handle fail specially when its not allowed to reconnect + } + } + } + //Listeners + onIceCandidate(event) { + console.log(_translations.sHVFQdqt || (_translations.sHVFQdqt = tr("Got ice candidate! Event:"))); + console.log(event); + if (event) { + if (event.candidate) + this.client.serverConnection.sendData(JSON.stringify({ + type: 'WebRTC', + request: "ice", + msg: event.candidate, + })); + else { + this.client.serverConnection.sendData(JSON.stringify({ + type: 'WebRTC', + request: "ice_finish" + })); + } + } + } + onOfferCreated(localSession) { + console.log(_translations.R64I2bL6 || (_translations.R64I2bL6 = tr("Offer created and accepted"))); + this.rtcPeerConnection.setLocalDescription(localSession).catch(error => { + console.log(_translations.rpGfb5bB || (_translations.rpGfb5bB = tr("Failed to apply local description: %o")), error); + //FIXME error handling + }); + console.log(_translations.sUrbL8F8 || (_translations.sUrbL8F8 = tr("Send offer: %o")), localSession); + this.client.serverConnection.sendData(JSON.stringify({ type: 'WebRTC', request: "create", msg: localSession })); + } + onDataChannelOpen(channel) { + console.log(_translations.aCeDkOq4 || (_translations.aCeDkOq4 = tr("Got new data channel! (%s)")), this.dataChannel.readyState); + this.client.controlBar.updateVoice(); + } + onDataChannelMessage(message) { + if (this.client.controlBar.muteOutput) + return; + let bin = new Uint8Array(message.data); + let clientId = bin[2] << 8 | bin[3]; + let packetId = bin[0] << 8 | bin[1]; + let codec = bin[4]; + //console.log("Client id " + clientId + " PacketID " + packetId + " Codec: " + codec); + let client = this.client.channelTree.findClient(clientId); + if (!client) { + console.error(_translations.u9oEsZpv || (_translations.u9oEsZpv = tr("Having voice from unknown client? (ClientID: %o)")), clientId); + return; + } + let codecPool = this.codec_pool[codec]; + if (!codecPool) { + console.error(_translations.sQ8Ba2oR || (_translations.sQ8Ba2oR = tr("Could not playback codec %o")), codec); + return; + } + let encodedData; + if (message.data.subarray) + encodedData = message.data.subarray(5); + else + encodedData = new Uint8Array(message.data, 5); + if (encodedData.length == 0) { + client.getAudioController().stopAudio(); + codecPool.releaseCodec(clientId); + } + else { + codecPool.ownCodec(clientId) + .then(decoder => decoder.decodeSamples(client.getAudioController().codecCache(codec), encodedData)) + .then(buffer => client.getAudioController().playBuffer(buffer)).catch(error => { + console.error(_translations.vH2yGkAk || (_translations.vH2yGkAk = tr("Could not playback client's (%o) audio (%o)")), clientId, error); + if (error instanceof Error) + console.error(error.stack); + }); + } + } + current_channel_codec() { + return (this.client.getClient().currentChannel() || { properties: { channel_codec: 4 } }).properties.channel_codec; + } + handleVoiceData(data, head) { + if (!this.voiceRecorder) + return; + if (!this.client.connected) + return false; + if (this.client.controlBar.muteInput) + return; + if (head) { + this.chunkVPacketId = 0; + this.client.getClient().speaking = true; + } + //TODO Use channel codec! + const codec = this.current_channel_codec(); + this.codec_pool[codec].ownCodec(this.client.getClientId()) + .then(encoder => encoder.encodeSamples(this.client.getClient().getAudioController().codecCache(codec), data)); + } + handleVoiceEnded() { + if (this.client && this.client.getClient()) + this.client.getClient().speaking = false; + if (!this.voiceRecorder) + return; + if (!this.client.connected) + return; + console.log(_translations.S2lnS5ls || (_translations.S2lnS5ls = tr("Local voice ended"))); + if (this.dataChannel) + this.sendVoicePacket(new Uint8Array(0), this.current_channel_codec()); //TODO Use channel codec! + } + handleVoiceStarted() { + console.log(_translations.PXSYJ5v0 || (_translations.PXSYJ5v0 = tr("Local voice started"))); + if (this.client && this.client.getClient()) + this.client.getClient().speaking = true; + } +} +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["775ab808069a9c2be9cc5e58e0bd80887fbc8b52ca9b9db14075a1018288337a"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["775ab808069a9c2be9cc5e58e0bd80887fbc8b52ca9b9db14075a1018288337a"] = "775ab808069a9c2be9cc5e58e0bd80887fbc8b52ca9b9db14075a1018288337a"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of []) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +let context_menu; +$(document).bind("mousedown", function (e) { + let menu = context_menu || (context_menu = $(".context-menu")); + if (!menu.is(":visible")) + return; + if ($(e.target).parents(".context-menu").length == 0) { + despawn_context_menu(); + } +}); +let contextMenuCloseFn = undefined; +function despawn_context_menu() { + let menu = context_menu || (context_menu = $(".context-menu")); + if (!menu.is(":visible")) + return; + menu.hide(100); + if (contextMenuCloseFn) + contextMenuCloseFn(); +} +var MenuEntryType; +(function (MenuEntryType) { + MenuEntryType[MenuEntryType["CLOSE"] = 0] = "CLOSE"; + MenuEntryType[MenuEntryType["ENTRY"] = 1] = "ENTRY"; + MenuEntryType[MenuEntryType["HR"] = 2] = "HR"; + MenuEntryType[MenuEntryType["SUB_MENU"] = 3] = "SUB_MENU"; +})(MenuEntryType || (MenuEntryType = {})); +class MenuEntry { + static HR() { + return { + callback: () => { }, + type: MenuEntryType.HR, + name: "", + icon: "" + }; + } + ; + static CLOSE(callback) { + return { + callback: callback, + type: MenuEntryType.CLOSE, + name: "", + icon: "" + }; + } +} +function generate_tag(entry) { + if (entry.type == MenuEntryType.HR) { + return $.spawn("hr"); + } + else if (entry.type == MenuEntryType.ENTRY) { + console.log(entry.icon); + let icon = $.isFunction(entry.icon) ? entry.icon() : entry.icon; + if (typeof (icon) === "string") { + if (!icon || icon.length == 0) + icon = "icon_empty"; + else + icon = "icon " + icon; + } + let tag = $.spawn("div").addClass("entry"); + tag.append(typeof (icon) === "string" ? $.spawn("div").addClass(icon) : icon); + tag.append($.spawn("div").html($.isFunction(entry.name) ? entry.name() : entry.name)); + if (entry.disabled || entry.invalidPermission) + tag.addClass("disabled"); + else { + tag.click(function () { + if ($.isFunction(entry.callback)) + entry.callback(); + despawn_context_menu(); + }); + } + return tag; + } + else if (entry.type == MenuEntryType.SUB_MENU) { + let icon = $.isFunction(entry.icon) ? entry.icon() : entry.icon; + if (typeof (icon) === "string") { + if (!icon || icon.length == 0) + icon = "icon_empty"; + else + icon = "icon " + icon; + } + let tag = $.spawn("div").addClass("entry").addClass("sub-container"); + tag.append(typeof (icon) === "string" ? $.spawn("div").addClass(icon) : icon); + tag.append($.spawn("div").html($.isFunction(entry.name) ? entry.name() : entry.name)); + tag.append($.spawn("div").addClass("arrow right")); + if (entry.disabled || entry.invalidPermission) + tag.addClass("disabled"); + else { + let menu = $.spawn("div").addClass("sub-menu").addClass("context-menu"); + for (let e of entry.sub_menu) + menu.append(generate_tag(e)); + menu.appendTo(tag); + } + return tag; + } + return $.spawn("div").text("undefined"); +} +function spawn_context_menu(x, y, ...entries) { + let menu = context_menu || (context_menu = $(".context-menu")); + menu.finish().empty(); + contextMenuCloseFn = undefined; + for (let entry of entries) { + if (entry.type == MenuEntryType.CLOSE) { + contextMenuCloseFn = entry.callback; + } + else + menu.append(generate_tag(entry)); + } + menu.show(100); + // In the right position (the mouse) + menu.css({ + "top": y + "px", + "left": x + "px" + }); +} +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["51a461c33127132fca0884de56176443fbdb7d1b6404f440f36b4489afd06853"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["51a461c33127132fca0884de56176443fbdb7d1b6404f440f36b4489afd06853"] = "51a461c33127132fca0884de56176443fbdb7d1b6404f440f36b4489afd06853"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of []) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +var sha; +(function (sha) { + /* + * [js-sha1]{@link https://github.com/emn178/js-sha1} + * + * @version 0.6.0 + * @author Chen, Yi-Cyuan [emn178@gmail.com] + * @copyright Chen, Yi-Cyuan 2014-2017 + * @license MIT + */ + /*jslint bitwise: true */ + (function () { + 'use strict'; + let root = typeof window === 'object' ? window : {}; + let NODE_JS = !root.JS_SHA1_NO_NODE_JS && typeof process === 'object' && process.versions && process.versions.node; + if (NODE_JS) { + root = global; + } + let COMMON_JS = !root.JS_SHA1_NO_COMMON_JS && typeof module === 'object' && module.exports; + let AMD = typeof define === 'function' && define.amd; + let HEX_CHARS = '0123456789abcdef'.split(''); + let EXTRA = [-2147483648, 8388608, 32768, 128]; + let SHIFT = [24, 16, 8, 0]; + let OUTPUT_TYPES = ['hex', 'array', 'digest', 'arrayBuffer']; + let blocks = []; + let createOutputMethod = function (outputType) { + return function (message) { + return new Sha1(true).update(message)[outputType](); + }; + }; + let createMethod = function () { + let method = createOutputMethod('hex'); + if (NODE_JS) { + method = nodeWrap(method); + } + method.create = function () { + return new Sha1(); + }; + method.update = function (message) { + return method.create().update(message); + }; + for (var i = 0; i < OUTPUT_TYPES.length; ++i) { + var type = OUTPUT_TYPES[i]; + method[type] = createOutputMethod(type); + } + return method; + }; + var nodeWrap = function (method) { + var crypto = eval("require('crypto')"); + var Buffer = eval("require('buffer').Buffer"); + var nodeMethod = function (message) { + if (typeof message === 'string') { + return crypto.createHash('sha1').update(message, 'utf8').digest('hex'); + } + else if (message.constructor === ArrayBuffer) { + message = new Uint8Array(message); + } + else if (message.length === undefined) { + return method(message); + } + return crypto.createHash('sha1').update(new Buffer(message)).digest('hex'); + }; + return nodeMethod; + }; + function Sha1(sharedMemory) { + if (sharedMemory) { + blocks[0] = blocks[16] = blocks[1] = blocks[2] = blocks[3] = + blocks[4] = blocks[5] = blocks[6] = blocks[7] = + blocks[8] = blocks[9] = blocks[10] = blocks[11] = + blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0; + this.blocks = blocks; + } + else { + this.blocks = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + } + this.h0 = 0x67452301; + this.h1 = 0xEFCDAB89; + this.h2 = 0x98BADCFE; + this.h3 = 0x10325476; + this.h4 = 0xC3D2E1F0; + this.block = this.start = this.bytes = this.hBytes = 0; + this.finalized = this.hashed = false; + this.first = true; + } + Sha1.prototype.update = function (message) { + if (this.finalized) { + return; + } + var notString = typeof (message) !== 'string'; + if (notString && message.constructor === root.ArrayBuffer) { + message = new Uint8Array(message); + } + var code, index = 0, i, length = message.length || 0, blocks = this.blocks; + while (index < length) { + if (this.hashed) { + this.hashed = false; + blocks[0] = this.block; + blocks[16] = blocks[1] = blocks[2] = blocks[3] = + blocks[4] = blocks[5] = blocks[6] = blocks[7] = + blocks[8] = blocks[9] = blocks[10] = blocks[11] = + blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0; + } + if (notString) { + for (i = this.start; index < length && i < 64; ++index) { + blocks[i >> 2] |= message[index] << SHIFT[i++ & 3]; + } + } + else { + for (i = this.start; index < length && i < 64; ++index) { + code = message.charCodeAt(index); + if (code < 0x80) { + blocks[i >> 2] |= code << SHIFT[i++ & 3]; + } + else if (code < 0x800) { + blocks[i >> 2] |= (0xc0 | (code >> 6)) << SHIFT[i++ & 3]; + blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; + } + else if (code < 0xd800 || code >= 0xe000) { + blocks[i >> 2] |= (0xe0 | (code >> 12)) << SHIFT[i++ & 3]; + blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3]; + blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; + } + else { + code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff)); + blocks[i >> 2] |= (0xf0 | (code >> 18)) << SHIFT[i++ & 3]; + blocks[i >> 2] |= (0x80 | ((code >> 12) & 0x3f)) << SHIFT[i++ & 3]; + blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3]; + blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; + } + } + } + this.lastByteIndex = i; + this.bytes += i - this.start; + if (i >= 64) { + this.block = blocks[16]; + this.start = i - 64; + this.hash(); + this.hashed = true; + } + else { + this.start = i; + } + } + if (this.bytes > 4294967295) { + this.hBytes += this.bytes / 4294967296 << 0; + this.bytes = this.bytes % 4294967296; + } + return this; + }; + Sha1.prototype.finalize = function () { + if (this.finalized) { + return; + } + this.finalized = true; + var blocks = this.blocks, i = this.lastByteIndex; + blocks[16] = this.block; + blocks[i >> 2] |= EXTRA[i & 3]; + this.block = blocks[16]; + if (i >= 56) { + if (!this.hashed) { + this.hash(); + } + blocks[0] = this.block; + blocks[16] = blocks[1] = blocks[2] = blocks[3] = + blocks[4] = blocks[5] = blocks[6] = blocks[7] = + blocks[8] = blocks[9] = blocks[10] = blocks[11] = + blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0; + } + blocks[14] = this.hBytes << 3 | this.bytes >>> 29; + blocks[15] = this.bytes << 3; + this.hash(); + }; + Sha1.prototype.hash = function () { + var a = this.h0, b = this.h1, c = this.h2, d = this.h3, e = this.h4; + var f, j, t, blocks = this.blocks; + for (j = 16; j < 80; ++j) { + t = blocks[j - 3] ^ blocks[j - 8] ^ blocks[j - 14] ^ blocks[j - 16]; + blocks[j] = (t << 1) | (t >>> 31); + } + for (j = 0; j < 20; j += 5) { + f = (b & c) | ((~b) & d); + t = (a << 5) | (a >>> 27); + e = t + f + e + 1518500249 + blocks[j] << 0; + b = (b << 30) | (b >>> 2); + f = (a & b) | ((~a) & c); + t = (e << 5) | (e >>> 27); + d = t + f + d + 1518500249 + blocks[j + 1] << 0; + a = (a << 30) | (a >>> 2); + f = (e & a) | ((~e) & b); + t = (d << 5) | (d >>> 27); + c = t + f + c + 1518500249 + blocks[j + 2] << 0; + e = (e << 30) | (e >>> 2); + f = (d & e) | ((~d) & a); + t = (c << 5) | (c >>> 27); + b = t + f + b + 1518500249 + blocks[j + 3] << 0; + d = (d << 30) | (d >>> 2); + f = (c & d) | ((~c) & e); + t = (b << 5) | (b >>> 27); + a = t + f + a + 1518500249 + blocks[j + 4] << 0; + c = (c << 30) | (c >>> 2); + } + for (; j < 40; j += 5) { + f = b ^ c ^ d; + t = (a << 5) | (a >>> 27); + e = t + f + e + 1859775393 + blocks[j] << 0; + b = (b << 30) | (b >>> 2); + f = a ^ b ^ c; + t = (e << 5) | (e >>> 27); + d = t + f + d + 1859775393 + blocks[j + 1] << 0; + a = (a << 30) | (a >>> 2); + f = e ^ a ^ b; + t = (d << 5) | (d >>> 27); + c = t + f + c + 1859775393 + blocks[j + 2] << 0; + e = (e << 30) | (e >>> 2); + f = d ^ e ^ a; + t = (c << 5) | (c >>> 27); + b = t + f + b + 1859775393 + blocks[j + 3] << 0; + d = (d << 30) | (d >>> 2); + f = c ^ d ^ e; + t = (b << 5) | (b >>> 27); + a = t + f + a + 1859775393 + blocks[j + 4] << 0; + c = (c << 30) | (c >>> 2); + } + for (; j < 60; j += 5) { + f = (b & c) | (b & d) | (c & d); + t = (a << 5) | (a >>> 27); + e = t + f + e - 1894007588 + blocks[j] << 0; + b = (b << 30) | (b >>> 2); + f = (a & b) | (a & c) | (b & c); + t = (e << 5) | (e >>> 27); + d = t + f + d - 1894007588 + blocks[j + 1] << 0; + a = (a << 30) | (a >>> 2); + f = (e & a) | (e & b) | (a & b); + t = (d << 5) | (d >>> 27); + c = t + f + c - 1894007588 + blocks[j + 2] << 0; + e = (e << 30) | (e >>> 2); + f = (d & e) | (d & a) | (e & a); + t = (c << 5) | (c >>> 27); + b = t + f + b - 1894007588 + blocks[j + 3] << 0; + d = (d << 30) | (d >>> 2); + f = (c & d) | (c & e) | (d & e); + t = (b << 5) | (b >>> 27); + a = t + f + a - 1894007588 + blocks[j + 4] << 0; + c = (c << 30) | (c >>> 2); + } + for (; j < 80; j += 5) { + f = b ^ c ^ d; + t = (a << 5) | (a >>> 27); + e = t + f + e - 899497514 + blocks[j] << 0; + b = (b << 30) | (b >>> 2); + f = a ^ b ^ c; + t = (e << 5) | (e >>> 27); + d = t + f + d - 899497514 + blocks[j + 1] << 0; + a = (a << 30) | (a >>> 2); + f = e ^ a ^ b; + t = (d << 5) | (d >>> 27); + c = t + f + c - 899497514 + blocks[j + 2] << 0; + e = (e << 30) | (e >>> 2); + f = d ^ e ^ a; + t = (c << 5) | (c >>> 27); + b = t + f + b - 899497514 + blocks[j + 3] << 0; + d = (d << 30) | (d >>> 2); + f = c ^ d ^ e; + t = (b << 5) | (b >>> 27); + a = t + f + a - 899497514 + blocks[j + 4] << 0; + c = (c << 30) | (c >>> 2); + } + this.h0 = this.h0 + a << 0; + this.h1 = this.h1 + b << 0; + this.h2 = this.h2 + c << 0; + this.h3 = this.h3 + d << 0; + this.h4 = this.h4 + e << 0; + }; + Sha1.prototype.hex = function () { + this.finalize(); + var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3, h4 = this.h4; + return HEX_CHARS[(h0 >> 28) & 0x0F] + HEX_CHARS[(h0 >> 24) & 0x0F] + + HEX_CHARS[(h0 >> 20) & 0x0F] + HEX_CHARS[(h0 >> 16) & 0x0F] + + HEX_CHARS[(h0 >> 12) & 0x0F] + HEX_CHARS[(h0 >> 8) & 0x0F] + + HEX_CHARS[(h0 >> 4) & 0x0F] + HEX_CHARS[h0 & 0x0F] + + HEX_CHARS[(h1 >> 28) & 0x0F] + HEX_CHARS[(h1 >> 24) & 0x0F] + + HEX_CHARS[(h1 >> 20) & 0x0F] + HEX_CHARS[(h1 >> 16) & 0x0F] + + HEX_CHARS[(h1 >> 12) & 0x0F] + HEX_CHARS[(h1 >> 8) & 0x0F] + + HEX_CHARS[(h1 >> 4) & 0x0F] + HEX_CHARS[h1 & 0x0F] + + HEX_CHARS[(h2 >> 28) & 0x0F] + HEX_CHARS[(h2 >> 24) & 0x0F] + + HEX_CHARS[(h2 >> 20) & 0x0F] + HEX_CHARS[(h2 >> 16) & 0x0F] + + HEX_CHARS[(h2 >> 12) & 0x0F] + HEX_CHARS[(h2 >> 8) & 0x0F] + + HEX_CHARS[(h2 >> 4) & 0x0F] + HEX_CHARS[h2 & 0x0F] + + HEX_CHARS[(h3 >> 28) & 0x0F] + HEX_CHARS[(h3 >> 24) & 0x0F] + + HEX_CHARS[(h3 >> 20) & 0x0F] + HEX_CHARS[(h3 >> 16) & 0x0F] + + HEX_CHARS[(h3 >> 12) & 0x0F] + HEX_CHARS[(h3 >> 8) & 0x0F] + + HEX_CHARS[(h3 >> 4) & 0x0F] + HEX_CHARS[h3 & 0x0F] + + HEX_CHARS[(h4 >> 28) & 0x0F] + HEX_CHARS[(h4 >> 24) & 0x0F] + + HEX_CHARS[(h4 >> 20) & 0x0F] + HEX_CHARS[(h4 >> 16) & 0x0F] + + HEX_CHARS[(h4 >> 12) & 0x0F] + HEX_CHARS[(h4 >> 8) & 0x0F] + + HEX_CHARS[(h4 >> 4) & 0x0F] + HEX_CHARS[h4 & 0x0F]; + }; + Sha1.prototype.toString = Sha1.prototype.hex; + Sha1.prototype.digest = function () { + this.finalize(); + var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3, h4 = this.h4; + return [ + (h0 >> 24) & 0xFF, (h0 >> 16) & 0xFF, (h0 >> 8) & 0xFF, h0 & 0xFF, + (h1 >> 24) & 0xFF, (h1 >> 16) & 0xFF, (h1 >> 8) & 0xFF, h1 & 0xFF, + (h2 >> 24) & 0xFF, (h2 >> 16) & 0xFF, (h2 >> 8) & 0xFF, h2 & 0xFF, + (h3 >> 24) & 0xFF, (h3 >> 16) & 0xFF, (h3 >> 8) & 0xFF, h3 & 0xFF, + (h4 >> 24) & 0xFF, (h4 >> 16) & 0xFF, (h4 >> 8) & 0xFF, h4 & 0xFF + ]; + }; + Sha1.prototype.array = Sha1.prototype.digest; + Sha1.prototype.arrayBuffer = function () { + this.finalize(); + var buffer = new ArrayBuffer(20); + var dataView = new DataView(buffer); + dataView.setUint32(0, this.h0); + dataView.setUint32(4, this.h1); + dataView.setUint32(8, this.h2); + dataView.setUint32(12, this.h3); + dataView.setUint32(16, this.h4); + return buffer; + }; + var exports = createMethod(); + if (COMMON_JS) { + module.exports = exports; + } + else { + root._sha1 = exports; + if (AMD) { + define(function () { + return exports; + }); + } + } + })(); + function encode_text(buffer) { + if (window.TextEncoder) { + return new TextEncoder().encode(buffer).buffer; + } + let utf8 = unescape(encodeURIComponent(buffer)); + let result = new Uint8Array(utf8.length); + for (let i = 0; i < utf8.length; i++) { + result[i] = utf8.charCodeAt(i); + } + return result.buffer; + } + sha.encode_text = encode_text; + function sha1(message) { + if (!(typeof (message) === "string" || message instanceof ArrayBuffer)) + throw "Invalid type!"; + let buffer = message instanceof ArrayBuffer ? message : encode_text(message); + if (!crypto || !crypto.subtle || !crypto.subtle.digest || /Edge/.test(navigator.userAgent)) + return new Promise(resolve => { + resolve(_sha1.arrayBuffer(buffer)); + }); + else + return crypto.subtle.digest("SHA-1", buffer); + } + sha.sha1 = sha1; +})(sha || (sha = {})); +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["517d19bc00e3255e9af067c1436f53169327e8a5ef9fb42c1f675a97eda58851"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["517d19bc00e3255e9af067c1436f53169327e8a5ef9fb42c1f675a97eda58851"] = "517d19bc00e3255e9af067c1436f53169327e8a5ef9fb42c1f675a97eda58851"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of []) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +/// +var helpers; +(function (helpers) { + function hashPassword(password) { + return new Promise((resolve, reject) => { + sha.sha1(password).then(result => { + resolve(btoa(String.fromCharCode.apply(null, new Uint8Array(result)))); + }); + }); + } + helpers.hashPassword = hashPassword; +})(helpers || (helpers = {})); +class LaterPromise extends Promise { + constructor() { + super((resolve, reject) => { }); + this._handle = new Promise((resolve, reject) => { + this._resolve = resolve; + this._reject = reject; + }); + this._time = Date.now(); + } + resolved(object) { + this._resolve(object); + } + rejected(reason) { + this._reject(reason); + } + function_rejected() { + return error => this.rejected(error); + } + time() { return this._time; } + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled, onrejected) { + return this._handle.then(onfulfilled, onrejected); + } + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected) { + return this._handle.then(onrejected); + } +} +const copy_to_clipboard = str => { + const el = document.createElement('textarea'); + el.value = str; + el.setAttribute('readonly', ''); + el.style.position = 'absolute'; + el.style.left = '-9999px'; + document.body.appendChild(el); + const selected = document.getSelection().rangeCount > 0 + ? document.getSelection().getRangeAt(0) + : false; + el.select(); + document.execCommand('copy'); + document.body.removeChild(el); + if (selected) { + document.getSelection().removeAllRanges(); + document.getSelection().addRange(selected); + } +}; +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["87b19fc0c7bbf638de93ca469843e03db19abbee1f2beffc648540779fc5ffe7"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["87b19fc0c7bbf638de93ca469843e03db19abbee1f2beffc648540779fc5ffe7"] = "87b19fc0c7bbf638de93ca469843e03db19abbee1f2beffc648540779fc5ffe7"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "aj1gtLqv", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/channel.ts (237,36)" }, { name: "teLhTVSa", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/channel.ts (244,36)" }, { name: "J0dpFOc2", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/channel.ts (251,36)" }, { name: "AJW_7Ysi", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/channel.ts (258,36)" }, { name: "WQPwyWBa", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/channel.ts (265,36)" }, { name: "fYGIIiFf", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/channel.ts (430,23)" }, { name: "xjDLtc_W", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/channel.ts (437,23)" }, { name: "fK8ljRBd", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/channel.ts (444,59)" }, { name: "Yzzhr43h", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/channel.ts (471,23)" }, { name: "NCpTBV8E", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/channel.ts (483,23)" }, { name: "CAKzmQnK", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/channel.ts (486,41)" }, { name: "Xy9l9iJX", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/channel.ts (486,73)" }, { name: "cW_P2hlA", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/channel.ts (492,42)" }, { name: "okfaF6u3", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/channel.ts (492,98)" }, { name: "vsYTC19a", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/channel.ts (500,23)" }, { name: "INSAXHWq", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/channel.ts (506,23)" }, { name: "F8DyGDHM", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/channel.ts (531,25)" }, { name: "fTdJPDs3", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/channel.ts (554,25)" }, { name: "g1tVT87U", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/channel.ts (585,59)" }, { name: "oU_VGnSx", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/channel.ts (592,21)" }, { name: "bLb2uTaE", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/channel.ts (601,82)" }, { name: "t4jDfLgx", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/channel.ts (608,23)" }, { name: "DbnOB3N5", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/channel.ts (688,30)" }, { name: "vKeWNwib", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/channel.ts (688,54)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +/// +/// +var ChannelType; +(function (ChannelType) { + ChannelType[ChannelType["PERMANENT"] = 0] = "PERMANENT"; + ChannelType[ChannelType["SEMI_PERMANENT"] = 1] = "SEMI_PERMANENT"; + ChannelType[ChannelType["TEMPORARY"] = 2] = "TEMPORARY"; +})(ChannelType || (ChannelType = {})); +(function (ChannelType) { + function normalize(mode) { + let value = ChannelType[mode]; + value = value.toLowerCase(); + return value[0].toUpperCase() + value.substr(1); + } + ChannelType.normalize = normalize; +})(ChannelType || (ChannelType = {})); +class ChannelProperties { + constructor() { + this.channel_order = 0; + this.channel_name = ""; + this.channel_name_phonetic = ""; + this.channel_topic = ""; + this.channel_password = ""; + this.channel_codec = 4; + this.channel_codec_quality = 0; + this.channel_codec_is_unencrypted = false; + this.channel_maxclients = -1; + this.channel_maxfamilyclients = -1; + this.channel_needed_talk_power = 1; + this.channel_flag_permanent = false; + this.channel_flag_semi_permanent = false; + this.channel_flag_default = false; + this.channel_flag_password = false; + this.channel_flag_maxclients_unlimited = false; + this.channel_flag_maxfamilyclients_inherited = false; + this.channel_flag_maxfamilyclients_unlimited = false; + this.channel_icon_id = 0; + this.channel_delete_delay = 0; + //Only after request + this.channel_description = ""; + } +} +class ChannelEntry { + constructor(channelId, channelName, parent = null) { + this.properties = new ChannelProperties(); + this._channel_name_alignment = undefined; + this._channel_name_formatted = undefined; + this._family_index = 0; + this._cached_channel_description = undefined; + this._cached_channel_description_promise = undefined; + this._cached_channel_description_promise_resolve = undefined; + this._cached_channel_description_promise_reject = undefined; + this.properties = new ChannelProperties(); + this.channelId = channelId; + this.properties.channel_name = channelName; + this.parent = parent; + this.channelTree = null; + this.initializeTag(); + this.__updateChannelName(); + } + channelName() { + return this.properties.channel_name; + } + formattedChannelName() { + return this._channel_name_formatted || this.properties.channel_name; + } + getChannelDescription() { + if (this._cached_channel_description) + return new Promise(resolve => resolve(this._cached_channel_description)); + if (this._cached_channel_description_promise) + return this._cached_channel_description_promise; + this.channelTree.client.serverConnection.send_command("channelgetdescription", { cid: this.channelId }).catch(error => { + this._cached_channel_description_promise_reject(error); + }); + return this._cached_channel_description_promise = new Promise((resolve, reject) => { + this._cached_channel_description_promise_resolve = resolve; + this._cached_channel_description_promise_reject = reject; + }); + } + parent_channel() { return this.parent; } + hasParent() { return this.parent != null; } + getChannelId() { return this.channelId; } + children(deep = false) { + const result = []; + if (this.channelTree == null) + return []; + const self = this; + this.channelTree.channels.forEach(function (entry) { + let current = entry; + if (deep) { + while (current) { + if (current.parent_channel() == self) { + result.push(entry); + break; + } + current = current.parent_channel(); + } + } + else if (current.parent_channel() == self) + result.push(entry); + }); + return result; + } + clients(deep = false) { + const result = []; + if (this.channelTree == null) + return []; + const self = this; + this.channelTree.clients.forEach(function (entry) { + let current = entry.currentChannel(); + if (deep) { + while (current) { + if (current == self) { + result.push(entry); + break; + } + current = current.parent_channel(); + } + } + else if (current == self) + result.push(entry); + }); + return result; + } + clients_ordered() { + const clients = this.clients(false); + clients.sort((a, b) => { + if (a.properties.client_talk_power < b.properties.client_talk_power) + return 1; + if (a.properties.client_talk_power > b.properties.client_talk_power) + return -1; + if (a.properties.client_nickname > b.properties.client_nickname) + return 1; + if (a.properties.client_nickname < b.properties.client_nickname) + return -1; + return 0; + }); + return clients; + } + update_family_index(enforce) { + const current_index = this._family_index; + const new_index = this.calculate_family_index(true); + if (current_index == new_index && !enforce) + return; + this._tag_channel.css("z-index", this._family_index); + this._tag_channel.css("padding-left", (this._family_index + 1) * 16 + "px"); + } + calculate_family_index(enforce_recalculate = false) { + if (this._family_index !== undefined && !enforce_recalculate) + return this._family_index; + this._family_index = 0; + let channel = this.parent_channel(); + while (channel) { + this._family_index++; + channel = channel.parent_channel(); + } + return this._family_index; + } + initializeTag() { + const tag_channel = $.spawn("div").addClass("tree-entry channel"); + { + const container_entry = $.spawn("div").addClass("container-channel"); + container_entry.attr("channel-id", this.channelId); + container_entry.addClass(this._channel_name_alignment); + /* channel icon (type) */ + { + container_entry.append($.spawn("div") + .addClass("show-channel-normal-only channel-type icon client-channel_green_subscribed")); + } + /* channel name */ + { + container_entry.append($.spawn("div") + .addClass("container-channel-name") + .append($.spawn("a") + .addClass("channel-name") + .text(this.channelName()))); + } + /* all icons (last element) */ + { + //Icons + let container_icons = $.spawn("span").addClass("icons"); + //Default icon (5) + container_icons.append($.spawn("div") + .addClass("show-channel-normal-only icon_entry icon_default icon client-channel_default") + .attr("title", _translations.aj1gtLqv || (_translations.aj1gtLqv = tr("Default channel")))); + //Password icon (4) + container_icons.append($.spawn("div") + .addClass("show-channel-normal-only icon_entry icon_password icon client-register") + .attr("title", _translations.teLhTVSa || (_translations.teLhTVSa = tr("The channel is password protected")))); + //Music icon (3) + container_icons.append($.spawn("div") + .addClass("show-channel-normal-only icon_entry icon_music icon client-music") + .attr("title", _translations.J0dpFOc2 || (_translations.J0dpFOc2 = tr("Music quality")))); + //Channel moderated (2) + container_icons.append($.spawn("div") + .addClass("show-channel-normal-only icon_entry icon_moderated icon client-moderated") + .attr("title", _translations.AJW_7Ysi || (_translations.AJW_7Ysi = tr("Channel is moderated")))); + //Channel Icon (1) + container_icons.append($.spawn("div") + .addClass("show-channel-normal-only icon_entry channel_icon") + .attr("title", _translations.WQPwyWBa || (_translations.WQPwyWBa = tr("Channel icon")))); + //Default no sound (0) + let container = $.spawn("div") + .css("position", "relative") + .addClass("icon_no_sound"); + let noSound = $.spawn("div") + .addClass("icon_entry icon client-conflict-icon") + .attr("title", "You don't support the channel codec"); + let bg = $.spawn("div") + .width(10) + .height(14) + .css("background", "red") + .css("position", "absolute") + .css("top", "1px") + .css("left", "3px") + .css("z-index", "-1"); + bg.appendTo(container); + noSound.appendTo(container); + container_icons.append(container); + container_icons.appendTo(container_entry); + } + tag_channel.append(this._tag_channel = container_entry); + this.update_family_index(true); + } + { + const container_client = $.spawn("div").addClass("container-clients"); + tag_channel.append(this._tag_clients = container_client); + } + { + const container_children = $.spawn("div").addClass("container-children"); + tag_channel.append(this._tag_siblings = container_children); + } + /* + setInterval(() => { + let color = (Math.random() * 10000000).toString(16).substr(0, 6); + bg.css("background", "#" + color); + }, 150); + */ + this._tag_root = tag_channel; + } + rootTag() { + return this._tag_root; + } + channelTag() { + return this._tag_channel; + } + siblingTag() { + return this._tag_siblings; + } + clientTag() { + return this._tag_clients; + } + reorderClients() { + let clients = this.clients(); + if (clients.length > 1) { + clients.sort((a, b) => { + if (a.properties.client_talk_power < b.properties.client_talk_power) + return 1; + if (a.properties.client_talk_power > b.properties.client_talk_power) + return -1; + if (a.properties.client_nickname > b.properties.client_nickname) + return 1; + if (a.properties.client_nickname < b.properties.client_nickname) + return -1; + return 0; + }); + clients.reverse(); + for (let index = 0; index + 1 < clients.length; index++) + clients[index].tag.before(clients[index + 1].tag); + for (let client of clients) { + console.log("- %i %s", client.properties.client_talk_power, client.properties.client_nickname); + } + } + } + initializeListener() { + const _this = this; + this.channelTag().click(function () { + _this.channelTree.onSelect(_this); + }); + this.channelTag().dblclick(() => { + if ($.isArray(this.channelTree.currently_selected)) { //Multiselect + return; + } + this.joinChannel(); + }); + if (!settings.static(Settings.KEY_DISABLE_CONTEXT_MENU, false)) { + this.channelTag().on("contextmenu", (event) => { + event.preventDefault(); + if ($.isArray(this.channelTree.currently_selected)) { //Multiselect + (this.channelTree.currently_selected_context_callback || ((_) => null))(event); + return; + } + _this.channelTree.onSelect(_this, true); + _this.showContextMenu(event.pageX, event.pageY, () => { + _this.channelTree.onSelect(undefined, true); + }); + }); + } + } + showContextMenu(x, y, on_close = undefined) { + let channelCreate = this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_CREATE_TEMPORARY).granted(1) || + this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_CREATE_SEMI_PERMANENT).granted(1) || + this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_CREATE_PERMANENT).granted(1); + let channelModify = this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_MODIFY_MAKE_DEFAULT).granted(1) || + this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_MODIFY_MAKE_PERMANENT).granted(1) || + this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_MODIFY_MAKE_SEMI_PERMANENT).granted(1) || + this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_MODIFY_MAKE_TEMPORARY).granted(1) || + this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_MODIFY_NAME).granted(1) || + this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_MODIFY_TOPIC).granted(1) || + this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_MODIFY_DESCRIPTION).granted(1) || + this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_MODIFY_PASSWORD).granted(1) || + this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_MODIFY_CODEC).granted(1) || + this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_MODIFY_CODEC_QUALITY).granted(1) || + this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_MODIFY_CODEC_LATENCY_FACTOR).granted(1) || + this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_MODIFY_MAXCLIENTS).granted(1) || + this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_MODIFY_MAXFAMILYCLIENTS).granted(1) || + this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_MODIFY_SORTORDER).granted(1) || + this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_MODIFY_NEEDED_TALK_POWER).granted(1) || + this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_MODIFY_MAKE_CODEC_ENCRYPTED).granted(1) || + this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_MODIFY_TEMP_DELETE_DELAY).granted(1) || + this.channelTree.client.permissions.neededPermission(PermissionType.B_ICON_MANAGE).granted(1); + let flagDelete = true; + if (this.clients(true).length > 0) + flagDelete = this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_DELETE_FLAG_FORCE).granted(1); + if (flagDelete) { + if (this.properties.channel_flag_permanent) + flagDelete = this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_DELETE_PERMANENT).granted(1); + else if (this.properties.channel_flag_semi_permanent) + flagDelete = this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_DELETE_PERMANENT).granted(1); + else + flagDelete = this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_DELETE_TEMPORARY).granted(1); + } + spawn_context_menu(x, y, { + type: MenuEntryType.ENTRY, + icon: "client-channel_switch", + name: _translations.fYGIIiFf || (_translations.fYGIIiFf = tr("Switch to channel")), + callback: () => this.joinChannel() + }, MenuEntry.HR(), { + type: MenuEntryType.ENTRY, + icon: "client-channel_edit", + name: _translations.xjDLtc_W || (_translations.xjDLtc_W = tr("Edit channel")), + invalidPermission: !channelModify, + callback: () => { + Modals.createChannelModal(this, undefined, this.channelTree.client.permissions, (changes, permissions) => { + if (changes) { + changes["cid"] = this.channelId; + this.channelTree.client.serverConnection.send_command("channeledit", changes); + log.info(LogCategory.CHANNEL, _translations.fK8ljRBd || (_translations.fK8ljRBd = tr("Changed channel properties of channel %s: %o")), this.channelName(), changes); + } + if (permissions && permissions.length > 0) { + let perms = []; + for (let perm of permissions) { + perms.push({ + permvalue: perm.value, + permnegated: false, + permskip: false, + permid: perm.type.id + }); + } + perms[0]["cid"] = this.channelId; + this.channelTree.client.serverConnection.send_command("channeladdperm", perms, { + flagset: ["continueonerror"] + }).then(() => { + sound.play(Sound.CHANNEL_EDITED_SELF); + }); + } + }); + } + }, { + type: MenuEntryType.ENTRY, + icon: "client-channel_delete", + name: _translations.Yzzhr43h || (_translations.Yzzhr43h = tr("Delete channel")), + invalidPermission: !flagDelete, + callback: () => { + this.channelTree.client.serverConnection.send_command("channeldelete", { cid: this.channelId }).then(() => { + sound.play(Sound.CHANNEL_DELETED); + }); + } + }, MenuEntry.HR(), { + type: MenuEntryType.ENTRY, + icon: "client-addon-collection", + name: _translations.NCpTBV8E || (_translations.NCpTBV8E = tr("Create music bot")), + callback: () => { + this.channelTree.client.serverConnection.send_command("musicbotcreate", { cid: this.channelId }).then(() => { + createInfoModal(_translations.CAKzmQnK || (_translations.CAKzmQnK = tr("Bot successfully created")), _translations.Xy9l9iJX || (_translations.Xy9l9iJX = tr("Bot has been successfully created."))).open(); + }).catch(error => { + if (error instanceof CommandResult) { + error = error.extra_message || error.message; + } + createErrorModal(_translations.cW_P2hlA || (_translations.cW_P2hlA = tr("Failed to create bot")), MessageHelper.formatMessage(_translations.okfaF6u3 || (_translations.okfaF6u3 = tr("Failed to create the music bot:
{0}")), error)).open(); + }); + } + }, MenuEntry.HR(), { + type: MenuEntryType.ENTRY, + icon: "client-channel_create_sub", + name: _translations.vsYTC19a || (_translations.vsYTC19a = tr("Create sub channel")), + invalidPermission: !(channelCreate && this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_CREATE_CHILD).granted(1)), + callback: () => this.channelTree.spawnCreateChannel(this) + }, { + type: MenuEntryType.ENTRY, + icon: "client-channel_create", + name: _translations.INSAXHWq || (_translations.INSAXHWq = tr("Create channel")), + invalidPermission: !channelCreate, + callback: () => this.channelTree.spawnCreateChannel() + }, MenuEntry.CLOSE(on_close)); + } + handle_frame_resized() { + this.__updateChannelName(); + } + __updateChannelName() { + this._channel_name_formatted = undefined; + parseType: if (this.parent_channel() == null && this.properties.channel_name.charAt(0) == '[') { + let end = this.properties.channel_name.indexOf(']'); + if (end == -1) + break parseType; + let options = this.properties.channel_name.substr(1, end - 1); + if (options.indexOf("spacer") == -1) + break parseType; + options = options.substr(0, options.indexOf("spacer")); + console.log(_translations.F8DyGDHM || (_translations.F8DyGDHM = tr("Channel options: '%o'")), options); + if (options.length == 0) + options = "align-left"; + else if (options.length > 1) + options = options[0]; + switch (options) { + case "r": + this._channel_name_alignment = "align-right"; + break; + case "l": + this._channel_name_alignment = "align-left"; + break; + case "c": + this._channel_name_alignment = "align-center"; + break; + case "*": + this._channel_name_alignment = "align-repetitive"; + break; + default: + this._channel_name_alignment = undefined; + break parseType; + } + this._channel_name_formatted = this.properties.channel_name.substr(end + 1) || ""; + console.log(_translations.fTdJPDs3 || (_translations.fTdJPDs3 = tr("Got formated channel name: %o")), this._channel_name_formatted); + } + this._tag_channel.find(".show-channel-normal-only").toggleClass("channel-normal", this._channel_name_formatted === undefined); + const tag_container_name = this._tag_channel.find(".container-channel-name"); + tag_container_name.removeClass(ChannelEntry.NAME_ALIGNMENTS.join(" ")); + const tag_name = tag_container_name.find(".channel-name"); + tag_name.text(this._channel_name_formatted === undefined ? this.properties.channel_name : this._channel_name_formatted); + if (this._channel_name_formatted !== undefined) { + tag_container_name.addClass(this._channel_name_alignment); + if (this._channel_name_alignment == "align-repetitive") { + if (tag_name.parent().width() != 0) { + let lastSuccess = ""; + let index = 6; + let name = this._channel_name_formatted; + if (name.length < 1) + throw "invalid name!"; + while (index-- > 0) + name = name + name; + tag_name.text(name); + do { + tag_name.text(name = name + name); + if (name.length > 1024 * 8) + index = 63; + } while (tag_name.parent().width() >= tag_name.width() && ++index < 64); + if (index == 64) + console.warn(LogCategory.CHANNEL, _translations.g1tVT87U || (_translations.g1tVT87U = tr("Repeating spacer took too much repeats!"))); + if (lastSuccess.length > 0) { + tag_name.text(lastSuccess); + } + } + } + } + console.log(_translations.oU_VGnSx || (_translations.oU_VGnSx = tr("Align: %s")), this._channel_name_alignment); + } + recalculate_repetitive_name() { + if (this._channel_name_alignment == "align-repetitive") + this.__updateChannelName(); + } + updateVariables(...variables) { + let group = log.group(log.LogType.DEBUG, LogCategory.CHANNEL_PROPERTIES, _translations.bLb2uTaE || (_translations.bLb2uTaE = tr("Update properties (%i) of %s (%i)")), variables.length, this.channelName(), this.getChannelId()); + for (let variable of variables) { + let key = variable.key; + let value = variable.value; + JSON.map_field_to(this.properties, value, variable.key); + group.log(_translations.t4jDfLgx || (_translations.t4jDfLgx = tr("Updating property %s = '%s' -> %o")), key, value, this.properties[key]); + if (key == "channel_name") { + this.__updateChannelName(); + } + else if (key == "channel_order") { + let order = this.channelTree.findChannel(this.properties.channel_order); + this.channelTree.moveChannel(this, order, this.parent); + } + else if (key == "channel_icon_id") { + let tag = this.channelTag().find(".icons .channel_icon"); + (this.properties.channel_icon_id > 0 ? $.fn.show : $.fn.hide).apply(tag); + if (this.properties.channel_icon_id > 0) { + tag.children().detach(); + this.channelTree.client.fileManager.icons.generateTag(this.properties.channel_icon_id).appendTo(tag); + } + } + else if (key == "channel_codec") { + (this.properties.channel_codec == 5 || this.properties.channel_codec == 3 ? $.fn.show : $.fn.hide).apply(this.channelTag().find(".icons .icon_music")); + (this.channelTree.client.voiceConnection.codecSupported(this.properties.channel_codec) ? $.fn.hide : $.fn.show).apply(this.channelTag().find(".icons .icon_no_sound")); + } + else if (key == "channel_flag_default") { + (this.properties.channel_flag_default ? $.fn.show : $.fn.hide).apply(this.channelTag().find(".icons .icon_default")); + } + else if (key == "channel_flag_password") + (this.properties.channel_flag_password ? $.fn.show : $.fn.hide).apply(this.channelTag().find(".icons .icon_password")); + else if (key == "channel_needed_talk_power") + (this.properties.channel_needed_talk_power > 0 ? $.fn.show : $.fn.hide).apply(this.channelTag().find(".icons .icon_moderated")); + else if (key == "channel_description") { + this._cached_channel_description = undefined; + if (this._cached_channel_description_promise_resolve) + this._cached_channel_description_promise_resolve(value); + this._cached_channel_description_promise = undefined; + this._cached_channel_description_promise_resolve = undefined; + this._cached_channel_description_promise_reject = undefined; + } + if (key == "channel_maxclients" || key == "channel_maxfamilyclients" || key == "channel_flag_private" || key == "channel_flag_password") + this.updateChannelTypeIcon(); + } + group.end(); + } + updateChannelTypeIcon() { + let tag = this.channelTag().find(".channel-type"); + tag.removeAttr('class'); + tag.addClass("show-channel-normal-only channel-type icon"); + if (this._channel_name_formatted === undefined) + tag.addClass("channel-normal"); + let type; + if (this.properties.channel_flag_password == true && !this._cachedPassword) + type = "yellow"; + else if ((!this.properties.channel_flag_maxclients_unlimited && this.clients().length >= this.properties.channel_maxclients) || + (!this.properties.channel_flag_maxfamilyclients_unlimited && this.properties.channel_maxfamilyclients >= 0 && this.clients(true).length >= this.properties.channel_maxfamilyclients)) + type = "red"; + else + type = "green"; + tag.addClass("client-channel_" + type + "_subscribed"); + } + generate_bbcode() { + return "[url=channel://" + this.channelId + "/" + encodeURIComponent(this.properties.channel_name) + "]" + this.formattedChannelName() + "[/url]"; + } + generate_tag(braces = false) { + return $(htmltags.generate_channel({ + channel_name: this.properties.channel_name, + channel_id: this.channelId, + add_braces: braces + })); + } + channelType() { + if (this.properties.channel_flag_permanent == true) + return ChannelType.PERMANENT; + if (this.properties.channel_flag_semi_permanent == true) + return ChannelType.SEMI_PERMANENT; + return ChannelType.TEMPORARY; + } + joinChannel() { + if (this.properties.channel_flag_password == true && + !this._cachedPassword && + !this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_JOIN_IGNORE_PASSWORD).granted(1)) { + createInputModal(_translations.DbnOB3N5 || (_translations.DbnOB3N5 = tr("Channel password")), _translations.vKeWNwib || (_translations.vKeWNwib = tr("Channel password:")), () => true, text => { + if (typeof (text) == typeof (true)) + return; + helpers.hashPassword(text).then(result => { + this._cachedPassword = result; + this.joinChannel(); + this.updateChannelTypeIcon(); + }); + }).open(); + } + else if (this.channelTree.client.getClient().currentChannel() != this) + this.channelTree.client.getServerConnection().command_helper.joinChannel(this, this._cachedPassword).then(() => { + sound.play(Sound.CHANNEL_JOINED); + }).catch(error => { + if (error instanceof CommandResult) { + if (error.id == 781) { //Invalid password + this._cachedPassword = undefined; + this.updateChannelTypeIcon(); + } + } + }); + } +} +ChannelEntry.NAME_ALIGNMENTS = ["align-left", "align-center", "align-right", "align-repetitive"]; +//Global functions +function chat_channel_contextmenu(_element, event) { + event.preventDefault(); + let element = $(_element); + let chid = Number.parseInt(element.attr("channelId")); + let channel = globalClient.channelTree.findChannel(chid); + if (!channel) { + //TODO + return; + } + channel.showContextMenu(event.pageX, event.pageY); +} +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["fe89711a43b24f07f1aeaf001e66406e4c8ea4bc71ed5c5f1cac1bda261407b6"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["fe89711a43b24f07f1aeaf001e66406e4c8ea4bc71ed5c5f1cac1bda261407b6"] = "fe89711a43b24f07f1aeaf001e66406e4c8ea4bc71ed5c5f1cac1bda261407b6"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "ZLhA9e2l", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalChangeVolume.ts (10,29)" }, { name: "x8QJcf2k", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalChangeVolume.ts (31,34)" }, { name: "qQQ55JPY", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalChangeVolume.ts (39,35)" }, { name: "RvdOD61Y", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalChangeVolume.ts (48,31)" }, { name: "as7HKx_Z", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalChangeVolume.ts (77,29)" }, { name: "i4uIKqph", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalChangeVolume.ts (98,39)" }, { name: "bIx1IofH", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalChangeVolume.ts (107,39)" }, { name: "n5WtCyPz", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalChangeVolume.ts (115,40)" }, { name: "r4iXq8Au", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalChangeVolume.ts (123,36)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +/// +/// +var Modals; +(function (Modals) { + function spawnChangeVolume(current, callback) { + let updateCallback; + const connectModal = createModal({ + header: function () { + let header = $.spawn("div"); + header.text(_translations.ZLhA9e2l || (_translations.ZLhA9e2l = tr("Change volume"))); + return header; + }, + body: function () { + let tag = $("#tmpl_change_volume").renderTag({ + max_volume: 200 + }); + tag.find(".volume_slider").on("change", _ => updateCallback(tag.find(".volume_slider").val())); + tag.find(".volume_slider").on("input", _ => updateCallback(tag.find(".volume_slider").val())); + //connect_address + return tag; + }, + footer: function () { + let tag = $.spawn("div"); + tag.css("text-align", "right"); + tag.css("margin-top", "3px"); + tag.css("margin-bottom", "6px"); + tag.addClass("modal-button-group"); + let buttonReset = $.spawn("button"); + buttonReset.text(_translations.x8QJcf2k || (_translations.x8QJcf2k = tr("Reset"))); + buttonReset.on("click", function () { + updateCallback(100); + }); + tag.append(buttonReset); + let buttonCancel = $.spawn("button"); + buttonCancel.text(_translations.qQQ55JPY || (_translations.qQQ55JPY = tr("Cancel"))); + buttonCancel.on("click", function () { + updateCallback(current * 100); + connectModal.close(); + }); + tag.append(buttonCancel); + let buttonOk = $.spawn("button"); + buttonOk.text(_translations.RvdOD61Y || (_translations.RvdOD61Y = tr("OK"))); + buttonOk.on("click", function () { + connectModal.close(); + }); + tag.append(buttonOk); + return tag; + }, + width: 600 + }); + updateCallback = value => { + connectModal.htmlTag.find(".volume_slider").val(value); + let display = connectModal.htmlTag.find(".display_volume"); + let number = (value - 100); + display.html((number == 0 ? "±" : number > 0 ? "+" : "") + number + " %"); + callback(value / 100); + }; + connectModal.open(); + updateCallback(current * 100); + } + Modals.spawnChangeVolume = spawnChangeVolume; + /* Units are between 0 and 1 */ + function spawnChangeRemoteVolume(current, max_value, callback) { + let update_volume; + let current_value = current; /* between 0 and 100! */ + const modal = createModal({ + header: function () { + let header = $.spawn("div"); + header.text(_translations.as7HKx_Z || (_translations.as7HKx_Z = tr("Change volume"))); + return header; + }, + body: function () { + let tag = $("#tmpl_change_volume").renderTag({ + max_volume: Math.ceil(max_value * 100) + }); + tag.find(".volume_slider").on("change", _ => update_volume(tag.find(".volume_slider").val())); + tag.find(".volume_slider").on("input", _ => update_volume(tag.find(".volume_slider").val())); + //connect_address + return tag; + }, + footer: function () { + let tag = $.spawn("div"); + tag.css("text-align", "right"); + tag.css("margin-top", "3px"); + tag.css("margin-bottom", "6px"); + tag.addClass("modal-button-group"); + { + let button_apply = $.spawn("button"); + button_apply.text(_translations.i4uIKqph || (_translations.i4uIKqph = tr("Apply"))); + button_apply.on("click", () => { + callback(current_value / 100); + }); + tag.append(button_apply); + } + { + let button_reset = $.spawn("button"); + button_reset.text(_translations.bIx1IofH || (_translations.bIx1IofH = tr("Reset"))); + button_reset.on("click", () => update_volume(max_value * 100)); + tag.append(button_reset); + } + { + let button_cancel = $.spawn("button"); + button_cancel.text(_translations.n5WtCyPz || (_translations.n5WtCyPz = tr("Cancel"))); + button_cancel.on("click", () => modal.close()); + tag.append(button_cancel); + } + { + let button_ok = $.spawn("button"); + button_ok.text(_translations.r4iXq8Au || (_translations.r4iXq8Au = tr("OK"))); + button_ok.on("click", () => { + callback(current_value / 100); + modal.close(); + }); + tag.append(button_ok); + } + return tag; + }, + width: 600 + }); + update_volume = value => { + modal.htmlTag.find(".volume_slider").val(value); + const tag_display = modal.htmlTag.find(".display_volume"); + tag_display.html(value + " %"); + current_value = value; + }; + modal.open(); + update_volume(current * 100); + } + Modals.spawnChangeRemoteVolume = spawnChangeRemoteVolume; +})(Modals || (Modals = {})); +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["708d45d2c158bc747ff051fa9488db664d0024c6f66c07320691939b63b78f77"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["708d45d2c158bc747ff051fa9488db664d0024c6f66c07320691939b63b78f77"] = "708d45d2c158bc747ff051fa9488db664d0024c6f66c07320691939b63b78f77"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "Tdn9l0kj", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalServerGroupDialog.ts (4,21)" }, { name: "nfIjkcVs", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalServerGroupDialog.ts (31,42)" }, { name: "b3pPvY46", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalServerGroupDialog.ts (48,35)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +var Modals; +(function (Modals) { + function createServerGroupAssignmentModal(client, callback) { + const modal = createModal({ + header: _translations.Tdn9l0kj || (_translations.Tdn9l0kj = tr("Server Groups")), + body: () => { + let tag = {}; + let groups = tag["groups"] = []; + tag["client_name"] = client.clientNickName(); + for (let group of client.channelTree.client.groups.serverGroups.sort(GroupManager.sorter())) { + if (group.type != GroupType.NORMAL) + continue; + let entry = {}; + entry["id"] = group.id; + entry["name"] = group.name; + entry["assigned"] = client.groupAssigned(group); + entry["disabled"] = !client.channelTree.client.permissions.neededPermission(PermissionType.I_GROUP_MEMBER_ADD_POWER).granted(group.requiredMemberRemovePower); + tag["icon_" + group.id] = client.channelTree.client.fileManager.icons.generateTag(group.properties.iconid); + groups.push(entry); + } + let template = $("#tmpl_server_group_assignment").renderTag(tag); + template.find(".group-entry input").each((_idx, _entry) => { + let entry = $(_entry); + entry.on('change', event => { + let group_id = parseInt(entry.attr("group-id")); + let group = client.channelTree.client.groups.serverGroup(group_id); + if (!group) { + console.warn(_translations.nfIjkcVs || (_translations.nfIjkcVs = tr("Could not resolve target group!"))); + return false; + } + let target = entry.prop("checked"); + callback(group, target).then(flag => flag ? Promise.resolve() : Promise.reject()).catch(error => entry.prop("checked", !target)); + }); + }); + return template; + }, + footer: () => { + let footer = $.spawn("div"); + footer.addClass("modal-button-group"); + footer.css("margin", "5px"); + let button_close = $.spawn("button"); + button_close.text(_translations.b3pPvY46 || (_translations.b3pPvY46 = tr("Close"))).addClass("button_close"); + footer.append(button_close); + return footer; + }, + width: "max-content" + }); + modal.htmlTag.find(".button_close").click(() => { + modal.close(); + }); + modal.open(); + } + Modals.createServerGroupAssignmentModal = createServerGroupAssignmentModal; +})(Modals || (Modals = {})); +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["ed30afb7068cb78a1fff26ad87178b5052f672ac142bb4d11f9311f059d1ee5f"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["ed30afb7068cb78a1fff26ad87178b5052f672ac142bb4d11f9311f059d1ee5f"] = "ed30afb7068cb78a1fff26ad87178b5052f672ac142bb4d11f9311f059d1ee5f"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "B5ot5_mB", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client_move.ts (48,21)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +/// +class ClientMover { + constructor(tree) { + this._active = false; + this.origin_point = undefined; + this.channel_tree = tree; + } + is_active() { return this._active; } + hover_text() { + if ($.isArray(this.selected_client)) { + return this.selected_client.filter(client => !!client).map(client => client.clientNickName()).join(", "); + } + else if (this.selected_client) { + return this.selected_client.clientNickName(); + } + else + return ""; + } + bbcode_text() { + if ($.isArray(this.selected_client)) { + return this.selected_client.filter(client => !!client).map(client => client.create_bbcode()).join(", "); + } + else if (this.selected_client) { + return this.selected_client.create_bbcode(); + } + else + return ""; + } + activate(client, callback, event) { + this.finish_listener(undefined); + this.selected_client = client; + this.callback = callback; + console.log(_translations.B5ot5_mB || (_translations.B5ot5_mB = tr("Starting mouse move"))); + ClientMover.listener_root.on('mouseup', this._bound_finish = this.finish_listener.bind(this)).on('mousemove', this._bound_move = this.move_listener.bind(this)); + { + const content = ClientMover.move_element.find(".container"); + content.empty(); + content.append($.spawn("a").text(this.hover_text())); + } + this.move_listener(event); + } + move_listener(event) { + //console.log("Mouse move: " + event.pageX + " - " + event.pageY); + if (!event.pageX || !event.pageY) + return; + if (!this.origin_point) + this.origin_point = { x: event.pageX, y: event.pageY }; + ClientMover.move_element.css({ + "top": (event.pageY - 1) + "px", + "left": (event.pageX + 10) + "px" + }); + if (!this._active) { + const d_x = this.origin_point.x - event.pageX; + const d_y = this.origin_point.y - event.pageY; + this._active = Math.sqrt(d_x * d_x + d_y * d_y) > 5 * 5; + if (this._active) { + if ($.isArray(this.selected_client)) { + this.channel_tree.onSelect(this.selected_client[0], true); + for (const client of this.selected_client.slice(1)) + this.channel_tree.onSelect(client, false, true); + } + else { + this.channel_tree.onSelect(this.selected_client, true); + } + ClientMover.move_element.show(); + } + } + const elements = document.elementsFromPoint(event.pageX, event.pageY); + while (elements.length > 0) { + if (elements[0].classList.contains("container-channel")) + break; + elements.pop_front(); + } + if (this.hovered_channel) { + this.hovered_channel.classList.remove("move-selected"); + this.hovered_channel = undefined; + } + if (elements.length > 0) { + elements[0].classList.add("move-selected"); + this.hovered_channel = elements[0]; + } + } + finish_listener(event) { + ClientMover.move_element.hide(); + const channel_id = this.hovered_channel ? parseInt(this.hovered_channel.getAttribute("channel-id")) : 0; + ClientMover.listener_root.unbind('mouseleave', this._bound_finish); + ClientMover.listener_root.unbind('mouseup', this._bound_finish); + ClientMover.listener_root.unbind('mousemove', this._bound_move); + if (this.hovered_channel) { + this.hovered_channel.classList.remove("move-selected"); + this.hovered_channel = undefined; + } + this.origin_point = undefined; + if (!this._active) { + this.selected_client = undefined; + this.callback = undefined; + return; + } + this._active = false; + if (this.callback) { + if (!channel_id) + this.callback(undefined); + else { + this.callback(this.channel_tree.findChannel(channel_id)); + } + this.callback = undefined; + } + /* test for the chat box */ + { + const elements = document.elementsFromPoint(event.pageX, event.pageY); + console.error(elements); + while (elements.length > 0) { + if (elements[0].classList.contains("client-chat-box-field")) + break; + elements.pop_front(); + } + if (elements.length > 0) { + const element = $(elements[0]); + element.val((element.val() || "") + this.bbcode_text()); + } + } + } + deactivate() { + this.callback = undefined; + this.finish_listener(undefined); + } +} +ClientMover.listener_root = $(document); +ClientMover.move_element = $("#mouse-move"); +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["9d81e62fbece35b2c7f7202b89538496b5c2c217088adc7b87fb08d71561a99c"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["9d81e62fbece35b2c7f7202b89538496b5c2c217088adc7b87fb08d71561a99c"] = "9d81e62fbece35b2c7f7202b89538496b5c2c217088adc7b87fb08d71561a99c"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "wzuKK0mB", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (228,19)" }, { name: "KUowCgCL", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (255,19)" }, { name: "Jxeh4FBs", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (262,19)" }, { name: "BDDek24b", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (275,23)" }, { name: "HJvmO6Yv", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (283,23)" }, { name: "BuvvoxPa", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (285,38)" }, { name: "z8B9Jr_b", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (285,57)" }, { name: "tQTaM2vV", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (300,23)" }, { name: "yKzAGCKN", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (302,38)" }, { name: "Q1CApngv", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (302,71)" }, { name: "lA_9fifG", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (320,23)" }, { name: "sMx2dF57", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (330,23)" }, { name: "ZTYB4b5C", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (332,38)" }, { name: "XFG3swM3", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (332,70)" }, { name: "LZ87Hyos", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (348,23)" }, { name: "WObQGUNP", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (350,38)" }, { name: "p1vJZOOJ", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (350,69)" }, { name: "IxNwAB6Z", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (366,23)" }, { name: "uhdldy7w", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (404,23)" }, { name: "IcO_rO5a", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (565,70)" }, { name: "nZsgZjvq", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (790,23)" }, { name: "luXlxqAz", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (795,23)" }, { name: "L3eN3w7x", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (798,38)" }, { name: "pJm9WNWU", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (798,68)" }, { name: "huKXae1n", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (800,41)" }, { name: "LUgGlgDn", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (858,49)" }, { name: "erjjkAEe", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (860,47)" }, { name: "yOofHBYZ", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (913,23)" }, { name: "Ib4e7gF0", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (917,38)" }, { name: "IW3obMAX", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (917,72)" }, { name: "QEBR_LaZ", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (929,23)" }, { name: "C8pFnqhh", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (933,38)" }, { name: "AEH0aFoC", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (933,75)" }, { name: "NFoAqO50", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (955,23)" }, { name: "hi3i15FD", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (966,42)" }, { name: "aEP95pp4", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (966,69)" }, { name: "Em4GmMYf", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (968,42)" }, { name: "HjT6bOoT", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (968,75)" }, { name: "BUWjmbJD", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (974,23)" }, { name: "u0N7Wpfv", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (978,38)" }, { name: "isk4PsRv", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (978,66)" }, { name: "E4YHyYIB", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (989,50)" }, { name: "DNOAqnou", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (1001,23)" }, { name: "mtkKxwaH", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (1011,23)" }, { name: "envwWmFs", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (1013,38)" }, { name: "mfkXcBbD", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (1013,70)" }, { name: "N8PkkYgk", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (1015,41)" }, { name: "a83GPSuP", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (1029,23)" }, { name: "vU0_4DbG", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (1042,23)" }, { name: "ReawvrYk", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (1061,23)" }, { name: "Iilzvtrs", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (1065,83)" }, { name: "GzAtMa7f", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/client.ts (1066,39)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +/// +/// +/// +/// +var ClientType; +(function (ClientType) { + ClientType[ClientType["CLIENT_VOICE"] = 0] = "CLIENT_VOICE"; + ClientType[ClientType["CLIENT_QUERY"] = 1] = "CLIENT_QUERY"; + ClientType[ClientType["CLIENT_INTERNAL"] = 2] = "CLIENT_INTERNAL"; + ClientType[ClientType["CLIENT_WEB"] = 3] = "CLIENT_WEB"; + ClientType[ClientType["CLIENT_MUSIC"] = 4] = "CLIENT_MUSIC"; + ClientType[ClientType["CLIENT_UNDEFINED"] = 5] = "CLIENT_UNDEFINED"; +})(ClientType || (ClientType = {})); +class ClientProperties { + constructor() { + this.client_type = ClientType.CLIENT_VOICE; //TeamSpeaks type + this.client_type_exact = ClientType.CLIENT_VOICE; + this.client_database_id = 0; + this.client_version = ""; + this.client_platform = ""; + this.client_nickname = "unknown"; + this.client_unique_identifier = "unknown"; + this.client_description = ""; + this.client_servergroups = ""; + this.client_channel_group_id = 0; + this.client_lastconnected = 0; + this.client_flag_avatar = ""; + this.client_icon_id = 0; + this.client_away_message = ""; + this.client_away = false; + this.client_input_hardware = false; + this.client_output_hardware = false; + this.client_input_muted = false; + this.client_output_muted = false; + this.client_is_channel_commander = false; + this.client_teaforum_id = 0; + this.client_teaforum_name = ""; + this.client_talk_power = 0; + } +} +class ClientEntry { + constructor(clientId, clientName, properties = new ClientProperties()) { + this.lastVariableUpdate = 0; + this._speaking = false; + this._properties = properties; + this._properties.client_nickname = clientName; + this._clientId = clientId; + this.channelTree = null; + this._channel = null; + this.audioController = new AudioController(); + const _this = this; + this.audioController.onSpeaking = function () { + _this.speaking = true; + }; + this.audioController.onSilence = function () { + _this.speaking = false; + }; + this.audioController.initialize(); + } + get properties() { + return this._properties; + } + currentChannel() { return this._channel; } + clientNickName() { return this.properties.client_nickname; } + clientUid() { return this.properties.client_unique_identifier; } + clientId() { return this._clientId; } + getAudioController() { + return this.audioController; + } + initializeListener() { + if (this._listener_initialized) + return; + this._listener_initialized = true; + this.tag.on('mouseup', event => { + if (!this.channelTree.client_mover.is_active()) { + this.channelTree.onSelect(this); + } + }); + this.tag.click(event => { + console.log("Clicked!"); + }); + if (!(this instanceof LocalClientEntry) && !(this instanceof MusicClientEntry)) + this.tag.dblclick(event => { + if ($.isArray(this.channelTree.currently_selected)) { //Multiselect + return; + } + this.chat(true).focus(); + }); + if (!settings.static(Settings.KEY_DISABLE_CONTEXT_MENU, false)) { + this.tag.on("contextmenu", (event) => { + event.preventDefault(); + if ($.isArray(this.channelTree.currently_selected)) { //Multiselect + (this.channelTree.currently_selected_context_callback || ((_) => null))(event); + return; + } + this.channelTree.onSelect(this, true); + this.showContextMenu(event.pageX, event.pageY, () => { }); + return false; + }); + } + this.tag.mousedown(event => { + if (event.which != 1) + return; //Only the left button + let clients = this.channelTree.currently_selected; + if (ppt.key_pressed(ppt.SpecialKey.SHIFT)) { + if (clients != this && !($.isArray(clients) && clients.indexOf(this) != -1)) + clients = $.isArray(clients) ? [...clients, this] : [clients, this]; + } + else { + clients = this; + } + this.channelTree.client_mover.activate(clients, target => { + if (!target) + return; + for (const client of $.isArray(clients) ? clients : [clients]) { + if (target == client._channel) + continue; + const source = client._channel; + const self = this.channelTree.client.getClient(); + this.channelTree.client.serverConnection.send_command("clientmove", { + clid: client.clientId(), + cid: target.getChannelId() + }).then(event => { + if (client.clientId() == this.channelTree.client.clientId) + sound.play(Sound.CHANNEL_JOINED); + else if (target !== source && target != self.currentChannel()) + sound.play(Sound.USER_MOVED); + }); + } + this.channelTree.onSelect(); + }, event); + }); + } + assignment_context() { + let server_groups = []; + for (let group of this.channelTree.client.groups.serverGroups.sort(GroupManager.sorter())) { + if (group.type != GroupType.NORMAL) + continue; + let entry = {}; + { + let tag = $.spawn("label").addClass("checkbox"); + $.spawn("input").attr("type", "checkbox").prop("checked", this.groupAssigned(group)).appendTo(tag); + $.spawn("span").addClass("checkmark").appendTo(tag); + entry.icon = tag; + } + entry.name = group.name + " [" + (group.properties.savedb ? "perm" : "tmp") + "]"; + if (this.groupAssigned(group)) { + entry.callback = () => { + this.channelTree.client.serverConnection.send_command("servergroupdelclient", { + sgid: group.id, + cldbid: this.properties.client_database_id + }); + }; + entry.disabled = !this.channelTree.client.permissions.neededPermission(PermissionType.I_GROUP_MEMBER_ADD_POWER).granted(group.requiredMemberRemovePower); + } + else { + entry.callback = () => { + this.channelTree.client.serverConnection.send_command("servergroupaddclient", { + sgid: group.id, + cldbid: this.properties.client_database_id + }); + }; + entry.disabled = !this.channelTree.client.permissions.neededPermission(PermissionType.I_GROUP_MEMBER_REMOVE_POWER).granted(group.requiredMemberAddPower); + } + entry.type = MenuEntryType.ENTRY; + server_groups.push(entry); + } + let channel_groups = []; + for (let group of this.channelTree.client.groups.channelGroups.sort(GroupManager.sorter())) { + if (group.type != GroupType.NORMAL) + continue; + let entry = {}; + { + let tag = $.spawn("label").addClass("checkbox"); + $.spawn("input").attr("type", "checkbox").prop("checked", this.assignedChannelGroup() == group.id).appendTo(tag); + $.spawn("span").addClass("checkmark").appendTo(tag); + entry.icon = tag; + } + entry.name = group.name + " [" + (group.properties.savedb ? "perm" : "tmp") + "]"; + entry.callback = () => { + this.channelTree.client.serverConnection.send_command("setclientchannelgroup", { + cldbid: this.properties.client_database_id, + cgid: group.id, + cid: this.currentChannel().channelId + }); + }; + entry.disabled = !this.channelTree.client.permissions.neededPermission(PermissionType.I_GROUP_MEMBER_ADD_POWER).granted(group.requiredMemberRemovePower); + entry.type = MenuEntryType.ENTRY; + channel_groups.push(entry); + } + return [{ + type: MenuEntryType.SUB_MENU, + icon: "client-permission_server_groups", + name: _translations.wzuKK0mB || (_translations.wzuKK0mB = tr("Set server group")), + sub_menu: [ + { + type: MenuEntryType.ENTRY, + icon: "client-permission_server_groups", + name: "Server groups dialog", + callback: () => { + Modals.createServerGroupAssignmentModal(this, (group, flag) => { + if (flag) { + return this.channelTree.client.serverConnection.send_command("servergroupaddclient", { + sgid: group.id, + cldbid: this.properties.client_database_id + }).then(result => true); + } + else + return this.channelTree.client.serverConnection.send_command("servergroupdelclient", { + sgid: group.id, + cldbid: this.properties.client_database_id + }).then(result => true); + }); + } + }, + MenuEntry.HR(), + ...server_groups + ] + }, { + type: MenuEntryType.SUB_MENU, + icon: "client-permission_channel", + name: _translations.KUowCgCL || (_translations.KUowCgCL = tr("Set channel group")), + sub_menu: [ + ...channel_groups + ] + }, { + type: MenuEntryType.SUB_MENU, + icon: "client-permission_client", + name: _translations.Jxeh4FBs || (_translations.Jxeh4FBs = tr("Permissions")), + disabled: true, + sub_menu: [] + }]; + } + showContextMenu(x, y, on_close = undefined) { + const _this = this; + spawn_context_menu(x, y, { + type: MenuEntryType.ENTRY, + icon: "client-change_nickname", + name: _translations.BDDek24b || (_translations.BDDek24b = tr("Open text chat")), + callback: function () { + chat.activeChat = _this.chat(true); + chat.focus(); + } + }, { + type: MenuEntryType.ENTRY, + icon: "client-poke", + name: _translations.HJvmO6Yv || (_translations.HJvmO6Yv = tr("Poke client")), + callback: function () { + createInputModal(_translations.BuvvoxPa || (_translations.BuvvoxPa = tr("Poke client")), _translations.z8B9Jr_b || (_translations.z8B9Jr_b = tr("Poke message:
")), text => true, result => { + if (typeof (result) === "string") { + //TODO tr + console.log("Poking client " + _this.clientNickName() + " with message " + result); + _this.channelTree.client.serverConnection.send_command("clientpoke", { + clid: _this.clientId(), + msg: result + }); + } + }, { width: 400, maxLength: 512 }).open(); + } + }, { + type: MenuEntryType.ENTRY, + icon: "client-edit", + name: _translations.tQTaM2vV || (_translations.tQTaM2vV = tr("Change description")), + callback: function () { + createInputModal(_translations.yKzAGCKN || (_translations.yKzAGCKN = tr("Change client description")), _translations.Q1CApngv || (_translations.Q1CApngv = tr("New description:
")), text => true, result => { + if (typeof (result) === "string") { + //TODO tr + console.log("Changing " + _this.clientNickName() + "'s description to " + result); + _this.channelTree.client.serverConnection.send_command("clientedit", { + clid: _this.clientId(), + client_description: result + }); + } + }, { width: 400, maxLength: 1024 }).open(); + } + }, MenuEntry.HR(), ...this.assignment_context(), MenuEntry.HR(), { + type: MenuEntryType.ENTRY, + icon: "client-move_client_to_own_channel", + name: _translations.lA_9fifG || (_translations.lA_9fifG = tr("Move client to your channel")), + callback: () => { + this.channelTree.client.serverConnection.send_command("clientmove", { + clid: this.clientId(), + cid: this.channelTree.client.getClient().currentChannel().getChannelId() + }); + } + }, { + type: MenuEntryType.ENTRY, + icon: "client-kick_channel", + name: _translations.sMx2dF57 || (_translations.sMx2dF57 = tr("Kick client from channel")), + callback: () => { + createInputModal(_translations.ZTYB4b5C || (_translations.ZTYB4b5C = tr("Kick client from channel")), _translations.XFG3swM3 || (_translations.XFG3swM3 = tr("Kick reason:
")), text => true, result => { + if (result) { + //TODO tr + console.log("Kicking client " + _this.clientNickName() + " from channel with reason " + result); + _this.channelTree.client.serverConnection.send_command("clientkick", { + clid: _this.clientId(), + reasonid: ViewReasonId.VREASON_CHANNEL_KICK, + reasonmsg: result + }); + } + }, { width: 400, maxLength: 255 }).open(); + } + }, { + type: MenuEntryType.ENTRY, + icon: "client-kick_server", + name: _translations.LZ87Hyos || (_translations.LZ87Hyos = tr("Kick client fom server")), + callback: () => { + createInputModal(_translations.WObQGUNP || (_translations.WObQGUNP = tr("Kick client from server")), _translations.p1vJZOOJ || (_translations.p1vJZOOJ = tr("Kick reason:
")), text => true, result => { + if (result) { + //TODO tr + console.log("Kicking client " + _this.clientNickName() + " from server with reason " + result); + _this.channelTree.client.serverConnection.send_command("clientkick", { + clid: _this.clientId(), + reasonid: ViewReasonId.VREASON_SERVER_KICK, + reasonmsg: result + }); + } + }, { width: 400, maxLength: 255 }).open(); + } + }, { + type: MenuEntryType.ENTRY, + icon: "client-ban_client", + name: _translations.IxNwAB6Z || (_translations.IxNwAB6Z = tr("Ban client")), + invalidPermission: !this.channelTree.client.permissions.neededPermission(PermissionType.I_CLIENT_BAN_MAX_BANTIME).granted(1), + callback: () => { + Modals.spawnBanClient(this.properties.client_nickname, (data) => { + this.channelTree.client.serverConnection.send_command("banclient", { + uid: this.properties.client_unique_identifier, + banreason: data.reason, + time: data.length + }, { + flagset: [data.no_ip ? "no-ip" : "", data.no_hwid ? "no-hardware-id" : "", data.no_name ? "no-nickname" : ""] + }).then(() => { + sound.play(Sound.USER_BANNED); + }); + }); + } + }, MenuEntry.HR(), + /* + { + type: MenuEntryType.ENTRY, + icon: "client-kick_server", + name: "Add group to client", + invalidPermission: true, //!this.channelTree.client.permissions.neededPermission(PermissionType.I_CLIENT_BAN_MAX_BANTIME).granted(1), + callback: () => { + Modals.spawnBanClient(this.properties.client_nickname, (duration, reason) => { + this.channelTree.client.serverConnection.send_command("banclient", { + uid: this.properties.client_unique_identifier, + banreason: reason, + time: duration + }); + }); + } + }, + MenuEntry.HR(), + */ + { + type: MenuEntryType.ENTRY, + icon: "client-volume", + name: _translations.uhdldy7w || (_translations.uhdldy7w = tr("Change Volume")), + callback: () => { + Modals.spawnChangeVolume(this.audioController.volume, volume => { + settings.changeServer("volume_client_" + this.clientUid(), volume); + this.audioController.volume = volume; + if (globalClient.selectInfo.currentSelected == this) + globalClient.selectInfo.update(); + }); + } + }, MenuEntry.CLOSE(on_close)); + } + get tag() { + if (this._tag) + return this._tag; + let container_client = $.spawn("div") + .addClass("tree-entry client") + .attr("client-id", this.clientId()); + container_client.append($.spawn("div") + .addClass("icon_client_state") + .attr("title", "Client state")); + container_client.append($.spawn("div") + .addClass("group-prefix") + .attr("title", "Server groups prefixes") + .hide()); + container_client.append($.spawn("div") + .addClass("client-name") + .text(this.clientNickName())); + container_client.append($.spawn("div") + .addClass("group-suffix") + .attr("title", "Server groups suffix") + .hide()); + container_client.append($.spawn("div") + .addClass("client-away-message") + .text(this.clientNickName())); + let container_icons = $.spawn("div").addClass("container-icons"); + container_icons.append($.spawn("div") + .addClass("icon icon_talk_power client-input_muted") + .hide()); + container_icons.append($.spawn("div") + .addClass("container-icons-group")); + container_icons.append($.spawn("div") + .addClass("container-icon-client")); + container_client.append(container_icons); + this._tag = container_client; + this.initializeListener(); + return this._tag; + } + static bbcodeTag(id, name, uid) { + return "[url=client://" + id + "/" + uid + "~" + encodeURIComponent(name) + "]" + name + "[/url]"; + } + static chatTag(id, name, uid, braces = false) { + return $(htmltags.generate_client({ + client_name: name, + client_id: id, + client_unique_id: uid, + add_braces: braces + })); + } + create_bbcode() { + return ClientEntry.bbcodeTag(this.clientId(), this.clientNickName(), this.clientUid()); + } + createChatTag(braces = false) { + return ClientEntry.chatTag(this.clientId(), this.clientNickName(), this.clientUid(), braces); + } + set speaking(flag) { + if (flag == this._speaking) + return; + this._speaking = flag; + this.updateClientSpeakIcon(); + } + updateClientStatusIcons() { + let talk_power = this.properties.client_talk_power >= this._channel.properties.channel_needed_talk_power; + if (talk_power) + this.tag.find(".icon_talk_power").hide(); + else + this.tag.find(".icon_talk_power").show(); + } + updateClientSpeakIcon() { + let icon = ""; + let clicon = ""; + if (this.properties.client_type_exact == ClientType.CLIENT_QUERY) { + icon = "client-server_query"; + console.log("Server query!"); + } + else { + if (this.properties.client_away) { + icon = "client-away"; + } + else if (!this.properties.client_output_hardware) { + icon = "client-hardware_output_muted"; + } + else if (this.properties.client_output_muted) { + icon = "client-output_muted"; + } + else if (!this.properties.client_input_hardware) { + icon = "client-hardware_input_muted"; + } + else if (this.properties.client_input_muted) { + icon = "client-input_muted"; + } + else { + if (this._speaking) { + if (this.properties.client_is_channel_commander) + clicon = "client_cc_talk"; + else + clicon = "client_talk"; + } + else { + if (this.properties.client_is_channel_commander) + clicon = "client_cc_idle"; + else + clicon = "client_idle"; + } + } + } + if (clicon.length > 0) + this.tag.find(".icon_client_state").attr('class', 'icon_client_state clicon ' + clicon); + else if (icon.length > 0) + this.tag.find(".icon_client_state").attr('class', 'icon_client_state icon ' + icon); + else + this.tag.find(".icon_client_state").attr('class', 'icon_client_state icon_empty'); + } + updateAwayMessage() { + let tag = this.tag.find(".client-away-message"); + if (this.properties.client_away == true && this.properties.client_away_message) { + tag.text("[" + this.properties.client_away_message + "]"); + tag.show(); + } + else { + tag.hide(); + } + } + updateVariables(...variables) { + let group = log.group(log.LogType.DEBUG, LogCategory.CLIENT, _translations.IcO_rO5a || (_translations.IcO_rO5a = tr("Update properties (%i) of %s (%i)")), variables.length, this.clientNickName(), this.clientId()); + let update_icon_status = false; + let update_icon_speech = false; + let update_away = false; + let reorder_channel = false; + for (let variable of variables) { + JSON.map_field_to(this._properties, variable.value, variable.key); + //TODO tr + group.log("Updating client " + this.clientId() + ". Key " + variable.key + " Value: '" + variable.value + "' (" + typeof (this.properties[variable.key]) + ")"); + if (variable.key == "client_nickname") { + this.tag.find(".client-name").text(variable.value); + let chat = this.chat(false); + if (chat) + chat.name = variable.value; + reorder_channel = true; + } + if (variable.key == "client_away" || variable.key == "client_output_muted" || variable.key == "client_input_hardware" || variable.key == "client_input_muted" || variable.key == "client_is_channel_commander") { + update_icon_speech = true; + } + if (variable.key == "client_away_message" || variable.key == "client_away") { + update_away = true; + } + if (variable.key == "client_unique_identifier") { + this.audioController.volume = parseFloat(settings.server("volume_client_" + this.clientUid(), "1")); + //TODO tr + console.error("Updated volume from config " + this.audioController.volume + " - " + "volume_client_" + this.clientUid() + " - " + settings.server("volume_client_" + this.clientUid(), "1")); + console.log(this.avatarId()); + } + if (variable.key == "client_talk_power") { + reorder_channel = true; + update_icon_status = true; + } + if (variable.key == "client_icon_id") + this.updateClientIcon(); + if (variable.key == "client_channel_group_id" || variable.key == "client_servergroups") + this.update_displayed_client_groups(); + } + /* process updates after variables have been set */ + if (this._channel && reorder_channel) + this._channel.reorderClients(); + if (update_icon_speech) + this.updateClientSpeakIcon(); + if (update_icon_status) + this.updateClientStatusIcons(); + if (update_away) + this.updateAwayMessage(); + group.end(); + } + update_displayed_client_groups() { + this.tag.find(".container-icons-group").children().detach(); + for (let id of this.assignedServerGroupIds()) + this.updateGroupIcon(this.channelTree.client.groups.serverGroup(id)); + this.updateGroupIcon(this.channelTree.client.groups.channelGroup(this.properties.client_channel_group_id)); + let prefix_groups = []; + let suffix_groups = []; + for (const group_id of this.assignedServerGroupIds()) { + const group = this.channelTree.client.groups.serverGroup(group_id); + if (!group) + continue; + if (group.properties.namemode == 1) + prefix_groups.push(group.name); + else if (group.properties.namemode == 2) + suffix_groups.push(group.name); + } + const tag_group_prefix = this.tag.find(".group-prefix"); + const tag_group_suffix = this.tag.find(".group-suffix"); + if (prefix_groups.length > 0) { + tag_group_prefix.text("[" + prefix_groups.join("][") + "]").show(); + } + else { + tag_group_prefix.hide(); + } + if (suffix_groups.length > 0) { + tag_group_suffix.text("[" + suffix_groups.join("][") + "]").show(); + } + else { + tag_group_suffix.hide(); + } + } + updateClientVariables() { + if (this.lastVariableUpdate == 0 || new Date().getTime() - 10 * 60 * 1000 > this.lastVariableUpdate) { //Cache these only 10 min + this.lastVariableUpdate = new Date().getTime(); + this.channelTree.client.serverConnection.send_command("clientgetvariables", { clid: this.clientId() }); + } + } + chat(create = false) { + let chatName = "client_" + this.clientUid() + ":" + this.clientId(); + let c = chat.findChat(chatName); + if ((!c) && create) { + c = chat.createChat(chatName); + c.closeable = true; + c.name = this.clientNickName(); + const _this = this; + c.onMessageSend = function (text) { + _this.channelTree.client.serverConnection.command_helper.sendMessage(text, ChatType.CLIENT, _this); + }; + c.onClose = function () { + //TODO check online? + _this.channelTree.client.serverConnection.send_command("clientchatclosed", { "clid": _this.clientId() }); + return true; + }; + } + return c; + } + updateClientIcon() { + this.tag.find(".container-icon-client").children().detach(); + if (this.properties.client_icon_id > 0) { + this.channelTree.client.fileManager.icons.generateTag(this.properties.client_icon_id).attr("title", "Client icon") + .appendTo(this.tag.find(".container-icon-client")); + } + } + updateGroupIcon(group) { + if (!group) + return; + //TODO group icon order + this.tag.find(".container-icons-group .icon_group_" + group.id).detach(); + if (group.properties.iconid > 0) { + this.tag.find(".container-icons-group").append($.spawn("div") + .addClass("container-group-icon icon_group_" + group.id) + .append(this.channelTree.client.fileManager.icons.generateTag(group.properties.iconid)).attr("title", group.name)); + } + } + assignedServerGroupIds() { + let result = []; + for (let id of this.properties.client_servergroups.split(",")) { + if (id.length == 0) + continue; + result.push(Number.parseInt(id)); + } + return result; + } + assignedChannelGroup() { + return this.properties.client_channel_group_id; + } + groupAssigned(group) { + if (group.target == GroupTarget.SERVER) { + for (let id of this.assignedServerGroupIds()) + if (id == group.id) + return true; + return false; + } + else + return group.id == this.assignedChannelGroup(); + } + onDelete() { + this.audioController.close(); + this.audioController = undefined; + } + calculateOnlineTime() { + return Date.now() / 1000 - this.properties.client_lastconnected; + } + avatarId() { + function str2ab(str) { + let buf = new ArrayBuffer(str.length); // 2 bytes for each char + let bufView = new Uint8Array(buf); + for (let i = 0, strLen = str.length; i < strLen; i++) { + bufView[i] = str.charCodeAt(i); + } + return buf; + } + try { + let raw = atob(this.properties.client_unique_identifier); + let input = hex.encode(str2ab(raw)); + let result = ""; + for (let index = 0; index < input.length; index++) { + let c = input.charAt(index); + let offset = 0; + if (c >= '0' && c <= '9') + offset = c.charCodeAt(0) - '0'.charCodeAt(0); + else if (c >= 'A' && c <= 'F') + offset = c.charCodeAt(0) - 'A'.charCodeAt(0) + 0x0A; + else if (c >= 'a' && c <= 'f') + offset = c.charCodeAt(0) - 'a'.charCodeAt(0) + 0x0A; + result += String.fromCharCode('a'.charCodeAt(0) + offset); + } + return result; + } + catch (e) { //invalid base 64 (like music bot etc) + return undefined; + } + } + update_family_index() { + if (!this._channel) + return; + const index = this._channel.calculate_family_index(); + this.tag.css('padding-left', (index + 2) * 16 + "px"); + } +} +class LocalClientEntry extends ClientEntry { + constructor(handle) { + super(0, "local client"); + this.handle = handle; + } + showContextMenu(x, y, on_close = undefined) { + const _self = this; + spawn_context_menu(x, y, { + name: _translations.nZsgZjvq || (_translations.nZsgZjvq = tr("Change name")), + icon: "client-change_nickname", + callback: () => _self.openRename(), + type: MenuEntryType.ENTRY + }, { + name: _translations.luXlxqAz || (_translations.luXlxqAz = tr("Change description")), + icon: "client-edit", + callback: () => { + createInputModal(_translations.L3eN3w7x || (_translations.L3eN3w7x = tr("Change own description")), _translations.pJm9WNWU || (_translations.pJm9WNWU = tr("New description:
")), text => true, result => { + if (result) { + console.log(_translations.huKXae1n || (_translations.huKXae1n = tr("Changing own description to %s")), result); + _self.channelTree.client.serverConnection.send_command("clientedit", { + clid: _self.clientId(), + client_description: result + }); + } + }, { width: 400, maxLength: 1024 }).open(); + }, + type: MenuEntryType.ENTRY + }, MenuEntry.HR(), ...this.assignment_context(), MenuEntry.CLOSE(on_close)); + } + initializeListener() { + super.initializeListener(); + this.tag.find(".client-name").addClass("client-name-own"); + this.tag.dblclick(() => { + if ($.isArray(this.channelTree.currently_selected)) { //Multiselect + return; + } + this.openRename(); + }); + } + openRename() { + const _self = this; + const elm = this.tag.find(".client-name"); + elm.attr("contenteditable", "true"); + elm.removeClass("client-name-own"); + elm.css("background-color", "white"); + elm.focus(); + _self.renaming = true; + elm.keypress(function (e) { + if (e.keyCode == 13 /* Enter */) { + $(this).trigger("focusout"); + return false; + } + }); + elm.focusout(function (e) { + if (!_self.renaming) + return; + _self.renaming = false; + elm.css("background-color", ""); + elm.removeAttr("contenteditable"); + elm.addClass("client-name-own"); + let text = elm.text().toString(); + if (_self.clientNickName() == text) + return; + elm.text(_self.clientNickName()); + _self.handle.serverConnection.command_helper.updateClient("client_nickname", text).then((e) => { + chat.serverChat().appendMessage(_translations.LUgGlgDn || (_translations.LUgGlgDn = tr("Nickname successfully changed"))); + }).catch((e) => { + chat.serverChat().appendError(_translations.erjjkAEe || (_translations.erjjkAEe = tr("Could not change nickname ({})")), e.extra_message); + _self.openRename(); + }); + }); + } +} +class MusicClientProperties extends ClientProperties { + constructor() { + super(...arguments); + this.player_state = 0; + this.player_volume = 0; + this.client_playlist_id = 0; + this.client_disabled = false; + } +} +class MusicClientPlayerInfo { + constructor() { + this.bot_id = 0; + this.player_state = 0; + this.player_buffered_index = 0; + this.player_replay_index = 0; + this.player_max_index = 0; + this.player_seekable = false; + this.player_title = ""; + this.player_description = ""; + this.song_id = 0; + this.song_url = ""; + this.song_invoker = 0; + this.song_loaded = false; + this.song_title = ""; + this.song_thumbnail = ""; + this.song_length = 0; + } +} +class MusicClientEntry extends ClientEntry { + constructor(clientId, clientName) { + super(clientId, clientName, new MusicClientProperties()); + this._info_promise_age = 0; + } + get properties() { + return this._properties; + } + showContextMenu(x, y, on_close = undefined) { + spawn_context_menu(x, y, { + name: _translations.yOofHBYZ || (_translations.yOofHBYZ = tr("Change bot name")), + icon: "client-change_nickname", + disabled: false, + callback: () => { + createInputModal(_translations.Ib4e7gF0 || (_translations.Ib4e7gF0 = tr("Change music bots nickname")), _translations.IW3obMAX || (_translations.IW3obMAX = tr("New nickname:
")), text => text.length >= 3 && text.length <= 31, result => { + if (result) { + this.channelTree.client.serverConnection.send_command("clientedit", { + clid: this.clientId(), + client_nickname: result + }); + } + }, { width: 400, maxLength: 255 }).open(); + }, + type: MenuEntryType.ENTRY + }, { + name: _translations.QEBR_LaZ || (_translations.QEBR_LaZ = tr("Change bot description")), + icon: "client-edit", + disabled: false, + callback: () => { + createInputModal(_translations.C8pFnqhh || (_translations.C8pFnqhh = tr("Change music bots description")), _translations.AEH0aFoC || (_translations.AEH0aFoC = tr("New description:
")), text => true, result => { + if (typeof (result) === 'string') { + this.channelTree.client.serverConnection.send_command("clientedit", { + clid: this.clientId(), + client_description: result + }); + } + }, { width: 400, maxLength: 255 }).open(); + }, + type: MenuEntryType.ENTRY + }, + /* + { + name: tr("Open music panel"), + icon: "client-edit", + disabled: true, + callback: () => {}, + type: MenuEntryType.ENTRY + }, + */ + { + name: _translations.NFoAqO50 || (_translations.NFoAqO50 = tr("Open bot's playlist")), + icon: "client-edit", + disabled: false, + callback: () => { + this.channelTree.client.serverConnection.command_helper.request_playlist_list().then(lists => { + for (const entry of lists) { + if (entry.playlist_id == this.properties.client_playlist_id) { + Modals.spawnPlaylistEdit(this.channelTree.client, entry); + return; + } + } + createErrorModal(_translations.hi3i15FD || (_translations.hi3i15FD = tr("Invalid permissions")), _translations.aEP95pp4 || (_translations.aEP95pp4 = tr("You dont have to see the bots playlist."))).open(); + }).catch(error => { + createErrorModal(_translations.Em4GmMYf || (_translations.Em4GmMYf = tr("Failed to query playlist.")), _translations.HjT6bOoT || (_translations.HjT6bOoT = tr("Failed to query playlist info."))).open(); + }); + }, + type: MenuEntryType.ENTRY + }, { + name: _translations.BUWjmbJD || (_translations.BUWjmbJD = tr("Quick url replay")), + icon: "client-edit", + disabled: false, + callback: () => { + createInputModal(_translations.u0N7Wpfv || (_translations.u0N7Wpfv = tr("Please enter the URL")), _translations.isk4PsRv || (_translations.isk4PsRv = tr("URL:")), text => true, result => { + if (result) { + this.channelTree.client.serverConnection.send_command("musicbotqueueadd", { + bot_id: this.properties.client_database_id, + type: "yt", + url: result + }).catch(error => { + if (error instanceof CommandResult) { + error = error.extra_message || error.message; + } + //TODO tr + createErrorModal(_translations.E4YHyYIB || (_translations.E4YHyYIB = tr("Failed to replay url")), "Failed to enqueue url:
" + error).open(); + }); + } + }, { width: 400, maxLength: 255 }).open(); + }, + type: MenuEntryType.ENTRY + }, MenuEntry.HR(), ...super.assignment_context(), MenuEntry.HR(), { + type: MenuEntryType.ENTRY, + icon: "client-move_client_to_own_channel", + name: _translations.DNOAqnou || (_translations.DNOAqnou = tr("Move client to your channel")), + callback: () => { + this.channelTree.client.serverConnection.send_command("clientmove", { + clid: this.clientId(), + cid: this.channelTree.client.getClient().currentChannel().getChannelId() + }); + } + }, { + type: MenuEntryType.ENTRY, + icon: "client-kick_channel", + name: _translations.mtkKxwaH || (_translations.mtkKxwaH = tr("Kick client from channel")), + callback: () => { + createInputModal(_translations.envwWmFs || (_translations.envwWmFs = tr("Kick client from channel")), _translations.mfkXcBbD || (_translations.mfkXcBbD = tr("Kick reason:
")), text => true, result => { + if (result) { + console.log(_translations.N8PkkYgk || (_translations.N8PkkYgk = tr("Kicking client %o from channel with reason %o")), this.clientNickName(), result); + this.channelTree.client.serverConnection.send_command("clientkick", { + clid: this.clientId(), + reasonid: ViewReasonId.VREASON_CHANNEL_KICK, + reasonmsg: result + }); + } + }, { width: 400, maxLength: 255 }).open(); + } + }, MenuEntry.HR(), { + type: MenuEntryType.ENTRY, + icon: "client-volume", + name: _translations.a83GPSuP || (_translations.a83GPSuP = tr("Change local volume")), + callback: () => { + Modals.spawnChangeVolume(this.audioController.volume, volume => { + settings.changeServer("volume_client_" + this.clientUid(), volume); + this.audioController.volume = volume; + if (globalClient.selectInfo.currentSelected == this) + globalClient.selectInfo.current_manager().update_local_volume(volume); + }); + } + }, { + type: MenuEntryType.ENTRY, + icon: "client-volume", + name: _translations.vU0_4DbG || (_translations.vU0_4DbG = tr("Change remote volume")), + callback: () => { + let max_volume = this.channelTree.client.permissions.neededPermission(PermissionType.I_CLIENT_MUSIC_CREATE_MODIFY_MAX_VOLUME).value; + if (max_volume < 0) + max_volume = 100; + Modals.spawnChangeRemoteVolume(this.properties.player_volume, max_volume / 100, value => { + this.channelTree.client.serverConnection.send_command("clientedit", { + clid: this.clientId(), + player_volume: value, + }).then(() => { + if (globalClient.selectInfo.currentSelected == this) + globalClient.selectInfo.current_manager().update_remote_volume(value); + }); + }); + } + }, MenuEntry.HR(), { + name: _translations.ReawvrYk || (_translations.ReawvrYk = tr("Delete bot")), + icon: "client-delete", + disabled: false, + callback: () => { + const tag = $.spawn("div").append(MessageHelper.formatMessage(_translations.Iilzvtrs || (_translations.Iilzvtrs = tr("Do you really want to delete {0}")), this.createChatTag(false))); + Modals.spawnYesNo(_translations.GzAtMa7f || (_translations.GzAtMa7f = tr("Are you sure?")), $.spawn("div").append(tag), result => { + if (result) { + this.channelTree.client.serverConnection.send_command("musicbotdelete", { + bot_id: this.properties.client_database_id + }); + } + }); + }, + type: MenuEntryType.ENTRY + }, MenuEntry.CLOSE(on_close)); + } + initializeListener() { + super.initializeListener(); + } + handlePlayerInfo(json) { + if (json) { + let info = JSON.map_to(new MusicClientPlayerInfo(), json); + if (this._info_promise_resolve) + this._info_promise_resolve(info); + this._info_promise_reject = undefined; + } + if (this._info_promise) { + if (this._info_promise_reject) + this._info_promise_reject("timeout"); + this._info_promise = undefined; + this._info_promise_age = undefined; + this._info_promise_reject = undefined; + this._info_promise_resolve = undefined; + } + } + requestPlayerInfo(max_age = 1000) { + if (this._info_promise && this._info_promise_age && Date.now() - max_age <= this._info_promise_age) + return this._info_promise; + this._info_promise_age = Date.now(); + this._info_promise = new Promise((resolve, reject) => { + this._info_promise_reject = reject; + this._info_promise_resolve = resolve; + }); + this.channelTree.client.serverConnection.send_command("musicbotplayerinfo", { bot_id: this.properties.client_database_id }); + return this._info_promise; + } +} +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["a2cf9f5398ab8ba40622e442d19e664992e019695aaa85a26579c2ba375729e9"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["a2cf9f5398ab8ba40622e442d19e664992e019695aaa85a26579c2ba375729e9"] = "a2cf9f5398ab8ba40622e442d19e664992e019695aaa85a26579c2ba375729e9"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "I_5eKNaW", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalCreateChannel.ts (7,31)" }, { name: "cONwhwiT", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalCreateChannel.ts (7,52)" }, { name: "aqtjtrQn", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalCreateChannel.ts (21,35)" }, { name: "AOJLpmQS", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalCreateChannel.ts (24,31)" }, { name: "PjdLwfL1", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalCreateChannel.ts (48,56)" }, { name: "_OFKRUyl", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalCreateChannel.ts (55,25)" }, { name: "K4OJG2tR", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalCreateChannel.ts (173,25)" }, { name: "EXs5RdoR", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalCreateChannel.ts (185,56)" }, { name: "liNig9Yy", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalCreateChannel.ts (192,33)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +/// +var Modals; +(function (Modals) { + function createChannelModal(channel, parent, permissions, callback) { + let properties = {}; //The changes properties + const modal = createModal({ + header: channel ? _translations.I_5eKNaW || (_translations.I_5eKNaW = tr("Edit channel")) : _translations.cONwhwiT || (_translations.cONwhwiT = tr("Create channel")), + body: () => { + let template = $("#tmpl_channel_edit").renderTag(channel ? channel.properties : { + channel_flag_maxfamilyclients_unlimited: true, + channel_flag_maxclients_unlimited: true + }); + return template.tabify(); + }, + footer: () => { + let footer = $.spawn("div"); + footer.addClass("modal-button-group"); + footer.css("margin", "5px"); + let buttonCancel = $.spawn("button"); + buttonCancel.text(_translations.aqtjtrQn || (_translations.aqtjtrQn = tr("Cancel"))).addClass("button_cancel"); + let buttonOk = $.spawn("button"); + buttonOk.text(_translations.AOJLpmQS || (_translations.AOJLpmQS = tr("Ok"))).addClass("button_ok"); + footer.append(buttonCancel); + footer.append(buttonOk); + return footer; + }, + width: 500 + }); + applyGeneralListener(properties, modal.htmlTag.find(".general_properties"), modal.htmlTag.find(".button_ok"), !channel); + applyStandardListener(properties, modal.htmlTag.find(".settings_standard"), modal.htmlTag.find(".button_ok"), parent, !channel); + applyPermissionListener(properties, modal.htmlTag.find(".settings_permissions"), modal.htmlTag.find(".button_ok"), permissions, channel); + applyAudioListener(properties, modal.htmlTag.find(".container-channel-settings-audio"), modal.htmlTag.find(".button_ok"), channel); + applyAdvancedListener(properties, modal.htmlTag.find(".settings_advanced"), modal.htmlTag.find(".button_ok"), channel); + let updated = []; + modal.htmlTag.find(".button_ok").click(() => { + modal.htmlTag.find(".settings_permissions").find("input[permission]").each((index, _element) => { + let element = $(_element); + if (!element.prop("changed")) + return; + let permission = permissions.resolveInfo(element.attr("permission")); + if (!permission) { + log.error(LogCategory.PERMISSIONS, _translations.PjdLwfL1 || (_translations.PjdLwfL1 = tr("Failed to resolve channel permission for name %o")), element.attr("permission")); + element.prop("disabled", true); + return; + } + updated.push(new PermissionValue(permission, element.val())); + }); + console.log(_translations._OFKRUyl || (_translations._OFKRUyl = tr("Updated permissions %o")), updated); + }).click(() => { + modal.close(); + callback(properties, updated); //First may create the channel + }); + modal.htmlTag.find(".button_cancel").click(() => { + modal.close(); + callback(); + }); + modal.open(); + if (!channel) + modal.htmlTag.find(".channel_name").focus(); + } + Modals.createChannelModal = createChannelModal; + function applyGeneralListener(properties, tag, button, create) { + let updateButton = () => { + if (tag.find(".input_error").length == 0) + button.removeAttr("disabled"); + else + button.attr("disabled", "true"); + }; + tag.find(".channel_name").on('change keyup', function () { + properties.channel_name = this.value; + $(this).removeClass("input_error"); + if (this.value.length < 1 || this.value.length > 40) + $(this).addClass("input_error"); + updateButton(); + }).prop("disabled", !create && !globalClient.permissions.neededPermission(PermissionType.B_CHANNEL_MODIFY_NAME).granted(1)); + tag.find(".channel_password").change(function () { + properties.channel_flag_password = this.value.length != 0; + if (properties.channel_flag_password) + helpers.hashPassword(this.value).then(pass => properties.channel_password = pass); + $(this).removeClass("input_error"); + if (!properties.channel_flag_password) + if (globalClient.permissions.neededPermission(PermissionType.B_CHANNEL_CREATE_MODIFY_WITH_FORCE_PASSWORD).granted(1)) + $(this).addClass("input_error"); + updateButton(); + }).prop("disabled", !globalClient.permissions.neededPermission(create ? PermissionType.B_CHANNEL_CREATE_WITH_PASSWORD : PermissionType.B_CHANNEL_MODIFY_PASSWORD).granted(1)); + tag.find(".channel_topic").change(function () { + properties.channel_topic = this.value; + }).prop("disabled", !globalClient.permissions.neededPermission(create ? PermissionType.B_CHANNEL_CREATE_WITH_TOPIC : PermissionType.B_CHANNEL_MODIFY_TOPIC).granted(1)); + tag.find(".channel_description").change(function () { + properties.channel_description = this.value; + }).prop("disabled", !globalClient.permissions.neededPermission(create ? PermissionType.B_CHANNEL_CREATE_WITH_DESCRIPTION : PermissionType.B_CHANNEL_MODIFY_DESCRIPTION).granted(1)); + if (create) { + setTimeout(() => { + tag.find(".channel_name").trigger("change"); + tag.find(".channel_password").trigger('change'); + }, 0); + } + } + function applyStandardListener(properties, tag, button, parent, create) { + tag.find("input[name=\"channel_type\"]").change(function () { + switch (this.value) { + case "semi": + properties.channel_flag_permanent = false; + properties.channel_flag_semi_permanent = true; + break; + case "perm": + properties.channel_flag_permanent = true; + properties.channel_flag_semi_permanent = false; + break; + default: + properties.channel_flag_permanent = false; + properties.channel_flag_semi_permanent = false; + break; + } + }); + tag.find("input[name=\"channel_type\"][value=\"temp\"]") + .prop("disabled", !globalClient.permissions.neededPermission(create ? PermissionType.B_CHANNEL_CREATE_TEMPORARY : PermissionType.B_CHANNEL_MODIFY_MAKE_TEMPORARY).granted(1)); + tag.find("input[name=\"channel_type\"][value=\"semi\"]") + .prop("disabled", !globalClient.permissions.neededPermission(create ? PermissionType.B_CHANNEL_CREATE_SEMI_PERMANENT : PermissionType.B_CHANNEL_MODIFY_MAKE_SEMI_PERMANENT).granted(1)); + tag.find("input[name=\"channel_type\"][value=\"perm\"]") + .prop("disabled", !globalClient.permissions.neededPermission(create ? PermissionType.B_CHANNEL_CREATE_PERMANENT : PermissionType.B_CHANNEL_MODIFY_MAKE_PERMANENT).granted(1)); + if (create) + tag.find("input[name=\"channel_type\"]:not(:disabled)").last().prop("checked", true).trigger('change'); + tag.find("input[name=\"channel_default\"]").change(function () { + console.log(this.checked); + properties.channel_flag_default = this.checked; + let elements = tag.find("input[name=\"channel_type\"]"); + elements.prop("disabled", this.checked); + if (this.checked) { + elements.prop("checked", false); + tag.find("input[name=\"channel_type\"][value=\"perm\"]").prop("checked", true).trigger("change"); + } + }).prop("disabled", !globalClient.permissions.neededPermission(create ? PermissionType.B_CHANNEL_CREATE_PERMANENT : PermissionType.B_CHANNEL_MODIFY_MAKE_PERMANENT).granted(1) || + !globalClient.permissions.neededPermission(create ? PermissionType.B_CHANNEL_CREATE_WITH_DEFAULT : PermissionType.B_CHANNEL_MODIFY_MAKE_DEFAULT).granted(1)); + tag.find("input[name=\"talk_power\"]").change(function () { + properties.channel_needed_talk_power = parseInt(this.value); + }).prop("disabled", !globalClient.permissions.neededPermission(create ? PermissionType.B_CHANNEL_CREATE_WITH_NEEDED_TALK_POWER : PermissionType.B_CHANNEL_MODIFY_NEEDED_TALK_POWER).granted(1)); + let orderTag = tag.find(".order_id"); + for (let channel of (parent ? parent.children() : globalClient.channelTree.rootChannel())) + $.spawn("option").attr("channelId", channel.channelId.toString()).text(channel.channelName()).appendTo(orderTag); + orderTag.change(function () { + let selected = $(this.options.item(this.selectedIndex)); + properties.channel_order = parseInt(selected.attr("channelId")); + }).prop("disabled", !globalClient.permissions.neededPermission(create ? PermissionType.B_CHANNEL_CREATE_WITH_SORTORDER : PermissionType.B_CHANNEL_MODIFY_SORTORDER).granted(1)); + orderTag.find("option").last().prop("selected", true); + } + function applyPermissionListener(properties, tag, button, permissions, channel) { + let apply_permissions = (channel_permissions) => { + console.log(_translations.K4OJG2tR || (_translations.K4OJG2tR = tr("Got permissions: %o")), channel_permissions); + let required_power = -2; + for (let cperm of channel_permissions) + if (cperm.type.name == PermissionType.I_CHANNEL_NEEDED_MODIFY_POWER) { + required_power = cperm.value; + break; + } + tag.find("input[permission]").each((index, _element) => { + let element = $(_element); + let permission = permissions.resolveInfo(element.attr("permission")); + if (!permission) { + log.error(LogCategory.PERMISSIONS, _translations.EXs5RdoR || (_translations.EXs5RdoR = tr("Failed to resolve channel permission for name %o")), element.attr("permission")); + element.prop("disabled", true); + return; + } + let old_value = 0; + element.on("click keyup", () => { + console.log(_translations.liNig9Yy || (_translations.liNig9Yy = tr("Permission triggered! %o")), element.val() != old_value); + element.prop("changed", element.val() != old_value); + }); + for (let cperm of channel_permissions) + if (cperm.type == permission) { + element.val(old_value = cperm.value); + return; + } + element.val(0); + }); + if (!permissions.neededPermission(PermissionType.I_CHANNEL_MODIFY_POWER).granted(required_power, false)) { + tag.find("input[permission]").prop("disabled", false); //No permissions + } + }; + if (channel) { + permissions.requestChannelPermissions(channel.getChannelId()).then(apply_permissions).catch((error) => { + tag.find("input[permission]").prop("disabled", true); + console.log("Failed to receive channel permissions (%o)", error); + }); + } + else + apply_permissions([]); + } + function applyAudioListener(properties, tag, button, channel) { + let update_template = () => { + let codec = properties.channel_codec; + if (!codec && channel) + codec = channel.properties.channel_codec; + if (!codec) + return; + let quality = properties.channel_codec_quality; + if (!quality && channel) + quality = channel.properties.channel_codec_quality; + if (!quality) + return; + if (codec == 4 && quality == 4) + tag.find("input[name=\"voice_template\"][value=\"voice_mobile\"]").prop("checked", true); + else if (codec == 4 && quality == 6) + tag.find("input[name=\"voice_template\"][value=\"voice_desktop\"]").prop("checked", true); + else if (codec == 5 && quality == 6) + tag.find("input[name=\"voice_template\"][value=\"music\"]").prop("checked", true); + else + tag.find("input[name=\"voice_template\"][value=\"custom\"]").prop("checked", true); + }; + let change_codec = codec => { + if (properties.channel_codec == codec) + return; + tag.find(".voice_codec option").prop("selected", false).eq(codec).prop("selected", true); + properties.channel_codec = codec; + update_template(); + }; + let quality_slider = tag.find(".voice_quality_slider"); + let quality_number = tag.find(".voice_quality_number"); + let change_quality = (quality) => { + if (properties.channel_codec_quality == quality) + return; + properties.channel_codec_quality = quality; + if (quality_slider.val() != quality) + quality_slider.val(quality); + if (parseInt(quality_number.text()) != quality) + quality_number.text(quality); + update_template(); + }; + tag.find("input[name=\"voice_template\"]").change(function () { + switch (this.value) { + case "custom": + break; + case "music": + change_codec(5); + change_quality(6); + break; + case "voice_desktop": + change_codec(4); + change_quality(6); + break; + case "voice_mobile": + change_codec(4); + change_quality(4); + break; + } + }); + tag.find("input[name=\"voice_template\"][value=\"voice_mobile\"]") + .prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_CHANNEL_CREATE_MODIFY_WITH_CODEC_OPUSVOICE).granted(1)); + tag.find("input[name=\"voice_template\"][value=\"voice_desktop\"]") + .prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_CHANNEL_CREATE_MODIFY_WITH_CODEC_OPUSVOICE).granted(1)); + tag.find("input[name=\"voice_template\"][value=\"music\"]") + .prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_CHANNEL_CREATE_MODIFY_WITH_CODEC_OPUSMUSIC).granted(1)); + let codecs = tag.find(".voice_codec option"); + codecs.eq(0).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_CHANNEL_CREATE_MODIFY_WITH_CODEC_SPEEX8).granted(1)); + codecs.eq(1).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_CHANNEL_CREATE_MODIFY_WITH_CODEC_SPEEX16).granted(1)); + codecs.eq(2).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_CHANNEL_CREATE_MODIFY_WITH_CODEC_SPEEX32).granted(1)); + codecs.eq(3).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_CHANNEL_CREATE_MODIFY_WITH_CODEC_CELTMONO48).granted(1)); + codecs.eq(4).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_CHANNEL_CREATE_MODIFY_WITH_CODEC_OPUSVOICE).granted(1)); + codecs.eq(5).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_CHANNEL_CREATE_MODIFY_WITH_CODEC_OPUSMUSIC).granted(1)); + tag.find(".voice_codec").change(function () { + if ($(this.item(this.selectedIndex)).prop("disabled")) + return false; + change_codec(this.selectedIndex); + }); + if (!channel) { + change_codec(4); + change_quality(6); + } + else { + change_codec(channel.properties.channel_codec); + change_quality(channel.properties.channel_codec_quality); + } + update_template(); + quality_slider.on('input', event => change_quality(parseInt(quality_slider.val()))); + } + function applyAdvancedListener(properties, tag, button, channel) { + tag.find(".channel_name_phonetic").change(function () { + properties.channel_topic = this.value; + }); + tag.find(".channel_delete_delay").change(function () { + properties.channel_delete_delay = parseInt(this.value); + }).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_CHANNEL_MODIFY_TEMP_DELETE_DELAY).granted(1)); + tag.find(".channel_codec_is_unencrypted").change(function () { + properties.channel_codec_is_unencrypted = parseInt(this.value) == 0; + }).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_CHANNEL_MODIFY_MAKE_CODEC_ENCRYPTED).granted(1)); + { + let tag_infinity = tag.find("input[name=\"max_users\"][value=\"infinity\"]"); + let tag_limited = tag.find("input[name=\"max_users\"][value=\"limited\"]"); + let tag_limited_value = tag.find(".channel_maxclients"); + if (!globalClient.permissions.neededPermission(!channel ? PermissionType.B_CHANNEL_CREATE_WITH_MAXCLIENTS : PermissionType.B_CHANNEL_MODIFY_MAXCLIENTS).granted(1)) { + tag_infinity.prop("disabled", true); + tag_limited.prop("disabled", true); + tag_limited_value.prop("disabled", true); + } + else { + tag.find("input[name=\"max_users\"]").change(function () { + console.log(this.value); + let infinity = this.value == "infinity"; + tag_limited_value.prop("disabled", infinity); + properties.channel_flag_maxclients_unlimited = infinity; + }); + tag_limited_value.change(event => properties.channel_maxclients = parseInt(tag_limited_value.val())); + tag.find("input[name=\"max_users\"]:checked").trigger('change'); + } + } + { + let tag_inherited = tag.find("input[name=\"max_users_family\"][value=\"inherited\"]"); + let tag_infinity = tag.find("input[name=\"max_users_family\"][value=\"infinity\"]"); + let tag_limited = tag.find("input[name=\"max_users_family\"][value=\"limited\"]"); + let tag_limited_value = tag.find(".channel_maxfamilyclients"); + if (!globalClient.permissions.neededPermission(!channel ? PermissionType.B_CHANNEL_CREATE_WITH_MAXCLIENTS : PermissionType.B_CHANNEL_MODIFY_MAXCLIENTS).granted(1)) { + tag_inherited.prop("disabled", true); + tag_infinity.prop("disabled", true); + tag_limited.prop("disabled", true); + tag_limited_value.prop("disabled", true); + } + else { + tag.find("input[name=\"max_users_family\"]").change(function () { + console.log(this.value); + tag_limited_value.prop("disabled", this.value != "limited"); + properties.channel_flag_maxfamilyclients_unlimited = this.value == "infinity"; + properties.channel_flag_maxfamilyclients_inherited = this.value == "inherited"; + }); + tag_limited_value.change(event => properties.channel_maxfamilyclients = parseInt(tag_limited_value.val())); + tag.find("input[name=\"max_users_family\"]:checked").trigger('change'); + } + } + } +})(Modals || (Modals = {})); +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["8dcbd8a70cd98a2257e1a14cbf1cf6645d3472a77e9fb1223c85f0eb8b75b0a5"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["8dcbd8a70cd98a2257e1a14cbf1cf6645d3472a77e9fb1223c85f0eb8b75b0a5"] = "8dcbd8a70cd98a2257e1a14cbf1cf6645d3472a77e9fb1223c85f0eb8b75b0a5"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "ic5s4uAG", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/view.ts (92,23)" }, { name: "Im6kkByq", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/view.ts (222,27)" }, { name: "wnjiw4ne", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/view.ts (434,21)" }, { name: "ltEIwecC", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/view.ts (437,21)" }, { name: "vf_m4UWD", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/view.ts (442,21)" }, { name: "idyf3ak0", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/view.ts (448,23)" }, { name: "tNuuZtyu", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/view.ts (450,38)" }, { name: "_R2YC2dC", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/view.ts (450,58)" }, { name: "Bv07ZFZd", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/view.ts (466,19)" }, { name: "vWLAAncQ", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/view.ts (481,23)" }, { name: "KhxDzhtu", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/view.ts (483,38)" }, { name: "RjdBTdS1", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/view.ts (483,71)" }, { name: "P5GiWVS7", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/view.ts (501,27)" }, { name: "k9P4QCzP", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/view.ts (503,42)" }, { name: "SMlzjZbN", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/view.ts (503,74)" }, { name: "muNp88F6", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/view.ts (518,27)" }, { name: "fmOFFQTy", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/view.ts (539,27)" }, { name: "wDkblViI", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/view.ts (545,90)" }, { name: "FgpUp2mr", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/view.ts (547,43)" }, { name: "_5X6xyU0", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/view.ts (599,44)" }, { name: "D_jouOXj", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/view.ts (603,52)" }, { name: "uTsNcd9d", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/view.ts (625,49)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +/// +/// +/// +/// +/// +/// +/// +class ChannelTree { + constructor(client, htmlTree) { + this.currently_selected = undefined; + this.currently_selected_context_callback = undefined; + this._tree_detached = false; + document.addEventListener("touchstart", function () { }, true); + this.client = client; + this.htmlTree = htmlTree; + this.htmlTree_parent = this.htmlTree.parent(); + this.client_mover = new ClientMover(this); + this.reset(); + if (!settings.static(Settings.KEY_DISABLE_CONTEXT_MENU, false)) { + this.htmlTree.parent().on("contextmenu", (event) => { + if (event.isDefaultPrevented()) + return; + for (const element of document.elementsFromPoint(event.pageX, event.pageY)) + if (element.classList.contains("channelLine") || element.classList.contains("client")) + return; + event.preventDefault(); + if ($.isArray(this.currently_selected)) { //Multiselect + (this.currently_selected_context_callback || ((_) => null))(event); + } + else { + this.onSelect(undefined); + this.showContextMenu(event.pageX, event.pageY); + } + }); + } + this.htmlTree.on('resize', this.handle_resized.bind(this)); + /* TODO release these events again when ChannelTree get deinitialized */ + $(document).on('click', event => { + if (this.selected_event != event.originalEvent) + this.selected_event = undefined; + }); + $(document).on('keydown', this.handle_key_press.bind(this)); + this.htmlTree.on('click', event => { + { + this.selected_event = event.originalEvent; + } + }); + } + hide_channel_tree() { + this.htmlTree.detach(); + this._tree_detached = true; + } + show_channel_tree() { + this._tree_detached = false; + this.htmlTree.appendTo(this.htmlTree_parent); + this.channels.forEach(e => e.recalculate_repetitive_name()); + } + showContextMenu(x, y, on_close = undefined) { + let channelCreate = this.client.permissions.neededPermission(PermissionType.B_CHANNEL_CREATE_TEMPORARY).granted(1) || + this.client.permissions.neededPermission(PermissionType.B_CHANNEL_CREATE_SEMI_PERMANENT).granted(1) || + this.client.permissions.neededPermission(PermissionType.B_CHANNEL_CREATE_PERMANENT).granted(1); + spawn_context_menu(x, y, { + type: MenuEntryType.ENTRY, + icon: "client-channel_create", + name: _translations.ic5s4uAG || (_translations.ic5s4uAG = tr("Create channel")), + invalidPermission: !channelCreate, + callback: () => this.spawnCreateChannel() + }, MenuEntry.CLOSE(on_close)); + } + initialiseHead(serverName, address) { + this.server = new ServerEntry(this, serverName, address); + this.server.htmlTag.appendTo(this.htmlTree); + this.server.initializeListener(); + } + __deleteAnimation(element) { + let tag = element instanceof ChannelEntry ? element.rootTag() : element.tag; + this.htmlTree.find(tag).fadeOut("slow", () => { + tag.remove(); + }); + } + rootChannel() { + return this.channels.filter(e => e.parent == undefined); + } + deleteChannel(channel) { + const _this = this; + for (let index = 0; index < this.channels.length; index++) { + let entry = this.channels[index]; + let currentEntry = this.channels[index]; + while (currentEntry != undefined && currentEntry != null) { + if (currentEntry == channel) { + _this.channels.remove(entry); + _this.__deleteAnimation(entry); + entry.channelTree = null; + index--; + break; + } + else + currentEntry = currentEntry.parent_channel(); + } + } + this.channels.remove(channel); + this.__deleteAnimation(channel); + channel.channelTree = null; + if (channel.channel_previous) + channel.channel_previous.channel_next = channel.channel_next; + if (channel.channel_next) + channel.channel_next.channel_previous = channel.channel_previous; + if (channel == this.channel_first) + this.channel_first = channel.channel_next; + if (channel == this.channel_last) + this.channel_last = channel.channel_previous; + } + insertChannel(channel) { + channel.channelTree = this; + this.channels.push(channel); + let elm = undefined; + let tag = this.htmlTree; + let previous_channel = null; + if (channel.hasParent()) { + let parent = channel.parent_channel(); + let siblings = parent.children(); + if (siblings.length == 0) { + elm = parent.rootTag(); + previous_channel = null; + } + else { + previous_channel = siblings.last(); + elm = previous_channel.tag; + } + tag = parent.siblingTag(); + } + else { + previous_channel = this.channel_last; + if (!this.channel_last) + this.channel_last = channel; + if (!this.channel_first) + this.channel_first = channel; + } + channel.channel_previous = previous_channel; + channel.channel_next = undefined; + if (previous_channel) { + channel.channel_next = previous_channel.channel_next; + previous_channel.channel_next = channel; + if (channel.channel_next) + channel.channel_next.channel_previous = channel; + } + let entry = channel.rootTag(); + if (!this._tree_detached) + entry.css({ display: "none" }).fadeIn("slow"); + entry.appendTo(tag); + if (elm != undefined) + elm.after(entry); + if (channel.channel_previous == channel) /* shall never happen */ + channel.channel_previous = undefined; + if (channel.channel_next == channel) /* shall never happen */ + channel.channel_next = undefined; + channel.initializeListener(); + channel.update_family_index(); + } + findChannel(channelId) { + for (let index = 0; index < this.channels.length; index++) + if (this.channels[index].getChannelId() == channelId) + return this.channels[index]; + return undefined; + } + find_channel_by_name(name, parent, force_parent = true) { + for (let index = 0; index < this.channels.length; index++) + if (this.channels[index].channelName() == name && (!force_parent || parent == this.channels[index].parent)) + return this.channels[index]; + return undefined; + } + moveChannel(channel, channel_previous, parent) { + if (channel_previous != null && channel_previous.parent != parent) { + console.error(_translations.Im6kkByq || (_translations.Im6kkByq = tr("Invalid channel move (different parents! (%o|%o)")), channel_previous.parent, parent); + return; + } + if (channel.channel_next) + channel.channel_next.channel_previous = channel.channel_previous; + if (channel.channel_previous) + channel.channel_previous.channel_next = channel.channel_next; + if (channel == this.channel_last) + this.channel_last = channel.channel_previous; + if (channel == this.channel_first) + this.channel_first = channel.channel_next; + channel.channel_next = undefined; + channel.channel_previous = channel_previous; + channel.parent = parent; + if (channel_previous) { + if (channel_previous == this.channel_last) + this.channel_last = channel; + channel.channel_next = channel_previous.channel_next; + channel_previous.channel_next = channel; + channel_previous.rootTag().after(channel.rootTag()); + if (channel.channel_next) + channel.channel_next.channel_previous = channel; + } + else { + if (parent) { + let children = parent.children(); + if (children.length <= 1) { //Self should be already in there + let left = channel.rootTag(); + left.appendTo(parent.siblingTag()); + channel.channel_next = undefined; + } + else { + channel.channel_previous = undefined; + channel.rootTag().prependTo(parent.siblingTag()); + channel.channel_next = children[1]; /* children 0 shall be the channel itself */ + channel.channel_next.channel_previous = channel; + } + } + else { + this.htmlTree.find(".server").after(channel.rootTag()); + channel.channel_next = this.channel_first; + if (this.channel_first) + this.channel_first.channel_previous = channel; + this.channel_first = channel; + } + } + channel.update_family_index(); + channel.children(true).forEach(e => e.update_family_index()); + channel.clients(true).forEach(e => e.update_family_index()); + if (channel.channel_previous == channel) { /* shall never happen */ + channel.channel_previous = undefined; + debugger; + } + if (channel.channel_next == channel) { /* shall never happen */ + channel.channel_next = undefined; + debugger; + } + } + deleteClient(client) { + this.clients.remove(client); + this.__deleteAnimation(client); + client.onDelete(); + } + insertClient(client, channel) { + let newClient = this.findClient(client.clientId()); + if (newClient) + client = newClient; //Got new client :) + else + this.clients.push(client); + client.channelTree = this; + client["_channel"] = channel; + let tag = client.tag; + if (!this._show_queries && client.properties.client_type == ClientType.CLIENT_QUERY) + client.tag.hide(); + else if (!this._tree_detached) + tag.css("display", "none").fadeIn("slow"); + tag.appendTo(channel.clientTag()); + client.currentChannel().reorderClients(); + channel.updateChannelTypeIcon(); + client.update_family_index(); + return client; + } + registerClient(client) { + this.clients.push(client); + client.channelTree = this; + } + moveClient(client, channel) { + let oldChannel = client.currentChannel(); + client["_channel"] = channel; + let tag = client.tag; + tag.detach(); + tag.appendTo(client.currentChannel().clientTag()); + if (oldChannel) { + oldChannel.updateChannelTypeIcon(); + } + if (client.currentChannel()) { + client.currentChannel().reorderClients(); + client.currentChannel().updateChannelTypeIcon(); + } + client.updateClientStatusIcons(); + client.update_family_index(); + } + findClient(clientId) { + for (let index = 0; index < this.clients.length; index++) { + if (this.clients[index].clientId() == clientId) + return this.clients[index]; + } + return undefined; + } + find_client_by_dbid(client_dbid) { + for (let index = 0; index < this.clients.length; index++) { + if (this.clients[index].properties.client_database_id == client_dbid) + return this.clients[index]; + } + return undefined; + } + find_client_by_unique_id(unique_id) { + for (let index = 0; index < this.clients.length; index++) { + if (this.clients[index].properties.client_unique_identifier == unique_id) + return this.clients[index]; + } + return undefined; + } + static same_selected_type(a, b) { + if (a instanceof ChannelEntry) + return b instanceof ChannelEntry; + if (a instanceof ClientEntry) + return b instanceof ClientEntry; + if (a instanceof ServerEntry) + return b instanceof ServerEntry; + return a == b; + } + onSelect(entry, enforce_single, flag_shift) { + console.log("Select: " + entry); + if (this.currently_selected && (ppt.key_pressed(ppt.SpecialKey.SHIFT) || flag_shift) && entry instanceof ClientEntry) { //Currently we're only supporting client multiselects :D + if (!entry) + return; //Nowhere + if ($.isArray(this.currently_selected)) { + if (!ChannelTree.same_selected_type(this.currently_selected[0], entry)) + return; //Not the same type + } + else if (ChannelTree.same_selected_type(this.currently_selected, entry)) { + this.currently_selected = [this.currently_selected]; + } + if (entry instanceof ChannelEntry) + this.currently_selected_context_callback = this.callback_multiselect_channel.bind(this); + if (entry instanceof ClientEntry) + this.currently_selected_context_callback = this.callback_multiselect_client.bind(this); + } + else + this.currently_selected = undefined; + if (!$.isArray(this.currently_selected) || enforce_single) { + this.currently_selected = entry; + this.htmlTree.find(".selected").each(function (idx, e) { + $(e).removeClass("selected"); + }); + } + else { + for (const e of this.currently_selected) + if (e == entry) { + this.currently_selected.remove(e); + if (entry instanceof ChannelEntry) + entry.channelTag().removeClass("selected"); + else if (entry instanceof ClientEntry) + entry.tag.removeClass("selected"); + else if (entry instanceof ServerEntry) + entry.htmlTag.removeClass("selected"); + if (this.currently_selected.length == 1) + this.currently_selected = this.currently_selected[0]; + else if (this.currently_selected.length == 0) + this.currently_selected = undefined; + //Already selected + return; + } + this.currently_selected.push(entry); + } + if (entry instanceof ChannelEntry) + entry.channelTag().addClass("selected"); + else if (entry instanceof ClientEntry) + entry.tag.addClass("selected"); + else if (entry instanceof ServerEntry) + entry.htmlTag.addClass("selected"); + this.client.selectInfo.setCurrentSelected($.isArray(this.currently_selected) ? undefined : entry); + } + callback_multiselect_channel(event) { + console.log(_translations.wnjiw4ne || (_translations.wnjiw4ne = tr("Multiselect channel"))); + } + callback_multiselect_client(event) { + console.log(_translations.ltEIwecC || (_translations.ltEIwecC = tr("Multiselect client"))); + const clients = this.currently_selected; + const music_only = clients.map(e => e instanceof MusicClientEntry ? 0 : 1).reduce((a, b) => a + b, 0) == 0; + const music_entry = clients.map(e => e instanceof MusicClientEntry ? 1 : 0).reduce((a, b) => a + b, 0) > 0; + const local_client = clients.map(e => e instanceof LocalClientEntry ? 1 : 0).reduce((a, b) => a + b, 0) > 0; + console.log(_translations.vf_m4UWD || (_translations.vf_m4UWD = tr("Music only: %o | Container music: %o | Container local: %o")), music_entry, music_entry, local_client); + let entries = []; + if (!music_entry && !local_client) { //Music bots or local client cant be poked + entries.push({ + type: MenuEntryType.ENTRY, + icon: "client-poke", + name: _translations.idyf3ak0 || (_translations.idyf3ak0 = tr("Poke clients")), + callback: () => { + createInputModal(_translations.tNuuZtyu || (_translations.tNuuZtyu = tr("Poke clients")), _translations._R2YC2dC || (_translations._R2YC2dC = tr("Poke message:
")), text => true, result => { + if (typeof (result) === "string") { + for (const client of this.currently_selected) + this.client.serverConnection.send_command("clientpoke", { + clid: client.clientId(), + msg: result + }); + } + }, { width: 400, maxLength: 512 }).open(); + } + }); + } + entries.push({ + type: MenuEntryType.ENTRY, + icon: "client-move_client_to_own_channel", + name: _translations.Bv07ZFZd || (_translations.Bv07ZFZd = tr("Move clients to your channel")), + callback: () => { + const target = this.client.getClient().currentChannel().getChannelId(); + for (const client of clients) + this.client.serverConnection.send_command("clientmove", { + clid: client.clientId(), + cid: target + }); + } + }); + if (!local_client) { //local client cant be kicked and/or banned or kicked + entries.push(MenuEntry.HR()); + entries.push({ + type: MenuEntryType.ENTRY, + icon: "client-kick_channel", + name: _translations.vWLAAncQ || (_translations.vWLAAncQ = tr("Kick clients from channel")), + callback: () => { + createInputModal(_translations.KhxDzhtu || (_translations.KhxDzhtu = tr("Kick clients from channel")), _translations.RjdBTdS1 || (_translations.RjdBTdS1 = tr("Kick reason:
")), text => true, result => { + if (result) { + for (const client of clients) + this.client.serverConnection.send_command("clientkick", { + clid: client.clientId(), + reasonid: ViewReasonId.VREASON_CHANNEL_KICK, + reasonmsg: result + }); + } + }, { width: 400, maxLength: 255 }).open(); + } + }); + if (!music_entry) { //Music bots cant be banned or kicked + entries.push({ + type: MenuEntryType.ENTRY, + icon: "client-kick_server", + name: _translations.P5GiWVS7 || (_translations.P5GiWVS7 = tr("Kick clients fom server")), + callback: () => { + createInputModal(_translations.k9P4QCzP || (_translations.k9P4QCzP = tr("Kick clients from server")), _translations.SMlzjZbN || (_translations.SMlzjZbN = tr("Kick reason:
")), text => true, result => { + if (result) { + for (const client of clients) + this.client.serverConnection.send_command("clientkick", { + clid: client.clientId(), + reasonid: ViewReasonId.VREASON_SERVER_KICK, + reasonmsg: result + }); + } + }, { width: 400, maxLength: 255 }).open(); + } + }, { + type: MenuEntryType.ENTRY, + icon: "client-ban_client", + name: _translations.muNp88F6 || (_translations.muNp88F6 = tr("Ban clients")), + invalidPermission: !this.client.permissions.neededPermission(PermissionType.I_CLIENT_BAN_MAX_BANTIME).granted(1), + callback: () => { + Modals.spawnBanClient((clients).map(entry => entry.clientNickName()), (data) => { + for (const client of clients) + this.client.serverConnection.send_command("banclient", { + uid: client.properties.client_unique_identifier, + banreason: data.reason, + time: data.length + }, { + flagset: [data.no_ip ? "no-ip" : "", data.no_hwid ? "no-hardware-id" : "", data.no_name ? "no-nickname" : ""] + }).then(() => { + sound.play(Sound.USER_BANNED); + }); + }); + } + }); + } + if (music_only) { + entries.push(MenuEntry.HR()); + entries.push({ + name: _translations.fmOFFQTy || (_translations.fmOFFQTy = tr("Delete bots")), + icon: "client-delete", + disabled: false, + callback: () => { + const param_string = clients.map((_, index) => "{" + index + "}").join(', '); + const param_values = clients.map(client => client.createChatTag(true)); + const tag = $.spawn("div").append(...MessageHelper.formatMessage((_translations.wDkblViI || (_translations.wDkblViI = tr("Do you really want to delete "))) + param_string, ...param_values)); + const tag_container = $.spawn("div").append(tag); + Modals.spawnYesNo(_translations.FgpUp2mr || (_translations.FgpUp2mr = tr("Are you sure?")), tag_container, result => { + if (result) { + for (const client of clients) + this.client.serverConnection.send_command("musicbotdelete", { + botid: client.properties.client_database_id + }); + } + }); + }, + type: MenuEntryType.ENTRY + }); + } + } + spawn_context_menu(event.pageX, event.pageY, ...entries); + } + clientsByGroup(group) { + let result = []; + for (let client of this.clients) { + if (client.groupAssigned(group)) + result.push(client); + } + return result; + } + clientsByChannel(channel) { + let result = []; + for (let client of this.clients) { + if (client.currentChannel() == channel) + result.push(client); + } + return result; + } + reset() { + this.server = null; + this.clients = []; + this.channels = []; + this.htmlTree.children().detach(); //Do not remove the listener! + this.channel_first = undefined; + this.channel_last = undefined; + } + spawnCreateChannel(parent) { + Modals.createChannelModal(undefined, parent, this.client.permissions, (properties, permissions) => { + if (!properties) + return; + properties["cpid"] = parent ? parent.channelId : 0; + log.debug(LogCategory.CHANNEL, _translations._5X6xyU0 || (_translations._5X6xyU0 = tr("Creating a new channel.\nProperties: %o\nPermissions: %o")), properties); + this.client.serverConnection.send_command("channelcreate", properties).then(() => { + let channel = this.find_channel_by_name(properties.channel_name, parent, true); + if (!channel) { + log.error(LogCategory.CHANNEL, _translations.D_jouOXj || (_translations.D_jouOXj = tr("Failed to resolve channel after creation. Could not apply permissions!"))); + return; + } + if (permissions && permissions.length > 0) { + let perms = []; + for (let perm of permissions) { + perms.push({ + permvalue: perm.value, + permnegated: false, + permskip: false, + permid: perm.type.id + }); + } + perms[0]["cid"] = channel.channelId; + return this.client.serverConnection.send_command("channeladdperm", perms, { + flagset: ["continueonerror"] + }).then(() => new Promise(resolve => { resolve(channel); })); + } + return new Promise(resolve => { resolve(channel); }); + }).then(channel => { + chat.serverChat().appendMessage(_translations.uTsNcd9d || (_translations.uTsNcd9d = tr("Channel {} successfully created!")), true, channel.generate_tag(true)); + sound.play(Sound.CHANNEL_CREATED); + }); + }); + } + handle_resized() { + for (let channel of this.channels) + channel.handle_frame_resized(); + } + select_next_channel(channel, select_client) { + if (select_client) { + const clients = channel.clients_ordered(); + if (clients.length > 0) { + this.onSelect(clients[0], true); + return; + } + } + const children = channel.children(); + if (children.length > 0) { + this.onSelect(children[0], true); + return; + } + const next = channel.channel_next; + if (next) { + this.onSelect(next, true); + return; + } + let parent = channel.parent_channel(); + while (parent) { + const p_next = parent.channel_next; + if (p_next) { + this.onSelect(p_next, true); + return; + } + parent = parent.parent_channel(); + } + } + handle_key_press(event) { + if (!this.selected_event || !this.currently_selected || $.isArray(this.currently_selected)) + return; + if (event.keyCode == 38 /* ArrowUp */) { + event.preventDefault(); + if (this.currently_selected instanceof ChannelEntry) { + let previous = this.currently_selected.channel_previous; + if (previous) { + while (true) { + const siblings = previous.children(); + if (siblings.length == 0) + break; + previous = siblings.last(); + } + const clients = previous.clients_ordered(); + if (clients.length > 0) { + this.onSelect(clients.last(), true); + return; + } + else { + this.onSelect(previous, true); + return; + } + } + else if (this.currently_selected.hasParent()) { + const channel = this.currently_selected.parent_channel(); + const clients = channel.clients_ordered(); + if (clients.length > 0) { + this.onSelect(clients.last(), true); + return; + } + else { + this.onSelect(channel, true); + return; + } + } + else + this.onSelect(this.server, true); + } + else if (this.currently_selected instanceof ClientEntry) { + const channel = this.currently_selected.currentChannel(); + const clients = channel.clients_ordered(); + const index = clients.indexOf(this.currently_selected); + if (index > 0) { + this.onSelect(clients[index - 1], true); + return; + } + this.onSelect(channel, true); + return; + } + } + else if (event.keyCode == 40 /* ArrowDown */) { + event.preventDefault(); + if (this.currently_selected instanceof ChannelEntry) { + this.select_next_channel(this.currently_selected, true); + } + else if (this.currently_selected instanceof ClientEntry) { + const channel = this.currently_selected.currentChannel(); + const clients = channel.clients_ordered(); + const index = clients.indexOf(this.currently_selected); + if (index + 1 < clients.length) { + this.onSelect(clients[index + 1], true); + return; + } + this.select_next_channel(channel, false); + } + else if (this.currently_selected instanceof ServerEntry) + this.onSelect(this.channel_first, true); + } + else if (event.keyCode == 13 /* Enter */) { + if (this.currently_selected instanceof ChannelEntry) { + this.currently_selected.joinChannel(); + } + } + } + toggle_server_queries(flag) { + if (this._show_queries == flag) + return; + this._show_queries = flag; + const channels = []; + for (const client of this.clients) + if (client.properties.client_type == ClientType.CLIENT_QUERY) { + if (this._show_queries) + client.tag.show(); + else + client.tag.hide(); + if (channels.indexOf(client.currentChannel()) == -1) + channels.push(client.currentChannel()); + } + } + get_first_channel() { + return this.channel_first; + } +} +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["151ae612934d91357c22d60a4d6af0e9c521ac18c46cbfa0f9d312cf353292a3"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["151ae612934d91357c22d60a4d6af0e9c521ac18c46cbfa0f9d312cf353292a3"] = "151ae612934d91357c22d60a4d6af0e9c521ac18c46cbfa0f9d312cf353292a3"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of []) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +/// +if (typeof (customElements) !== "undefined") { + try { + class X_Properties extends HTMLElement { + } + class X_Property extends HTMLElement { + } + customElements.define('x-properties', X_Properties, { extends: 'div' }); + customElements.define('x-property', X_Property, { extends: 'div' }); + } + catch (error) { + console.warn("failed to define costum elements"); + } +} +class StaticSettings { + static get instance() { + if (!this._instance) + this._instance = new StaticSettings(true); + return this._instance; + } + static transformStO(input, _default) { + if (typeof input === "undefined") + return _default; + if (typeof _default === "string") + return input; + else if (typeof _default === "number") + return parseInt(input); + else if (typeof _default === "boolean") + return (input == "1" || input == "true"); + else if (typeof _default === "undefined") + return input; + return JSON.parse(input); + } + static transformOtS(input) { + if (typeof input === "string") + return input; + else if (typeof input === "number") + return input.toString(); + else if (typeof input === "boolean") + return input ? "1" : "0"; + else if (typeof input === "undefined") + return undefined; + return JSON.stringify(input); + } + constructor(_reserved = undefined) { + if (_reserved && !StaticSettings._instance) { + this._staticPropsTag = $("#properties"); + this.initializeStatic(); + } + else { + this._handle = StaticSettings.instance; + } + } + initializeStatic() { + location.search.substr(1).split("&").forEach(part => { + let item = part.split("="); + $("") + .attr("key", item[0]) + .attr("value", item[1]) + .appendTo(this._staticPropsTag); + }); + } + static(key, _default) { + if (this._handle) + return this._handle.static(key, _default); + let result = this._staticPropsTag.find("[key='" + key + "']"); + return StaticSettings.transformStO(result.length > 0 ? decodeURIComponent(result.last().attr("value")) : undefined, _default); + } + deleteStatic(key) { + if (this._handle) { + this._handle.deleteStatic(key); + return; + } + let result = this._staticPropsTag.find("[key='" + key + "']"); + if (result.length != 0) + result.detach(); + } +} +class Settings extends StaticSettings { + constructor() { + super(); + this.cacheGlobal = {}; + this.cacheServer = {}; + this.updated = false; + this.cacheGlobal = JSON.parse(localStorage.getItem("settings.global")); + if (!this.cacheGlobal) + this.cacheGlobal = {}; + this.saveWorker = setInterval(() => { + if (this.updated) + this.save(); + }, 5 * 1000); + } + static_global(key, _default) { + let _static = this.static(key); + if (_static) + return StaticSettings.transformStO(_static, _default); + return this.global(key, _default); + } + global(key, _default) { + let result = this.cacheGlobal[key]; + return StaticSettings.transformStO(result, _default); + } + server(key, _default) { + let result = this.cacheServer[key]; + return StaticSettings.transformStO(result, _default); + } + changeGlobal(key, value) { + if (this.cacheGlobal[key] == value) + return; + this.updated = true; + this.cacheGlobal[key] = StaticSettings.transformOtS(value); + if (Settings.UPDATE_DIRECT) + this.save(); + } + changeServer(key, value) { + if (this.cacheServer[key] == value) + return; + this.updated = true; + this.cacheServer[key] = StaticSettings.transformOtS(value); + if (Settings.UPDATE_DIRECT) + this.save(); + } + setServer(server) { + if (this.currentServer) { + this.save(); + this.cacheServer = {}; + this.currentServer = undefined; + } + this.currentServer = server; + if (this.currentServer) { + let serverId = this.currentServer.properties.virtualserver_unique_identifier; + this.cacheServer = JSON.parse(localStorage.getItem("settings.server_" + serverId)); + if (!this.cacheServer) + this.cacheServer = {}; + } + } + save() { + this.updated = false; + if (this.currentServer) { + let serverId = this.currentServer.properties.virtualserver_unique_identifier; + let server = JSON.stringify(this.cacheServer); + localStorage.setItem("settings.server_" + serverId, server); + } + let global = JSON.stringify(this.cacheGlobal); + localStorage.setItem("settings.global", global); + } +} +Settings.KEY_DISABLE_CONTEXT_MENU = "disableContextMenu"; +Settings.KEY_DISABLE_UNLOAD_DIALOG = "disableUnloadDialog"; +Settings.UPDATE_DIRECT = true; +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["5d36be1b22073610ea6ef1da2b21930a0adbcf36af90d5700bd24d85808d3fe6"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["5d36be1b22073610ea6ef1da2b21930a0adbcf36af90d5700bd24d85808d3fe6"] = "5d36be1b22073610ea6ef1da2b21930a0adbcf36af90d5700bd24d85808d3fe6"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of []) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +/* +Copyright (C) 2011 Patrick Gillespie, http://patorjk.com/ + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +/* + Extendible BBCode Parser v1.0.0 + By Patrick Gillespie (patorjk@gmail.com) + Website: http://patorjk.com/ + + This module allows you to parse BBCode and to extend to the mark-up language + to add in your own tags. +*/ +var XBBCODE; +(function (XBBCODE) { + // ----------------------------------------------------------------------------- + // Set up private variables + // ----------------------------------------------------------------------------- + const urlPattern = /^(?:https?|file|c):(?:\/{1,3}|\\{1})[-a-zA-Z0-9:;,@#%&()~_?\+=\/\\\.]*$/, colorNamePattern = /^(?:aliceblue|antiquewhite|aqua|aquamarine|azure|beige|bisque|black|blanchedalmond|blue|blueviolet|brown|burlywood|cadetblue|chartreuse|chocolate|coral|cornflowerblue|cornsilk|crimson|cyan|darkblue|darkcyan|darkgoldenrod|darkgray|darkgreen|darkkhaki|darkmagenta|darkolivegreen|darkorange|darkorchid|darkred|darksalmon|darkseagreen|darkslateblue|darkslategray|darkturquoise|darkviolet|deeppink|deepskyblue|dimgray|dodgerblue|firebrick|floralwhite|forestgreen|fuchsia|gainsboro|ghostwhite|gold|goldenrod|gray|green|greenyellow|honeydew|hotpink|indianred|indigo|ivory|khaki|lavender|lavenderblush|lawngreen|lemonchiffon|lightblue|lightcoral|lightcyan|lightgoldenrodyellow|lightgray|lightgreen|lightpink|lightsalmon|lightseagreen|lightskyblue|lightslategray|lightsteelblue|lightyellow|lime|limegreen|linen|magenta|maroon|mediumaquamarine|mediumblue|mediumorchid|mediumpurple|mediumseagreen|mediumslateblue|mediumspringgreen|mediumturquoise|mediumvioletred|midnightblue|mintcream|mistyrose|moccasin|navajowhite|navy|oldlace|olive|olivedrab|orange|orangered|orchid|palegoldenrod|palegreen|paleturquoise|palevioletred|papayawhip|peachpuff|peru|pink|plum|powderblue|purple|red|rosybrown|royalblue|saddlebrown|salmon|sandybrown|seagreen|seashell|sienna|silver|skyblue|slateblue|slategray|snow|springgreen|steelblue|tan|teal|thistle|tomato|turquoise|violet|wheat|white|whitesmoke|yellow|yellowgreen)$/, colorCodePattern = /^#?[a-fA-F0-9]{6}$/, emailPattern = /[^\s@]+@[^\s@]+\.[^\s@]+/, fontFacePattern = /^([a-z][a-z0-9_]+|"[a-z][a-z0-9_\s]+")$/i; + let tagList, tagsNoParseList = [], bbRegExp, pbbRegExp, pbbRegExp2, openTags, closeTags; + /* ----------------------------------------------------------------------------- + * _tags + * This object contains a list of _tags that your code will be able to understand. + * Each tag object has the following properties: + * + * openTag - A function that takes in the tag's parameters (if any) and its + * contents, and returns what its HTML open tag should be. + * Example: [color=red]test[/color] would take in "=red" as a + * parameter input, and "test" as a content input. + * It should be noted that any BBCode inside of "content" will have + * been processed by the time it enter the openTag function. + * + * closeTag - A function that takes in the tag's parameters (if any) and its + * contents, and returns what its HTML close tag should be. + * + * displayContent - Defaults to true. If false, the content for the tag will + * not be displayed. This is useful for _tags like IMG where + * its contents are actually a parameter input. + * + * restrictChildrenTo - A list of BBCode _tags which are allowed to be nested + * within this BBCode tag. If this property is omitted, + * any BBCode tag may be nested within the tag. + * + * restrictParentsTo - A list of BBCode _tags which are allowed to be parents of + * this BBCode tag. If this property is omitted, any BBCode + * tag may be a parent of the tag. + * + * noParse - true or false. If true, none of the content WITHIN this tag will be + * parsed by the XBBCode parser. + * + * + * + * LIMITIONS on adding NEW TAGS: + * - Tag names should be alphanumeric (including underscores) and all _tags should have an opening tag + * and a closing tag. + * The [*] tag is an exception because it was already a standard + * bbcode tag. Technecially _tags don't *have* to be alphanumeric, but since + * regular expressions are used to parse the text, if you use a non-alphanumeric + * tag names, just make sure the tag name gets escaped properly (if needed). + * --------------------------------------------------------------------------- */ + let _tags = { + "b": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + } + }, + /* + This tag does nothing and is here mostly to be used as a classification for + the bbcode input when evaluating parent-child tag relationships + */ + "bbcode": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + } + }, + "center": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + } + }, + "code": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + }, + noParse: true + }, + "color": { + openTag: function (params, content) { + params = params || ''; + var colorCode = (params.substr(1)).toLowerCase() || "black"; + colorNamePattern.lastIndex = 0; + colorCodePattern.lastIndex = 0; + if (!colorNamePattern.test(colorCode)) { + if (!colorCodePattern.test(colorCode)) { + colorCode = "black"; + } + else { + if (colorCode.substr(0, 1) !== "#") { + colorCode = "#" + colorCode; + } + } + } + return ''; + }, + closeTag: function (params, content) { + return ''; + } + }, + "email": { + openTag: function (params, content) { + var myEmail; + if (!params) { + myEmail = content.replace(/<.*?>/g, ""); + } + else { + myEmail = params.substr(1); + } + emailPattern.lastIndex = 0; + if (!emailPattern.test(myEmail)) { + return ''; + } + return ''; + }, + closeTag: function (params, content) { + return ''; + } + }, + "face": { + openTag: function (params, content) { + params = params || ''; + var faceCode = params.substr(1) || "inherit"; + fontFacePattern.lastIndex = 0; + if (!fontFacePattern.test(faceCode)) { + faceCode = "inherit"; + } + return ''; + }, + closeTag: function (params, content) { + return ''; + } + }, + "font": { + openTag: function (params, content) { + params = params || ''; + var faceCode = params.substr(1) || "inherit"; + fontFacePattern.lastIndex = 0; + if (!fontFacePattern.test(faceCode)) { + faceCode = "inherit"; + } + return ''; + }, + closeTag: function (params, content) { + return ''; + } + }, + "i": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + } + }, + "img": { + openTag: function (params, content) { + var myUrl = content; + urlPattern.lastIndex = 0; + if (!urlPattern.test(myUrl)) { + myUrl = ""; + } + return ''; + }, + closeTag: function (params, content) { + return ''; + }, + displayContent: false + }, + "justify": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + } + }, + "large": { + openTag: function (params, content) { + params = params || ''; + var colorCode = params.substr(1) || "inherit"; + colorNamePattern.lastIndex = 0; + colorCodePattern.lastIndex = 0; + if (!colorNamePattern.test(colorCode)) { + if (!colorCodePattern.test(colorCode)) { + colorCode = "inherit"; + } + else { + if (colorCode.substr(0, 1) !== "#") { + colorCode = "#" + colorCode; + } + } + } + return ''; + }, + closeTag: function (params, content) { + return ''; + } + }, + "left": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + } + }, + "li": { + openTag: function (params, content) { + return "
  • "; + }, + closeTag: function (params, content) { + return "
  • "; + }, + restrictParentsTo: ["list", "ul", "ol"] + }, + "list": { + openTag: function (params, content) { + return '
      '; + }, + closeTag: function (params, content) { + return '
    '; + }, + restrictChildrenTo: ["*", "li"] + }, + "noparse": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + }, + noParse: true + }, + "ol": { + openTag: function (params, content) { + return '
      '; + }, + closeTag: function (params, content) { + return '
    '; + }, + restrictChildrenTo: ["*", "li"] + }, + "php": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + }, + noParse: true + }, + "quote": { + openTag: function (params, content) { + return '
    '; + }, + closeTag: function (params, content) { + return '
    '; + } + }, + "right": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + } + }, + "s": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + } + }, + "size": { + openTag: function (params, content) { + params = params || ''; + var mySize = parseInt(params.substr(1), 10) || 0; + if (mySize < 4 || mySize > 40) { + mySize = 14; + } + return ''; + }, + closeTag: function (params, content) { + return ''; + } + }, + "small": { + openTag: function (params, content) { + params = params || ''; + var colorCode = params.substr(1) || "inherit"; + colorNamePattern.lastIndex = 0; + colorCodePattern.lastIndex = 0; + if (!colorNamePattern.test(colorCode)) { + if (!colorCodePattern.test(colorCode)) { + colorCode = "inherit"; + } + else { + if (colorCode.substr(0, 1) !== "#") { + colorCode = "#" + colorCode; + } + } + } + return ''; + }, + closeTag: function (params, content) { + return ''; + } + }, + "sub": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + } + }, + "sup": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + } + }, + "table": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return '
    '; + }, + restrictChildrenTo: ["tbody", "thead", "tfoot", "tr"] + }, + "tbody": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + }, + restrictChildrenTo: ["tr"], + restrictParentsTo: ["table"] + }, + "tfoot": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + }, + restrictChildrenTo: ["tr"], + restrictParentsTo: ["table"] + }, + "thead": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + }, + restrictChildrenTo: ["tr"], + restrictParentsTo: ["table"] + }, + "td": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + }, + restrictParentsTo: ["tr"] + }, + "th": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + }, + restrictParentsTo: ["tr"] + }, + "tr": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + }, + restrictChildrenTo: ["td", "th"], + restrictParentsTo: ["table", "tbody", "tfoot", "thead"] + }, + "u": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + } + }, + "ul": { + openTag: function (params, content) { + return '
      '; + }, + closeTag: function (params, content) { + return '
    '; + }, + restrictChildrenTo: ["*", "li"] + }, + "url": { + openTag: function (params, content) { + let myUrl; + if (!params) { + myUrl = content.replace(/<.*?>/g, ""); + } + else { + myUrl = params.substr(1); + } + urlPattern.lastIndex = 0; + if (!urlPattern.test(myUrl)) { + myUrl = "#"; + } + return ''; + }, + closeTag: function (params, content) { + return ''; + } + }, + "hr": { + openTag: (params, content) => { + return "
    "; + }, + closeTag: (params, content) => { + return ""; + } + }, + /* + The [*] tag is special since the user does not define a closing [/*] tag when writing their bbcode. + Instead this module parses the code and adds the closing [/*] tag in for them. None of the _tags you + add will act like this and this tag is an exception to the others. + */ + "*": { + openTag: function (params, content) { + return "
  • "; + }, + closeTag: function (params, content) { + return "
  • "; + }, + restrictParentsTo: ["list", "ul", "ol"] + } + }; + // create tag list and lookup fields + function initTags() { + tagList = []; + let prop, ii, len; + for (prop in _tags) { + if (_tags.hasOwnProperty(prop)) { + if (prop === "*") { + tagList.push("\\" + prop); + } + else { + tagList.push(prop); + if (_tags[prop].noParse) { + tagsNoParseList.push(prop); + } + } + _tags[prop].validChildLookup = {}; + _tags[prop].validParentLookup = {}; + _tags[prop].restrictParentsTo = _tags[prop].restrictParentsTo || []; + _tags[prop].restrictChildrenTo = _tags[prop].restrictChildrenTo || []; + len = _tags[prop].restrictChildrenTo.length; + for (ii = 0; ii < len; ii++) { + _tags[prop].validChildLookup[_tags[prop].restrictChildrenTo[ii]] = true; + } + len = _tags[prop].restrictParentsTo.length; + for (ii = 0; ii < len; ii++) { + _tags[prop].validParentLookup[_tags[prop].restrictParentsTo[ii]] = true; + } + } + } + bbRegExp = new RegExp("]*?)?>((?:.|[\\r\\n])*?)", "gi"); + pbbRegExp = new RegExp("\\[(" + tagList.join("|") + ")([ =][^\\]]*?)?\\]([^\\[]*?)\\[/\\1\\]", "gi"); + pbbRegExp2 = new RegExp("\\[(" + tagsNoParseList.join("|") + ")([ =][^\\]]*?)?\\]([\\s\\S]*?)\\[/\\1\\]", "gi"); + // create the regex for escaping ['s that aren't apart of _tags + (function () { + var closeTagList = []; + for (var ii = 0; ii < tagList.length; ii++) { + if (tagList[ii] !== "\\*") { // the * tag doesn't have an offical closing tag + closeTagList.push("/" + tagList[ii]); + } + } + openTags = new RegExp("(\\[)((?:" + tagList.join("|") + ")(?:[ =][^\\]]*?)?)(\\])", "gi"); + closeTags = new RegExp("(\\[)(" + closeTagList.join("|") + ")(\\])", "gi"); + })(); + } + initTags(); + // ----------------------------------------------------------------------------- + // private functions + // ----------------------------------------------------------------------------- + function checkParentChildRestrictions(parentTag, bbcode, bbcodeLevel, tagName, tagParams, tagContents, errQueue) { + errQueue = errQueue || []; + bbcodeLevel++; + // get a list of all of the child _tags to this tag + var reTagNames = new RegExp("(])", "gi"), reTagNamesParts = new RegExp("(])", "i"), matchingTags = tagContents.match(reTagNames) || [], cInfo, errStr, ii, childTag, pInfo = _tags[parentTag] || {}; + reTagNames.lastIndex = 0; + if (!matchingTags) { + tagContents = ""; + } + for (ii = 0; ii < matchingTags.length; ii++) { + reTagNamesParts.lastIndex = 0; + childTag = (matchingTags[ii].match(reTagNamesParts))[2].toLowerCase(); + if (pInfo && pInfo.restrictChildrenTo && pInfo.restrictChildrenTo.length > 0) { + if (!pInfo.validChildLookup[childTag]) { + errStr = "The tag \"" + childTag + "\" is not allowed as a child of the tag \"" + parentTag + "\"."; + errQueue.push(errStr); + } + } + cInfo = _tags[childTag] || {}; + if (cInfo.restrictParentsTo.length > 0) { + if (!cInfo.validParentLookup[parentTag]) { + errStr = "The tag \"" + parentTag + "\" is not allowed as a parent of the tag \"" + childTag + "\"."; + errQueue.push(errStr); + } + } + } + tagContents = tagContents.replace(bbRegExp, function (matchStr, bbcodeLevel, tagName, tagParams, tagContents) { + errQueue = checkParentChildRestrictions(tagName.toLowerCase(), matchStr, bbcodeLevel, tagName, tagParams, tagContents, errQueue); + return matchStr; + }); + return errQueue; + } + /* + This function updates or adds a piece of metadata to each tag called "bbcl" which + indicates how deeply nested a particular tag was in the bbcode. This property is removed + from the HTML code _tags at the end of the processing. + */ + function updateTagDepths(tagContents) { + tagContents = tagContents.replace(/\<([^\>][^\>]*?)\>/gi, function (matchStr, subMatchStr) { + var bbCodeLevel = subMatchStr.match(/^bbcl=([0-9]+) /); + if (bbCodeLevel === null) { + return ""; + } + else { + return "<" + subMatchStr.replace(/^(bbcl=)([0-9]+)/, function (matchStr, m1, m2) { + return m1 + (parseInt(m2, 10) + 1); + }) + ">"; + } + }); + return tagContents; + } + /* + This function removes the metadata added by the updateTagDepths function + */ + function unprocess(tagContent) { + return tagContent.replace(//gi, "").replace(//gi, "]"); + } + var replaceFunct = function (matchStr, bbcodeLevel, tagName, tagParams, tagContents) { + tagName = tagName.toLowerCase(); + var processedContent = _tags[tagName].noParse ? unprocess(tagContents) : tagContents.replace(bbRegExp, replaceFunct), openTag = _tags[tagName].openTag(tagParams, processedContent), closeTag = _tags[tagName].closeTag(tagParams, processedContent); + if (_tags[tagName].displayContent === false) { + processedContent = ""; + } + return openTag + processedContent + closeTag; + }; + function parse(config) { + var output = config.text; + output = output.replace(bbRegExp, replaceFunct); + return output; + } + /* + The star tag [*] is special in that it does not use a closing tag. Since this parser requires that _tags to have a closing + tag, we must pre-process the input and add in closing _tags [/*] for the star tag. + We have a little levaridge in that we know the text we're processing wont contain the <> characters (they have been + changed into their HTML entity form to prevent XSS and code injection), so we can use those characters as markers to + help us define boundaries and figure out where to place the [/*] _tags. + */ + function fixStarTag(text) { + text = text.replace(/\[(?!\*[ =\]]|list([ =][^\]]*)?\]|\/list[\]])/ig, "<"); + text = text.replace(/\[(?=list([ =][^\]]*)?\]|\/list[\]])/ig, ">"); + while (text !== (text = text.replace(/>list([ =][^\]]*)?\]([^>]*?)(>\/list])/gi, function (matchStr, contents, endTag) { + var innerListTxt = matchStr; + while (innerListTxt !== (innerListTxt = innerListTxt.replace(/\[\*\]([^\[]*?)(\[\*\]|>\/list])/i, function (matchStr, contents, endTag) { + if (endTag.toLowerCase() === ">/list]") { + endTag = "/g, "<"); + return innerListTxt; + }))) + ; + // add ['s for our _tags back in + text = text.replace(/"); + return updateTagDepths(matchStr); + }))) + ; + return text; + } + // ----------------------------------------------------------------------------- + // public functions + // ----------------------------------------------------------------------------- + // API, Expose all available _tags + function tags() { + return _tags; + } + XBBCODE.tags = tags; + ; + function addTags(...tags) { + for (const tag of tags) + _tags[tag.tag] = tag.function; + initTags(); + } + XBBCODE.addTags = addTags; + ; + class ProcessResult { + } + XBBCODE.ProcessResult = ProcessResult; + function process(config) { + let result = new ProcessResult(); + result.errorQueue = []; + config.text = config.text.replace(//g, ">"); // escape HTML tag brackets + config.text = config.text.replace(openTags, function (matchStr, openB, contents, closeB) { + return "<" + contents + ">"; + }); + config.text = config.text.replace(closeTags, function (matchStr, openB, contents, closeB) { + return "<" + contents + ">"; + }); + config.text = config.text.replace(/\[/g, "["); // escape ['s that aren't apart of _tags + config.text = config.text.replace(/\]/g, "]"); // escape ['s that aren't apart of _tags + config.text = config.text.replace(//g, "]"); // escape ['s that aren't apart of _tags + // process _tags that don't have their content parsed + while (config.text !== (config.text = config.text.replace(pbbRegExp2, function (matchStr, tagName, tagParams, tagContents) { + tagContents = tagContents.replace(/\[/g, "["); + tagContents = tagContents.replace(/\]/g, "]"); + tagParams = tagParams || ""; + tagContents = tagContents || ""; + return "[" + tagName + tagParams + "]" + tagContents + "[/" + tagName + "]"; + }))) + ; + config.text = fixStarTag(config.text); // add in closing _tags for the [*] tag + config.text = config.text.replace(/\[hr](?!.*\[\/hr])/gmi, "[hr][/hr]"); /* fix hr tag */ + config.text = addBbcodeLevels(config.text); // add in level metadata + result.errorQueue = checkParentChildRestrictions("bbcode", config.text, -1, "", "", config.text); + result.html = parse(config); + if (result.html.indexOf("[") !== -1 || result.html.indexOf("]") !== -1) { + result.errorQueue.push("Some _tags appear to be misaligned."); + } + if (config.removeMisalignedTags) { + result.html = result.html.replace(/\[.*?\]/g, ""); + } + if (config.addInLineBreaks) { + result.html = '
    ' + result.html + '
    '; + } + if (!config.escapeHtml) { + result.html = result.html.replace("[", "["); // put ['s back in + result.html = result.html.replace("]", "]"); // put ['s back in + } + if (result.errorQueue.length == 0) { + result.error = false; + result.errorQueue = undefined; + } + else { + result.error = true; + } + return result; + } + XBBCODE.process = process; + ; +})(XBBCODE || (XBBCODE = {})); +// for node +if (typeof module !== "undefined") { + module.exports = XBBCODE; +} +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["7b297ca7625a51ff8c0e02125b8afcc7469dbd2971f36884c9d121b9f3df9433"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["7b297ca7625a51ff8c0e02125b8afcc7469dbd2971f36884c9d121b9f3df9433"] = "7b297ca7625a51ff8c0e02125b8afcc7469dbd2971f36884c9d121b9f3df9433"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "sYG_CjvV", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/SelectedItemInfo.ts (95,21)" }, { name: "foGudfH1", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/SelectedItemInfo.ts (143,30)" }, { name: "XUKsV23g", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/SelectedItemInfo.ts (172,30)" }, { name: "AqbuoGOP", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/SelectedItemInfo.ts (183,23)" }, { name: "MxJZzPra", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/SelectedItemInfo.ts (436,49)" }, { name: "olQ_3zdj", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/SelectedItemInfo.ts (438,60)" }, { name: "LqrvULtX", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/SelectedItemInfo.ts (446,69)" }, { name: "EscvNJt1", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/SelectedItemInfo.ts (466,54)" }, { name: "O7zlMfzk", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/SelectedItemInfo.ts (466,112)" }, { name: "YQnthsII", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/SelectedItemInfo.ts (479,54)" }, { name: "xB8wZniv", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/SelectedItemInfo.ts (479,113)" }, { name: "aNEaYUft", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/SelectedItemInfo.ts (491,50)" }, { name: "Fdt8TwbH", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/SelectedItemInfo.ts (491,108)" }, { name: "nf70fBUO", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/SelectedItemInfo.ts (514,50)" }, { name: "rpDxx1_J", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/SelectedItemInfo.ts (514,83)" }, { name: "KS3oJM_V", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/SelectedItemInfo.ts (523,50)" }, { name: "c_RawLvr", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/SelectedItemInfo.ts (523,81)" }, { name: "DT6FshRi", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/SelectedItemInfo.ts (535,50)" }, { name: "kL1M5jAc", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/SelectedItemInfo.ts (535,77)" }, { name: "LkHqtJYO", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/SelectedItemInfo.ts (537,50)" }, { name: "vBpIbVBl", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/SelectedItemInfo.ts (537,83)" }, { name: "TIA5kbb9", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/SelectedItemInfo.ts (700,25)" }, { name: "w6veI4_R", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/SelectedItemInfo.ts (701,25)" }, { name: "PzHxNyIZ", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/SelectedItemInfo.ts (702,25)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +/// +/// +class InfoManagerBase { + constructor() { + this.timers = []; + this.intervals = []; + } + resetTimers() { + for (let timer of this.timers) + clearTimeout(timer); + this.timers = []; + } + resetIntervals() { + for (let interval of this.intervals) + clearInterval(interval); + this.intervals = []; + } + registerTimer(timer) { + this.timers.push(timer); + } + registerInterval(interval) { + this.intervals.push(interval); + } +} +class InfoManager extends InfoManagerBase { + createFrame(handle, object, html_tag) { + this.handle = handle; + } + finalizeFrame(object, frame) { + this.resetIntervals(); + this.resetTimers(); + this.handle = undefined; + } + triggerUpdate() { + if (this.handle) + this.handle.update(); + } +} +class InfoBar { + constructor(client, htmlTag) { + this._current_manager = undefined; + this.managers = []; + this.handle = client; + this._htmlTag = htmlTag; + this._tag_info = htmlTag.find(".container-select-info"); + this._tag_banner = htmlTag.find(".container-banner"); + this.managers.push(new MusicInfoManager()); + this.managers.push(new ClientInfoManager()); + this.managers.push(new ChannelInfoManager()); + this.managers.push(new ServerInfoManager()); + this.banner_manager = new Hostbanner(client, this._tag_banner); + } + setCurrentSelected(entry) { + if (this.current_selected == entry) + return; + if (this._current_manager) { + this._current_manager.finalizeFrame(this.current_selected, this._tag_info); + this._current_manager = null; + this.current_selected = null; + } + this._tag_info.empty(); + this.current_selected = entry; + for (let manager of this.managers) { + if (manager.available(this.current_selected)) { + this._current_manager = manager; + break; + } + } + console.log(_translations.sYG_CjvV || (_translations.sYG_CjvV = tr("Using info manager: %o")), this._current_manager); + if (this._current_manager) + this._current_manager.createFrame(this, this.current_selected, this._tag_info); + } + get currentSelected() { + return this.current_selected; + } + update() { + if (this._current_manager && this.current_selected) + this._current_manager.updateFrame(this.current_selected, this._tag_info); + } + update_banner() { + this.banner_manager.update(); + } + current_manager() { return this._current_manager; } + html_tag() { return this._htmlTag; } +} +class Hostbanner { + constructor(client, htmlTag) { + this.client = client; + this.html_tag = htmlTag; + } + update() { + if (this.updater) { + clearTimeout(this.updater); + this.updater = undefined; + } + const tag = this.generate_tag(); + if (tag) { + tag.then(element => { + this.html_tag.empty(); + this.html_tag.append(element).removeClass("disabled"); + }).catch(error => { + console.warn(_translations.foGudfH1 || (_translations.foGudfH1 = tr("Failed to load hostbanner: %o")), error); + this.html_tag.empty().addClass("disabled"); + }); + } + else { + this.html_tag.empty().addClass("disabled"); + } + } + generate_tag() { + if (!this.client.connected) + return undefined; + const server = this.client.channelTree.server; + if (!server) + return undefined; + if (!server.properties.virtualserver_hostbanner_gfx_url) + return undefined; + let properties = {}; + for (let key in server.properties) + properties["property_" + key] = server.properties[key]; + if (server.properties.virtualserver_hostbanner_gfx_interval > 0) { + const update_interval = Math.min(server.properties.virtualserver_hostbanner_gfx_interval, 60); + const update_timestamp = (Math.floor((Date.now() / 1000) / update_interval) * update_interval).toString(); + try { + const url = new URL(server.properties.virtualserver_hostbanner_gfx_url); + if (url.search.length == 0) + properties["cache_tag"] = "?_ts=" + update_timestamp; + else + properties["cache_tag"] = "&_ts=" + update_timestamp; + } + catch (error) { + console.warn(_translations.XUKsV23g || (_translations.XUKsV23g = tr("Failed to parse banner URL: %o")), error); + properties["cache_tag"] = "&_ts=" + update_timestamp; + } + this.updater = setTimeout(() => this.update(), update_interval * 1000); + } + else { + properties["cache_tag"] = ""; + } + const rendered = $("#tmpl_selected_hostbanner").renderTag(properties); + console.debug(_translations.AqbuoGOP || (_translations.AqbuoGOP = tr("Hostbanner has been loaded"))); + return Promise.resolve(rendered); + /* + const image = rendered.find("img"); + return new Promise>((resolve, reject) => { + const node_image = image[0] as HTMLImageElement; + node_image.onload = () => { + console.debug(tr("Hostbanner has been loaded")); + if(server.properties.virtualserver_hostbanner_gfx_interval > 0) + this.updater = setTimeout(() => this.update(), Math.min(server.properties.virtualserver_hostbanner_gfx_interval, 60) * 1000); + resolve(rendered); + }; + node_image.onerror = event => { + reject(event); + } + }); + */ + } +} +class ClientInfoManager extends InfoManager { + available(object) { + return typeof object == "object" && object instanceof ClientEntry; + } + createFrame(handle, client, html_tag) { + super.createFrame(handle, client, html_tag); + client.updateClientVariables(); + this.updateFrame(client, html_tag); + } + updateFrame(client, html_tag) { + this.resetIntervals(); + html_tag.empty(); + let properties = this.buildProperties(client); + let rendered = $("#tmpl_selected_client").renderTag(properties); + html_tag.append(rendered); + this.registerInterval(setInterval(() => { + html_tag.find(".update_onlinetime").text(formatDate(client.calculateOnlineTime())); + }, 1000)); + } + buildProperties(client) { + let properties = {}; + properties["client_name"] = client.createChatTag()[0]; + properties["client_onlinetime"] = formatDate(client.calculateOnlineTime()); + properties["sound_volume"] = client.audioController.volume * 100; + properties["client_is_query"] = client.properties.client_type == ClientType.CLIENT_QUERY; + properties["group_server"] = []; + for (let groupId of client.assignedServerGroupIds()) { + let group = client.channelTree.client.groups.serverGroup(groupId); + if (!group) + continue; + let group_property = {}; + group_property["group_id"] = groupId; + group_property["group_name"] = group.name; + properties["group_server"].push(group_property); + properties["group_" + groupId + "_icon"] = client.channelTree.client.fileManager.icons.generateTag(group.properties.iconid); + } + let group = client.channelTree.client.groups.channelGroup(client.assignedChannelGroup()); + if (group) { + properties["group_channel"] = group.id; + properties["group_" + group.id + "_name"] = group.name; + properties["group_" + group.id + "_icon"] = client.channelTree.client.fileManager.icons.generateTag(group.properties.iconid); + } + for (let key in client.properties) + properties["property_" + key] = client.properties[key]; + if (client.properties.client_teaforum_id > 0) { + properties["teaspeak_forum"] = $.spawn("a") + .attr("href", "//forum.teaspeak.de/index.php?members/" + client.properties.client_teaforum_id) + .attr("target", "_blank") + .text(client.properties.client_teaforum_id); + } + if (client.properties.client_flag_avatar && client.properties.client_flag_avatar.length > 0) { + properties["client_avatar"] = client.channelTree.client.fileManager.avatars.generateTag(client); + } + return properties; + } +} +class ServerInfoManager extends InfoManager { + createFrame(handle, server, html_tag) { + super.createFrame(handle, server, html_tag); + if (server.shouldUpdateProperties()) + server.updateProperties(); + this.updateFrame(server, html_tag); + } + updateFrame(server, html_tag) { + this.resetIntervals(); + html_tag.empty(); + let properties = {}; + properties["server_name"] = $.spawn("a").text(server.properties.virtualserver_name); + properties["server_onlinetime"] = formatDate(server.calculateUptime()); + properties["server_address"] = server.remote_address.host + ":" + server.remote_address.port; + for (let key in server.properties) + properties["property_" + key] = server.properties[key]; + let rendered = $("#tmpl_selected_server").renderTag([properties]); + this.registerInterval(setInterval(() => { + html_tag.find(".update_onlinetime").text(formatDate(server.calculateUptime())); + }, 1000)); + { + let requestUpdate = rendered.find(".btn_update"); + requestUpdate.prop("disabled", !server.shouldUpdateProperties()); + requestUpdate.click(() => { + server.updateProperties(); + this.triggerUpdate(); + }); + this.registerTimer(setTimeout(function () { + requestUpdate.prop("disabled", false); + }, server.nextInfoRequest - Date.now())); + } + html_tag.append(rendered); + } + available(object) { + return typeof object == "object" && object instanceof ServerEntry; + } +} +class ChannelInfoManager extends InfoManager { + createFrame(handle, channel, html_tag) { + super.createFrame(handle, channel, html_tag); + this.updateFrame(channel, html_tag); + } + updateFrame(channel, html_tag) { + this.resetIntervals(); + html_tag.empty(); + let properties = {}; + properties["channel_name"] = channel.generate_tag(false); + properties["channel_type"] = ChannelType.normalize(channel.channelType()); + properties["channel_clients"] = channel.channelTree.clientsByChannel(channel).length; + properties["channel_subscribed"] = true; //TODO + properties["server_encryption"] = channel.channelTree.server.properties.virtualserver_codec_encryption_mode; + for (let key in channel.properties) + properties["property_" + key] = channel.properties[key]; + let tag_channel_description = $.spawn("div"); + properties["bbcode_channel_description"] = tag_channel_description; + channel.getChannelDescription().then(description => { + let result = XBBCODE.process({ + text: description, + escapeHtml: true, + addInLineBreaks: true + }); + if (result.error) { + console.log("BBCode parse error: %o", result.errorQueue); + } + tag_channel_description.html(result.html) + .css("overflow-y", "auto") + .css("flex-grow", "1"); + }); + let rendered = $("#tmpl_selected_channel").renderTag([properties]); + html_tag.append(rendered); + } + available(object) { + return typeof object == "object" && object instanceof ChannelEntry; + } +} +function format_time(time) { + let hours = 0, minutes = 0, seconds = 0; + if (time >= 60 * 60) { + hours = Math.floor(time / (60 * 60)); + time -= hours * 60 * 60; + } + if (time >= 60) { + minutes = Math.floor(time / 60); + time -= minutes * 60; + } + seconds = time; + if (hours > 9) + hours = hours.toString(); + else if (hours > 0) + hours = '0' + hours.toString(); + else + hours = ''; + if (minutes > 9) + minutes = minutes.toString(); + else if (minutes > 0) + minutes = '0' + minutes.toString(); + else + minutes = '00'; + if (seconds > 9) + seconds = seconds.toString(); + else if (seconds > 0) + seconds = '0' + seconds.toString(); + else + seconds = '00'; + return (hours ? hours + ":" : "") + minutes + ':' + seconds; +} +var MusicPlayerState; +(function (MusicPlayerState) { + MusicPlayerState[MusicPlayerState["SLEEPING"] = 0] = "SLEEPING"; + MusicPlayerState[MusicPlayerState["LOADING"] = 1] = "LOADING"; + MusicPlayerState[MusicPlayerState["PLAYING"] = 2] = "PLAYING"; + MusicPlayerState[MusicPlayerState["PAUSED"] = 3] = "PAUSED"; + MusicPlayerState[MusicPlayerState["STOPPED"] = 4] = "STOPPED"; +})(MusicPlayerState || (MusicPlayerState = {})); +class MusicInfoManager extends ClientInfoManager { + createFrame(handle, channel, html_tag) { + super.createFrame(handle, channel, html_tag); + this.updateFrame(channel, html_tag); + } + updateFrame(bot, html_tag) { + if (this.single_handler) { + this.handle.handle.serverConnection.command_handler_boss().remove_single_handler(this.single_handler); + this.single_handler = undefined; + } + this.resetIntervals(); + html_tag.empty(); + let properties = super.buildProperties(bot); + { //Render info frame + if (bot.properties.player_state < MusicPlayerState.PLAYING) { + properties["music_player"] = $("#tmpl_music_frame_empty").renderTag().css("align-self", "center"); + } + else { + let frame = $.spawn("div").text(_translations.MxJZzPra || (_translations.MxJZzPra = tr("loading..."))); + properties["music_player"] = frame; + properties["song_url"] = $.spawn("a").text(_translations.olQ_3zdj || (_translations.olQ_3zdj = tr("loading..."))); + bot.requestPlayerInfo().then(info => { + let timestamp = Date.now(); + console.log(info); + let _frame = $("#tmpl_music_frame").renderTag({ + song_name: info.player_title ? info.player_title : + info.song_url ? info.song_url : _translations.LqrvULtX || (_translations.LqrvULtX = tr("No title or url")), + song_url: info.song_url, + thumbnail: info.song_thumbnail && info.song_thumbnail.length > 0 ? info.song_thumbnail : undefined + }).css("align-self", "center"); + properties["song_url"].text(info.song_url); + frame.replaceWith(_frame); + frame = _frame; + /* Play/Pause logic */ + { + let button_play = frame.find(".button_play"); + let button_pause = frame.find(".button_pause"); + let button_stop = frame.find('.button_stop'); + button_play.click(handler => { + if (!button_play.hasClass("active")) { + this.handle.handle.serverConnection.send_command("musicbotplayeraction", { + bot_id: bot.properties.client_database_id, + action: 1 + }).then(updated => this.triggerUpdate()).catch(error => { + createErrorModal(_translations.EscvNJt1 || (_translations.EscvNJt1 = tr("Failed to execute play")), MessageHelper.formatMessage(_translations.O7zlMfzk || (_translations.O7zlMfzk = tr("Failed to execute play.
    {}")), error)).open(); + this.triggerUpdate(); + }); + } + button_pause.show(); + button_play.hide(); + }); + button_pause.click(handler => { + if (!button_pause.hasClass("active")) { + this.handle.handle.serverConnection.send_command("musicbotplayeraction", { + bot_id: bot.properties.client_database_id, + action: 2 + }).then(updated => this.triggerUpdate()).catch(error => { + createErrorModal(_translations.YQnthsII || (_translations.YQnthsII = tr("Failed to execute pause")), MessageHelper.formatMessage(_translations.xB8wZniv || (_translations.xB8wZniv = tr("Failed to execute pause.
    {}")), error)).open(); + this.triggerUpdate(); + }); + } + button_play.show(); + button_pause.hide(); + }); + button_stop.click(handler => { + this.handle.handle.serverConnection.send_command("musicbotplayeraction", { + bot_id: bot.properties.client_database_id, + action: 0 + }).then(updated => this.triggerUpdate()).catch(error => { + createErrorModal(_translations.aNEaYUft || (_translations.aNEaYUft = tr("Failed to execute stop")), MessageHelper.formatMessage(_translations.Fdt8TwbH || (_translations.Fdt8TwbH = tr("Failed to execute stop.
    {}")), error)).open(); + this.triggerUpdate(); + }); + }); + if (bot.properties.player_state == 2) { + button_play.hide(); + button_pause.show(); + } + else if (bot.properties.player_state == 3) { + button_pause.hide(); + button_play.show(); + } + else if (bot.properties.player_state == 4) { + button_pause.hide(); + button_play.show(); + } + } + { /* Button functions */ + _frame.find(".btn-forward").click(() => { + this.handle.handle.serverConnection.send_command("musicbotplayeraction", { + bot_id: bot.properties.client_database_id, + action: 3 + }).then(updated => this.triggerUpdate()).catch(error => { + createErrorModal(_translations.nf70fBUO || (_translations.nf70fBUO = tr("Failed to execute forward")), (_translations.rpDxx1_J || (_translations.rpDxx1_J = tr("Failed to execute pause.
    {}"))).format(error)).open(); + this.triggerUpdate(); + }); + }); + _frame.find(".btn-rewind").click(() => { + this.handle.handle.serverConnection.send_command("musicbotplayeraction", { + bot_id: bot.properties.client_database_id, + action: 4 + }).then(updated => this.triggerUpdate()).catch(error => { + createErrorModal(_translations.KS3oJM_V || (_translations.KS3oJM_V = tr("Failed to execute rewind")), (_translations.c_RawLvr || (_translations.c_RawLvr = tr("Failed to execute pause.
    {}"))).format(error)).open(); + this.triggerUpdate(); + }); + }); + _frame.find(".btn-settings").click(() => { + this.handle.handle.serverConnection.command_helper.request_playlist_list().then(lists => { + for (const entry of lists) { + if (entry.playlist_id == bot.properties.client_playlist_id) { + Modals.spawnPlaylistEdit(bot.channelTree.client, entry); + return; + } + } + createErrorModal(_translations.DT6FshRi || (_translations.DT6FshRi = tr("Invalid permissions")), _translations.kL1M5jAc || (_translations.kL1M5jAc = tr("You don't have to see the bots playlist."))).open(); + }).catch(error => { + createErrorModal(_translations.LkHqtJYO || (_translations.LkHqtJYO = tr("Failed to query playlist.")), _translations.vBpIbVBl || (_translations.vBpIbVBl = tr("Failed to query playlist info."))).open(); + }); + }); + } + /* Required flip card javascript */ + frame.find(".right").mouseenter(() => { + frame.find(".controls-overlay").addClass("flipped"); + }); + frame.find(".right").mouseleave(() => { + frame.find(".controls-overlay").removeClass("flipped"); + }); + /* Slider */ + frame.find(".timeline .slider").on('mousedown', ev => { + let timeline = frame.find(".timeline"); + let time = frame.find(".time"); + let slider = timeline.find(".slider"); + let slider_old = slider.css("margin-left"); + let time_max = parseInt(timeline.attr("time-max")); + slider.prop("editing", true); + let target_timestamp = 0; + let move_handler = (event) => { + let max = timeline.width(); + let current = event.pageX - timeline.offset().left - slider.width() / 2; + if (current < 0) + current = 0; + else if (current > max) + current = max; + target_timestamp = current / max * time_max; + time.text(format_time(Math.floor(target_timestamp / 1000))); + slider.css("margin-left", current / max * 100 + "%"); + }; + let finish_handler = event => { + console.log("Event (%i | %s): %o", event.button, event.type, event); + if (event.type == "mousedown" && event.button != 2) + return; + $(document).unbind("mousemove", move_handler); + $(document).unbind("mouseup mouseleave mousedown", finish_handler); + if (event.type != "mousedown") { + slider.prop("editing", false); + slider.prop("edited", true); + let current_timestamp = info.player_replay_index + Date.now() - timestamp; + this.handle.handle.serverConnection.send_command("musicbotplayeraction", { + bot_id: bot.properties.client_database_id, + action: current_timestamp > target_timestamp ? 6 : 5, + units: current_timestamp < target_timestamp ? target_timestamp - current_timestamp : current_timestamp - target_timestamp + }).then(() => this.triggerUpdate()).catch(error => { + slider.prop("edited", false); + }); + } + else { //Restore old + event.preventDefault(); + slider.css("margin-left", slider_old + "%"); + } + }; + $(document).on('mousemove', move_handler); + $(document).on('mouseup mouseleave mousedown', finish_handler); + ev.preventDefault(); + return false; + }); + { + frame.find(".timeline").attr("time-max", info.player_max_index); + let timeline = frame.find(".timeline"); + let time_bar = timeline.find(".played"); + let buffered_bar = timeline.find(".buffered"); + let slider = timeline.find(".slider"); + let player_time = _frame.find(".player_time"); + let update_handler = (played, buffered) => { + let time_index = played || info.player_replay_index + (bot.properties.player_state == 2 ? Date.now() - timestamp : 0); + let buffered_index = buffered || 0; + time_bar.css("width", time_index / info.player_max_index * 100 + "%"); + buffered_bar.css("width", buffered_index / info.player_max_index * 100 + "%"); + if (!slider.prop("editing") && !slider.prop("edited")) { + player_time.text(format_time(Math.floor(time_index / 1000))); + slider.css("margin-left", time_index / info.player_max_index * 100 + "%"); + } + }; + let interval = setInterval(update_handler, 1000); + this.registerInterval(interval); + update_handler(); + /* register subscription */ + this.handle.handle.serverConnection.send_command("musicbotsetsubscription", { bot_id: bot.properties.client_database_id }).catch(error => { + console.error("Failed to subscribe to displayed music bot! Using pseudo timeline"); + }).then(() => { + clearInterval(interval); + }); + this.single_handler = { + command: "notifymusicstatusupdate", + function: command => { + const json = command.arguments[0]; + update_handler(parseInt(json["player_replay_index"]), parseInt(json["player_buffered_index"])); + return false; /* do not unregister me! */ + } + }; + this.handle.handle.serverConnection.command_handler_boss().register_single_handler(this.single_handler); + } + }); + } + const player = properties["music_player"]; + const player_transformer = $.spawn("div").append(player); + player_transformer.css({ + 'display': 'block', + //'width': "100%", + 'height': '100%' + }); + properties["music_player"] = player_transformer; + } + let rendered = $("#tmpl_selected_music").renderTag([properties]); + html_tag.append(rendered); + { + const player = properties["music_player"]; + const player_width = 400; //player.width(); + const player_height = 400; //player.height(); + const parent = player.parent(); + parent.css({ + 'flex-grow': 1, + 'display': 'flex', + 'flex-direction': 'row', + 'justify-content': 'space-around', + }); + const padding = 14; + const scale_x = Math.min((parent.width() - padding) / player_width, 1.5); + const scale_y = Math.min((parent.height() - padding) / player_height, 1.5); + let scale = Math.min(scale_x, scale_y); + let translate_x = 50, translate_y = 50; + if (scale_x == scale_y && scale_x == scale) { + //Equal scale + } + else if (scale_x == scale) { + //We scale on the x-Axis + //We have to adjust the y-Axis + } + else { + //We scale on the y-Axis + //We have to adjust the x-Axis + } + //1 => 0 | 0 + //1.5 => 0 | 25 + //0.5 => 0 | -25 + //const translate_x = scale_x != scale ? 0 : undefined || 50 - (50 * ((parent.width() - padding) / player_width)); + //const translate_y = scale_y != scale || scale_y > 1 ? 0 : undefined || 50 - (50 * ((parent.height() - padding) / player_height)); + const transform = ("translate(0%, " + (scale * 50 - 50) + "%) scale(" + scale.toPrecision(2) + ")"); + console.log(_translations.TIA5kbb9 || (_translations.TIA5kbb9 = tr("Parents: %o | %o")), parent.width(), parent.height()); + console.log(_translations.w6veI4_R || (_translations.w6veI4_R = tr("Player: %o | %o")), player_width, player_height); + console.log(_translations.PzHxNyIZ || (_translations.PzHxNyIZ = tr("Scale: %f => translate: %o | %o")), scale, translate_x, translate_y); + player.css({ + transform: transform + }); + console.log("Transform: " + transform); + } + this.registerInterval(setInterval(() => { + html_tag.find(".update_onlinetime").text(formatDate(bot.calculateOnlineTime())); + }, 1000)); + } + update_local_volume(volume) { + this.handle.html_tag().find(".property-volume-local").text(Math.floor(volume * 100) + "%"); + } + update_remote_volume(volume) { + this.handle.html_tag().find(".property-volume-remote").text(Math.floor(volume * 100) + "%"); + } + available(object) { + return typeof object == "object" && object instanceof MusicClientEntry; + } + finalizeFrame(object, frame) { + if (this.single_handler) { + this.handle.handle.serverConnection.command_handler_boss().remove_single_handler(this.single_handler); + this.single_handler = undefined; + } + super.finalizeFrame(object, frame); + } +} +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["91941f6d856c806ef067a7da7d0f4da6489c18d3d9e6ea5633cb70445364127a"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["91941f6d856c806ef067a7da7d0f4da6489c18d3d9e6ea5633cb70445364127a"] = "91941f6d856c806ef067a7da7d0f4da6489c18d3d9e6ea5633cb70445364127a"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "yRMsT8NR", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/ConnectionBase.ts (100,30)" }, { name: "ARnxHcil", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/ConnectionBase.ts (129,35)" }, { name: "voFFeV9H", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/ConnectionBase.ts (141,35)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +var connection; +(function (connection_1) { + connection_1.CommandOptionDefaults = { + flagset: [], + process_result: true, + timeout: 1000 + }; + class AbstractServerConnection { + constructor(client) { + this.client = client; + this.command_helper = new connection_1.CommandHelper(this); + } + } + connection_1.AbstractServerConnection = AbstractServerConnection; + class AbstractVoiceConnection { + constructor(connection) { + this.connection = connection; + } + } + connection_1.AbstractVoiceConnection = AbstractVoiceConnection; + class ServerCommand { + } + connection_1.ServerCommand = ServerCommand; + class AbstractCommandHandler { + constructor(connection) { + this.volatile_handler_boss = false; /* if true than the command handler could be registered twice to two or more handlers */ + this.ignore_consumed = false; + this.connection = connection; + } + } + connection_1.AbstractCommandHandler = AbstractCommandHandler; + class AbstractCommandHandlerBoss { + constructor(connection) { + this.command_handlers = []; + /* TODO: Timeout */ + this.single_command_handler = []; + this.connection = connection; + } + register_handler(handler) { + if (!handler.volatile_handler_boss && handler.handler_boss) + throw "handler already registered"; + this.command_handlers.remove(handler); /* just to be sure */ + this.command_handlers.push(handler); + handler.handler_boss = this; + } + unregister_handler(handler) { + if (!handler.volatile_handler_boss && handler.handler_boss !== this) { + console.warn(_translations.yRMsT8NR || (_translations.yRMsT8NR = tr("Tried to unregister command handler which does not belong to the handler boss"))); + return; + } + this.command_handlers.remove(handler); + handler.handler_boss = undefined; + } + register_single_handler(handler) { + this.single_command_handler.push(handler); + } + remove_single_handler(handler) { + this.single_command_handler.remove(handler); + } + handlers() { + return this.command_handlers; + } + invoke_handle(command) { + let flag_consumed = false; + for (const handler of this.command_handlers) { + try { + if (!flag_consumed || handler.ignore_consumed) + flag_consumed = flag_consumed || handler.handle_command(command); + } + catch (error) { + console.error(_translations.ARnxHcil || (_translations.ARnxHcil = tr("Failed to invoke command handler. Invocation results in an exception: %o")), error); + } + } + for (const handler of [...this.single_command_handler]) { + if (handler.command && handler.command != command.command) + continue; + try { + if (handler.function(command)) + this.single_command_handler.remove(handler); + } + catch (error) { + console.error(_translations.voFFeV9H || (_translations.voFFeV9H = tr("Failed to invoke single command handler. Invocation results in an exception: %o")), error); + } + } + return flag_consumed; + } + } + connection_1.AbstractCommandHandlerBoss = AbstractCommandHandlerBoss; +})(connection || (connection = {})); +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["03b9f2276efe385ded09171572780068a757abad97b3501693214ccae5963ef4"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["03b9f2276efe385ded09171572780068a757abad97b3501693214ccae5963ef4"] = "03b9f2276efe385ded09171572780068a757abad97b3501693214ccae5963ef4"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "l6YeuZJB", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/permission/PermissionManager.ts (386,44)" }, { name: "hiRWWQk0", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/permission/PermissionManager.ts (480,51)" }, { name: "KvTloMLv", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/permission/PermissionManager.ts (552,75)" }, { name: "MSzE2M5g", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/permission/PermissionManager.ts (559,30)" }, { name: "Icp51Xyn", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/permission/PermissionManager.ts (573,23)" }, { name: "JCXF8tNn", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/permission/PermissionManager.ts (578,43)" }, { name: "xW3OtQsi", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/permission/PermissionManager.ts (587,47)" }, { name: "gqaXY6XV", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/permission/PermissionManager.ts (596,75)" }, { name: "GQx2LqqU", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/permission/PermissionManager.ts (612,55)" }, { name: "TU9ekKrB", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/permission/PermissionManager.ts (641,43)" }, { name: "ODK68n4X", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/permission/PermissionManager.ts (650,44)" }, { name: "REzpKcHE", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/permission/PermissionManager.ts (770,44)" }, { name: "cFseHpLq", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/permission/PermissionManager.ts (773,47)" }, { name: "q7zQFaQp", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/permission/PermissionManager.ts (795,27)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +/// +/// +var PermissionType; +(function (PermissionType) { + PermissionType["B_SERVERINSTANCE_HELP_VIEW"] = "b_serverinstance_help_view"; + PermissionType["B_SERVERINSTANCE_VERSION_VIEW"] = "b_serverinstance_version_view"; + PermissionType["B_SERVERINSTANCE_INFO_VIEW"] = "b_serverinstance_info_view"; + PermissionType["B_SERVERINSTANCE_VIRTUALSERVER_LIST"] = "b_serverinstance_virtualserver_list"; + PermissionType["B_SERVERINSTANCE_BINDING_LIST"] = "b_serverinstance_binding_list"; + PermissionType["B_SERVERINSTANCE_PERMISSION_LIST"] = "b_serverinstance_permission_list"; + PermissionType["B_SERVERINSTANCE_PERMISSION_FIND"] = "b_serverinstance_permission_find"; + PermissionType["B_VIRTUALSERVER_CREATE"] = "b_virtualserver_create"; + PermissionType["B_VIRTUALSERVER_DELETE"] = "b_virtualserver_delete"; + PermissionType["B_VIRTUALSERVER_START_ANY"] = "b_virtualserver_start_any"; + PermissionType["B_VIRTUALSERVER_STOP_ANY"] = "b_virtualserver_stop_any"; + PermissionType["B_VIRTUALSERVER_CHANGE_MACHINE_ID"] = "b_virtualserver_change_machine_id"; + PermissionType["B_VIRTUALSERVER_CHANGE_TEMPLATE"] = "b_virtualserver_change_template"; + PermissionType["B_SERVERQUERY_LOGIN"] = "b_serverquery_login"; + PermissionType["B_SERVERINSTANCE_TEXTMESSAGE_SEND"] = "b_serverinstance_textmessage_send"; + PermissionType["B_SERVERINSTANCE_LOG_VIEW"] = "b_serverinstance_log_view"; + PermissionType["B_SERVERINSTANCE_LOG_ADD"] = "b_serverinstance_log_add"; + PermissionType["B_SERVERINSTANCE_STOP"] = "b_serverinstance_stop"; + PermissionType["B_SERVERINSTANCE_MODIFY_SETTINGS"] = "b_serverinstance_modify_settings"; + PermissionType["B_SERVERINSTANCE_MODIFY_QUERYGROUP"] = "b_serverinstance_modify_querygroup"; + PermissionType["B_SERVERINSTANCE_MODIFY_TEMPLATES"] = "b_serverinstance_modify_templates"; + PermissionType["B_VIRTUALSERVER_SELECT"] = "b_virtualserver_select"; + PermissionType["B_VIRTUALSERVER_SELECT_GODMODE"] = "b_virtualserver_select_godmode"; + PermissionType["B_VIRTUALSERVER_INFO_VIEW"] = "b_virtualserver_info_view"; + PermissionType["B_VIRTUALSERVER_CONNECTIONINFO_VIEW"] = "b_virtualserver_connectioninfo_view"; + PermissionType["B_VIRTUALSERVER_CHANNEL_LIST"] = "b_virtualserver_channel_list"; + PermissionType["B_VIRTUALSERVER_CHANNEL_SEARCH"] = "b_virtualserver_channel_search"; + PermissionType["B_VIRTUALSERVER_CLIENT_LIST"] = "b_virtualserver_client_list"; + PermissionType["B_VIRTUALSERVER_CLIENT_SEARCH"] = "b_virtualserver_client_search"; + PermissionType["B_VIRTUALSERVER_CLIENT_DBLIST"] = "b_virtualserver_client_dblist"; + PermissionType["B_VIRTUALSERVER_CLIENT_DBSEARCH"] = "b_virtualserver_client_dbsearch"; + PermissionType["B_VIRTUALSERVER_CLIENT_DBINFO"] = "b_virtualserver_client_dbinfo"; + PermissionType["B_VIRTUALSERVER_PERMISSION_FIND"] = "b_virtualserver_permission_find"; + PermissionType["B_VIRTUALSERVER_CUSTOM_SEARCH"] = "b_virtualserver_custom_search"; + PermissionType["B_VIRTUALSERVER_START"] = "b_virtualserver_start"; + PermissionType["B_VIRTUALSERVER_STOP"] = "b_virtualserver_stop"; + PermissionType["B_VIRTUALSERVER_TOKEN_LIST"] = "b_virtualserver_token_list"; + PermissionType["B_VIRTUALSERVER_TOKEN_ADD"] = "b_virtualserver_token_add"; + PermissionType["B_VIRTUALSERVER_TOKEN_USE"] = "b_virtualserver_token_use"; + PermissionType["B_VIRTUALSERVER_TOKEN_DELETE"] = "b_virtualserver_token_delete"; + PermissionType["B_VIRTUALSERVER_LOG_VIEW"] = "b_virtualserver_log_view"; + PermissionType["B_VIRTUALSERVER_LOG_ADD"] = "b_virtualserver_log_add"; + PermissionType["B_VIRTUALSERVER_JOIN_IGNORE_PASSWORD"] = "b_virtualserver_join_ignore_password"; + PermissionType["B_VIRTUALSERVER_NOTIFY_REGISTER"] = "b_virtualserver_notify_register"; + PermissionType["B_VIRTUALSERVER_NOTIFY_UNREGISTER"] = "b_virtualserver_notify_unregister"; + PermissionType["B_VIRTUALSERVER_SNAPSHOT_CREATE"] = "b_virtualserver_snapshot_create"; + PermissionType["B_VIRTUALSERVER_SNAPSHOT_DEPLOY"] = "b_virtualserver_snapshot_deploy"; + PermissionType["B_VIRTUALSERVER_PERMISSION_RESET"] = "b_virtualserver_permission_reset"; + PermissionType["B_VIRTUALSERVER_MODIFY_NAME"] = "b_virtualserver_modify_name"; + PermissionType["B_VIRTUALSERVER_MODIFY_WELCOMEMESSAGE"] = "b_virtualserver_modify_welcomemessage"; + PermissionType["B_VIRTUALSERVER_MODIFY_MAXCLIENTS"] = "b_virtualserver_modify_maxclients"; + PermissionType["B_VIRTUALSERVER_MODIFY_RESERVED_SLOTS"] = "b_virtualserver_modify_reserved_slots"; + PermissionType["B_VIRTUALSERVER_MODIFY_PASSWORD"] = "b_virtualserver_modify_password"; + PermissionType["B_VIRTUALSERVER_MODIFY_DEFAULT_SERVERGROUP"] = "b_virtualserver_modify_default_servergroup"; + PermissionType["B_VIRTUALSERVER_MODIFY_DEFAULT_MUSICGROUP"] = "b_virtualserver_modify_default_musicgroup"; + PermissionType["B_VIRTUALSERVER_MODIFY_DEFAULT_CHANNELGROUP"] = "b_virtualserver_modify_default_channelgroup"; + PermissionType["B_VIRTUALSERVER_MODIFY_DEFAULT_CHANNELADMINGROUP"] = "b_virtualserver_modify_default_channeladmingroup"; + PermissionType["B_VIRTUALSERVER_MODIFY_CHANNEL_FORCED_SILENCE"] = "b_virtualserver_modify_channel_forced_silence"; + PermissionType["B_VIRTUALSERVER_MODIFY_COMPLAIN"] = "b_virtualserver_modify_complain"; + PermissionType["B_VIRTUALSERVER_MODIFY_ANTIFLOOD"] = "b_virtualserver_modify_antiflood"; + PermissionType["B_VIRTUALSERVER_MODIFY_FT_SETTINGS"] = "b_virtualserver_modify_ft_settings"; + PermissionType["B_VIRTUALSERVER_MODIFY_FT_QUOTAS"] = "b_virtualserver_modify_ft_quotas"; + PermissionType["B_VIRTUALSERVER_MODIFY_HOSTMESSAGE"] = "b_virtualserver_modify_hostmessage"; + PermissionType["B_VIRTUALSERVER_MODIFY_HOSTBANNER"] = "b_virtualserver_modify_hostbanner"; + PermissionType["B_VIRTUALSERVER_MODIFY_HOSTBUTTON"] = "b_virtualserver_modify_hostbutton"; + PermissionType["B_VIRTUALSERVER_MODIFY_PORT"] = "b_virtualserver_modify_port"; + PermissionType["B_VIRTUALSERVER_MODIFY_HOST"] = "b_virtualserver_modify_host"; + PermissionType["B_VIRTUALSERVER_MODIFY_DEFAULT_MESSAGES"] = "b_virtualserver_modify_default_messages"; + PermissionType["B_VIRTUALSERVER_MODIFY_AUTOSTART"] = "b_virtualserver_modify_autostart"; + PermissionType["B_VIRTUALSERVER_MODIFY_NEEDED_IDENTITY_SECURITY_LEVEL"] = "b_virtualserver_modify_needed_identity_security_level"; + PermissionType["B_VIRTUALSERVER_MODIFY_PRIORITY_SPEAKER_DIMM_MODIFICATOR"] = "b_virtualserver_modify_priority_speaker_dimm_modificator"; + PermissionType["B_VIRTUALSERVER_MODIFY_LOG_SETTINGS"] = "b_virtualserver_modify_log_settings"; + PermissionType["B_VIRTUALSERVER_MODIFY_MIN_CLIENT_VERSION"] = "b_virtualserver_modify_min_client_version"; + PermissionType["B_VIRTUALSERVER_MODIFY_ICON_ID"] = "b_virtualserver_modify_icon_id"; + PermissionType["B_VIRTUALSERVER_MODIFY_WEBLIST"] = "b_virtualserver_modify_weblist"; + PermissionType["B_VIRTUALSERVER_MODIFY_CODEC_ENCRYPTION_MODE"] = "b_virtualserver_modify_codec_encryption_mode"; + PermissionType["B_VIRTUALSERVER_MODIFY_TEMPORARY_PASSWORDS"] = "b_virtualserver_modify_temporary_passwords"; + PermissionType["B_VIRTUALSERVER_MODIFY_TEMPORARY_PASSWORDS_OWN"] = "b_virtualserver_modify_temporary_passwords_own"; + PermissionType["B_VIRTUALSERVER_MODIFY_CHANNEL_TEMP_DELETE_DELAY_DEFAULT"] = "b_virtualserver_modify_channel_temp_delete_delay_default"; + PermissionType["B_VIRTUALSERVER_MODIFY_MUSIC_BOT_LIMIT"] = "b_virtualserver_modify_music_bot_limit"; + PermissionType["I_CHANNEL_MIN_DEPTH"] = "i_channel_min_depth"; + PermissionType["I_CHANNEL_MAX_DEPTH"] = "i_channel_max_depth"; + PermissionType["B_CHANNEL_GROUP_INHERITANCE_END"] = "b_channel_group_inheritance_end"; + PermissionType["I_CHANNEL_PERMISSION_MODIFY_POWER"] = "i_channel_permission_modify_power"; + PermissionType["I_CHANNEL_NEEDED_PERMISSION_MODIFY_POWER"] = "i_channel_needed_permission_modify_power"; + PermissionType["B_CHANNEL_INFO_VIEW"] = "b_channel_info_view"; + PermissionType["B_CHANNEL_CREATE_CHILD"] = "b_channel_create_child"; + PermissionType["B_CHANNEL_CREATE_PERMANENT"] = "b_channel_create_permanent"; + PermissionType["B_CHANNEL_CREATE_SEMI_PERMANENT"] = "b_channel_create_semi_permanent"; + PermissionType["B_CHANNEL_CREATE_TEMPORARY"] = "b_channel_create_temporary"; + PermissionType["B_CHANNEL_CREATE_PRIVATE"] = "b_channel_create_private"; + PermissionType["B_CHANNEL_CREATE_WITH_TOPIC"] = "b_channel_create_with_topic"; + PermissionType["B_CHANNEL_CREATE_WITH_DESCRIPTION"] = "b_channel_create_with_description"; + PermissionType["B_CHANNEL_CREATE_WITH_PASSWORD"] = "b_channel_create_with_password"; + PermissionType["B_CHANNEL_CREATE_MODIFY_WITH_CODEC_SPEEX8"] = "b_channel_create_modify_with_codec_speex8"; + PermissionType["B_CHANNEL_CREATE_MODIFY_WITH_CODEC_SPEEX16"] = "b_channel_create_modify_with_codec_speex16"; + PermissionType["B_CHANNEL_CREATE_MODIFY_WITH_CODEC_SPEEX32"] = "b_channel_create_modify_with_codec_speex32"; + PermissionType["B_CHANNEL_CREATE_MODIFY_WITH_CODEC_CELTMONO48"] = "b_channel_create_modify_with_codec_celtmono48"; + PermissionType["B_CHANNEL_CREATE_MODIFY_WITH_CODEC_OPUSVOICE"] = "b_channel_create_modify_with_codec_opusvoice"; + PermissionType["B_CHANNEL_CREATE_MODIFY_WITH_CODEC_OPUSMUSIC"] = "b_channel_create_modify_with_codec_opusmusic"; + PermissionType["I_CHANNEL_CREATE_MODIFY_WITH_CODEC_MAXQUALITY"] = "i_channel_create_modify_with_codec_maxquality"; + PermissionType["I_CHANNEL_CREATE_MODIFY_WITH_CODEC_LATENCY_FACTOR_MIN"] = "i_channel_create_modify_with_codec_latency_factor_min"; + PermissionType["B_CHANNEL_CREATE_WITH_MAXCLIENTS"] = "b_channel_create_with_maxclients"; + PermissionType["B_CHANNEL_CREATE_WITH_MAXFAMILYCLIENTS"] = "b_channel_create_with_maxfamilyclients"; + PermissionType["B_CHANNEL_CREATE_WITH_SORTORDER"] = "b_channel_create_with_sortorder"; + PermissionType["B_CHANNEL_CREATE_WITH_DEFAULT"] = "b_channel_create_with_default"; + PermissionType["B_CHANNEL_CREATE_WITH_NEEDED_TALK_POWER"] = "b_channel_create_with_needed_talk_power"; + PermissionType["B_CHANNEL_CREATE_MODIFY_WITH_FORCE_PASSWORD"] = "b_channel_create_modify_with_force_password"; + PermissionType["I_CHANNEL_CREATE_MODIFY_WITH_TEMP_DELETE_DELAY"] = "i_channel_create_modify_with_temp_delete_delay"; + PermissionType["B_CHANNEL_MODIFY_PARENT"] = "b_channel_modify_parent"; + PermissionType["B_CHANNEL_MODIFY_MAKE_DEFAULT"] = "b_channel_modify_make_default"; + PermissionType["B_CHANNEL_MODIFY_MAKE_PERMANENT"] = "b_channel_modify_make_permanent"; + PermissionType["B_CHANNEL_MODIFY_MAKE_SEMI_PERMANENT"] = "b_channel_modify_make_semi_permanent"; + PermissionType["B_CHANNEL_MODIFY_MAKE_TEMPORARY"] = "b_channel_modify_make_temporary"; + PermissionType["B_CHANNEL_MODIFY_NAME"] = "b_channel_modify_name"; + PermissionType["B_CHANNEL_MODIFY_TOPIC"] = "b_channel_modify_topic"; + PermissionType["B_CHANNEL_MODIFY_DESCRIPTION"] = "b_channel_modify_description"; + PermissionType["B_CHANNEL_MODIFY_PASSWORD"] = "b_channel_modify_password"; + PermissionType["B_CHANNEL_MODIFY_CODEC"] = "b_channel_modify_codec"; + PermissionType["B_CHANNEL_MODIFY_CODEC_QUALITY"] = "b_channel_modify_codec_quality"; + PermissionType["B_CHANNEL_MODIFY_CODEC_LATENCY_FACTOR"] = "b_channel_modify_codec_latency_factor"; + PermissionType["B_CHANNEL_MODIFY_MAXCLIENTS"] = "b_channel_modify_maxclients"; + PermissionType["B_CHANNEL_MODIFY_MAXFAMILYCLIENTS"] = "b_channel_modify_maxfamilyclients"; + PermissionType["B_CHANNEL_MODIFY_SORTORDER"] = "b_channel_modify_sortorder"; + PermissionType["B_CHANNEL_MODIFY_NEEDED_TALK_POWER"] = "b_channel_modify_needed_talk_power"; + PermissionType["I_CHANNEL_MODIFY_POWER"] = "i_channel_modify_power"; + PermissionType["I_CHANNEL_NEEDED_MODIFY_POWER"] = "i_channel_needed_modify_power"; + PermissionType["B_CHANNEL_MODIFY_MAKE_CODEC_ENCRYPTED"] = "b_channel_modify_make_codec_encrypted"; + PermissionType["B_CHANNEL_MODIFY_TEMP_DELETE_DELAY"] = "b_channel_modify_temp_delete_delay"; + PermissionType["B_CHANNEL_DELETE_PERMANENT"] = "b_channel_delete_permanent"; + PermissionType["B_CHANNEL_DELETE_SEMI_PERMANENT"] = "b_channel_delete_semi_permanent"; + PermissionType["B_CHANNEL_DELETE_TEMPORARY"] = "b_channel_delete_temporary"; + PermissionType["B_CHANNEL_DELETE_FLAG_FORCE"] = "b_channel_delete_flag_force"; + PermissionType["I_CHANNEL_DELETE_POWER"] = "i_channel_delete_power"; + PermissionType["I_CHANNEL_NEEDED_DELETE_POWER"] = "i_channel_needed_delete_power"; + PermissionType["B_CHANNEL_JOIN_PERMANENT"] = "b_channel_join_permanent"; + PermissionType["B_CHANNEL_JOIN_SEMI_PERMANENT"] = "b_channel_join_semi_permanent"; + PermissionType["B_CHANNEL_JOIN_TEMPORARY"] = "b_channel_join_temporary"; + PermissionType["B_CHANNEL_JOIN_IGNORE_PASSWORD"] = "b_channel_join_ignore_password"; + PermissionType["B_CHANNEL_JOIN_IGNORE_MAXCLIENTS"] = "b_channel_join_ignore_maxclients"; + PermissionType["B_CHANNEL_IGNORE_VIEW_POWER"] = "b_channel_ignore_view_power"; + PermissionType["I_CHANNEL_JOIN_POWER"] = "i_channel_join_power"; + PermissionType["I_CHANNEL_NEEDED_JOIN_POWER"] = "i_channel_needed_join_power"; + PermissionType["B_CHANNEL_IGNORE_JOIN_POWER"] = "b_channel_ignore_join_power"; + PermissionType["I_CHANNEL_VIEW_POWER"] = "i_channel_view_power"; + PermissionType["I_CHANNEL_NEEDED_VIEW_POWER"] = "i_channel_needed_view_power"; + PermissionType["I_CHANNEL_SUBSCRIBE_POWER"] = "i_channel_subscribe_power"; + PermissionType["I_CHANNEL_NEEDED_SUBSCRIBE_POWER"] = "i_channel_needed_subscribe_power"; + PermissionType["I_CHANNEL_DESCRIPTION_VIEW_POWER"] = "i_channel_description_view_power"; + PermissionType["I_CHANNEL_NEEDED_DESCRIPTION_VIEW_POWER"] = "i_channel_needed_description_view_power"; + PermissionType["I_ICON_ID"] = "i_icon_id"; + PermissionType["I_MAX_ICON_FILESIZE"] = "i_max_icon_filesize"; + PermissionType["B_ICON_MANAGE"] = "b_icon_manage"; + PermissionType["B_GROUP_IS_PERMANENT"] = "b_group_is_permanent"; + PermissionType["I_GROUP_AUTO_UPDATE_TYPE"] = "i_group_auto_update_type"; + PermissionType["I_GROUP_AUTO_UPDATE_MAX_VALUE"] = "i_group_auto_update_max_value"; + PermissionType["I_GROUP_SORT_ID"] = "i_group_sort_id"; + PermissionType["I_GROUP_SHOW_NAME_IN_TREE"] = "i_group_show_name_in_tree"; + PermissionType["B_VIRTUALSERVER_SERVERGROUP_CREATE"] = "b_virtualserver_servergroup_create"; + PermissionType["B_VIRTUALSERVER_SERVERGROUP_LIST"] = "b_virtualserver_servergroup_list"; + PermissionType["B_VIRTUALSERVER_SERVERGROUP_PERMISSION_LIST"] = "b_virtualserver_servergroup_permission_list"; + PermissionType["B_VIRTUALSERVER_SERVERGROUP_CLIENT_LIST"] = "b_virtualserver_servergroup_client_list"; + PermissionType["B_VIRTUALSERVER_CHANNELGROUP_CREATE"] = "b_virtualserver_channelgroup_create"; + PermissionType["B_VIRTUALSERVER_CHANNELGROUP_LIST"] = "b_virtualserver_channelgroup_list"; + PermissionType["B_VIRTUALSERVER_CHANNELGROUP_PERMISSION_LIST"] = "b_virtualserver_channelgroup_permission_list"; + PermissionType["B_VIRTUALSERVER_CHANNELGROUP_CLIENT_LIST"] = "b_virtualserver_channelgroup_client_list"; + PermissionType["B_VIRTUALSERVER_CLIENT_PERMISSION_LIST"] = "b_virtualserver_client_permission_list"; + PermissionType["B_VIRTUALSERVER_CHANNEL_PERMISSION_LIST"] = "b_virtualserver_channel_permission_list"; + PermissionType["B_VIRTUALSERVER_CHANNELCLIENT_PERMISSION_LIST"] = "b_virtualserver_channelclient_permission_list"; + PermissionType["B_VIRTUALSERVER_PLAYLIST_PERMISSION_LIST"] = "b_virtualserver_playlist_permission_list"; + PermissionType["I_SERVER_GROUP_MODIFY_POWER"] = "i_server_group_modify_power"; + PermissionType["I_SERVER_GROUP_NEEDED_MODIFY_POWER"] = "i_server_group_needed_modify_power"; + PermissionType["I_SERVER_GROUP_MEMBER_ADD_POWER"] = "i_server_group_member_add_power"; + PermissionType["I_SERVER_GROUP_SELF_ADD_POWER"] = "i_server_group_self_add_power"; + PermissionType["I_SERVER_GROUP_NEEDED_MEMBER_ADD_POWER"] = "i_server_group_needed_member_add_power"; + PermissionType["I_SERVER_GROUP_MEMBER_REMOVE_POWER"] = "i_server_group_member_remove_power"; + PermissionType["I_SERVER_GROUP_SELF_REMOVE_POWER"] = "i_server_group_self_remove_power"; + PermissionType["I_SERVER_GROUP_NEEDED_MEMBER_REMOVE_POWER"] = "i_server_group_needed_member_remove_power"; + PermissionType["I_CHANNEL_GROUP_MODIFY_POWER"] = "i_channel_group_modify_power"; + PermissionType["I_CHANNEL_GROUP_NEEDED_MODIFY_POWER"] = "i_channel_group_needed_modify_power"; + PermissionType["I_CHANNEL_GROUP_MEMBER_ADD_POWER"] = "i_channel_group_member_add_power"; + PermissionType["I_CHANNEL_GROUP_SELF_ADD_POWER"] = "i_channel_group_self_add_power"; + PermissionType["I_CHANNEL_GROUP_NEEDED_MEMBER_ADD_POWER"] = "i_channel_group_needed_member_add_power"; + PermissionType["I_CHANNEL_GROUP_MEMBER_REMOVE_POWER"] = "i_channel_group_member_remove_power"; + PermissionType["I_CHANNEL_GROUP_SELF_REMOVE_POWER"] = "i_channel_group_self_remove_power"; + PermissionType["I_CHANNEL_GROUP_NEEDED_MEMBER_REMOVE_POWER"] = "i_channel_group_needed_member_remove_power"; + PermissionType["I_GROUP_MEMBER_ADD_POWER"] = "i_group_member_add_power"; + PermissionType["I_GROUP_NEEDED_MEMBER_ADD_POWER"] = "i_group_needed_member_add_power"; + PermissionType["I_GROUP_MEMBER_REMOVE_POWER"] = "i_group_member_remove_power"; + PermissionType["I_GROUP_NEEDED_MEMBER_REMOVE_POWER"] = "i_group_needed_member_remove_power"; + PermissionType["I_GROUP_MODIFY_POWER"] = "i_group_modify_power"; + PermissionType["I_GROUP_NEEDED_MODIFY_POWER"] = "i_group_needed_modify_power"; + PermissionType["I_PERMISSION_MODIFY_POWER"] = "i_permission_modify_power"; + PermissionType["B_PERMISSION_MODIFY_POWER_IGNORE"] = "b_permission_modify_power_ignore"; + PermissionType["B_VIRTUALSERVER_SERVERGROUP_DELETE"] = "b_virtualserver_servergroup_delete"; + PermissionType["B_VIRTUALSERVER_CHANNELGROUP_DELETE"] = "b_virtualserver_channelgroup_delete"; + PermissionType["I_CLIENT_PERMISSION_MODIFY_POWER"] = "i_client_permission_modify_power"; + PermissionType["I_CLIENT_NEEDED_PERMISSION_MODIFY_POWER"] = "i_client_needed_permission_modify_power"; + PermissionType["I_CLIENT_MAX_CLONES_UID"] = "i_client_max_clones_uid"; + PermissionType["I_CLIENT_MAX_CLONES_IP"] = "i_client_max_clones_ip"; + PermissionType["I_CLIENT_MAX_CLONES_HWID"] = "i_client_max_clones_hwid"; + PermissionType["I_CLIENT_MAX_IDLETIME"] = "i_client_max_idletime"; + PermissionType["I_CLIENT_MAX_AVATAR_FILESIZE"] = "i_client_max_avatar_filesize"; + PermissionType["I_CLIENT_MAX_CHANNEL_SUBSCRIPTIONS"] = "i_client_max_channel_subscriptions"; + PermissionType["I_CLIENT_MAX_CHANNELS"] = "i_client_max_channels"; + PermissionType["I_CLIENT_MAX_TEMPORARY_CHANNELS"] = "i_client_max_temporary_channels"; + PermissionType["I_CLIENT_MAX_SEMI_CHANNELS"] = "i_client_max_semi_channels"; + PermissionType["I_CLIENT_MAX_PERMANENT_CHANNELS"] = "i_client_max_permanent_channels"; + PermissionType["B_CLIENT_USE_PRIORITY_SPEAKER"] = "b_client_use_priority_speaker"; + PermissionType["B_CLIENT_SKIP_CHANNELGROUP_PERMISSIONS"] = "b_client_skip_channelgroup_permissions"; + PermissionType["B_CLIENT_FORCE_PUSH_TO_TALK"] = "b_client_force_push_to_talk"; + PermissionType["B_CLIENT_IGNORE_BANS"] = "b_client_ignore_bans"; + PermissionType["B_CLIENT_IGNORE_VPN"] = "b_client_ignore_vpn"; + PermissionType["B_CLIENT_IGNORE_ANTIFLOOD"] = "b_client_ignore_antiflood"; + PermissionType["B_CLIENT_ENFORCE_VALID_HWID"] = "b_client_enforce_valid_hwid"; + PermissionType["B_CLIENT_ALLOW_INVALID_PACKET"] = "b_client_allow_invalid_packet"; + PermissionType["B_CLIENT_ALLOW_INVALID_BADGES"] = "b_client_allow_invalid_badges"; + PermissionType["B_CLIENT_ISSUE_CLIENT_QUERY_COMMAND"] = "b_client_issue_client_query_command"; + PermissionType["B_CLIENT_USE_RESERVED_SLOT"] = "b_client_use_reserved_slot"; + PermissionType["B_CLIENT_USE_CHANNEL_COMMANDER"] = "b_client_use_channel_commander"; + PermissionType["B_CLIENT_REQUEST_TALKER"] = "b_client_request_talker"; + PermissionType["B_CLIENT_AVATAR_DELETE_OTHER"] = "b_client_avatar_delete_other"; + PermissionType["B_CLIENT_IS_STICKY"] = "b_client_is_sticky"; + PermissionType["B_CLIENT_IGNORE_STICKY"] = "b_client_ignore_sticky"; + PermissionType["B_CLIENT_MUSIC_CREATE_PERMANENT"] = "b_client_music_create_permanent"; + PermissionType["B_CLIENT_MUSIC_CREATE_SEMI_PERMANENT"] = "b_client_music_create_semi_permanent"; + PermissionType["B_CLIENT_MUSIC_CREATE_TEMPORARY"] = "b_client_music_create_temporary"; + PermissionType["B_CLIENT_MUSIC_MODIFY_PERMANENT"] = "b_client_music_modify_permanent"; + PermissionType["B_CLIENT_MUSIC_MODIFY_SEMI_PERMANENT"] = "b_client_music_modify_semi_permanent"; + PermissionType["B_CLIENT_MUSIC_MODIFY_TEMPORARY"] = "b_client_music_modify_temporary"; + PermissionType["I_CLIENT_MUSIC_CREATE_MODIFY_MAX_VOLUME"] = "i_client_music_create_modify_max_volume"; + PermissionType["I_CLIENT_MUSIC_LIMIT"] = "i_client_music_limit"; + PermissionType["I_CLIENT_MUSIC_NEEDED_DELETE_POWER"] = "i_client_music_needed_delete_power"; + PermissionType["I_CLIENT_MUSIC_DELETE_POWER"] = "i_client_music_delete_power"; + PermissionType["I_CLIENT_MUSIC_PLAY_POWER"] = "i_client_music_play_power"; + PermissionType["I_CLIENT_MUSIC_NEEDED_PLAY_POWER"] = "i_client_music_needed_play_power"; + PermissionType["I_CLIENT_MUSIC_MODIFY_POWER"] = "i_client_music_modify_power"; + PermissionType["I_CLIENT_MUSIC_NEEDED_MODIFY_POWER"] = "i_client_music_needed_modify_power"; + PermissionType["I_CLIENT_MUSIC_RENAME_POWER"] = "i_client_music_rename_power"; + PermissionType["I_CLIENT_MUSIC_NEEDED_RENAME_POWER"] = "i_client_music_needed_rename_power"; + PermissionType["B_PLAYLIST_CREATE"] = "b_playlist_create"; + PermissionType["I_PLAYLIST_VIEW_POWER"] = "i_playlist_view_power"; + PermissionType["I_PLAYLIST_NEEDED_VIEW_POWER"] = "i_playlist_needed_view_power"; + PermissionType["I_PLAYLIST_MODIFY_POWER"] = "i_playlist_modify_power"; + PermissionType["I_PLAYLIST_NEEDED_MODIFY_POWER"] = "i_playlist_needed_modify_power"; + PermissionType["I_PLAYLIST_PERMISSION_MODIFY_POWER"] = "i_playlist_permission_modify_power"; + PermissionType["I_PLAYLIST_NEEDED_PERMISSION_MODIFY_POWER"] = "i_playlist_needed_permission_modify_power"; + PermissionType["I_PLAYLIST_DELETE_POWER"] = "i_playlist_delete_power"; + PermissionType["I_PLAYLIST_NEEDED_DELETE_POWER"] = "i_playlist_needed_delete_power"; + PermissionType["I_PLAYLIST_SONG_ADD_POWER"] = "i_playlist_song_add_power"; + PermissionType["I_PLAYLIST_SONG_NEEDED_ADD_POWER"] = "i_playlist_song_needed_add_power"; + PermissionType["I_PLAYLIST_SONG_REMOVE_POWER"] = "i_playlist_song_remove_power"; + PermissionType["I_PLAYLIST_SONG_NEEDED_REMOVE_POWER"] = "i_playlist_song_needed_remove_power"; + PermissionType["B_CLIENT_INFO_VIEW"] = "b_client_info_view"; + PermissionType["B_CLIENT_PERMISSIONOVERVIEW_VIEW"] = "b_client_permissionoverview_view"; + PermissionType["B_CLIENT_PERMISSIONOVERVIEW_OWN"] = "b_client_permissionoverview_own"; + PermissionType["B_CLIENT_REMOTEADDRESS_VIEW"] = "b_client_remoteaddress_view"; + PermissionType["I_CLIENT_SERVERQUERY_VIEW_POWER"] = "i_client_serverquery_view_power"; + PermissionType["I_CLIENT_NEEDED_SERVERQUERY_VIEW_POWER"] = "i_client_needed_serverquery_view_power"; + PermissionType["B_CLIENT_CUSTOM_INFO_VIEW"] = "b_client_custom_info_view"; + PermissionType["B_CLIENT_MUSIC_CHANNEL_LIST"] = "b_client_music_channel_list"; + PermissionType["B_CLIENT_MUSIC_SERVER_LIST"] = "b_client_music_server_list"; + PermissionType["I_CLIENT_MUSIC_INFO"] = "i_client_music_info"; + PermissionType["I_CLIENT_MUSIC_NEEDED_INFO"] = "i_client_music_needed_info"; + PermissionType["I_CLIENT_KICK_FROM_SERVER_POWER"] = "i_client_kick_from_server_power"; + PermissionType["I_CLIENT_NEEDED_KICK_FROM_SERVER_POWER"] = "i_client_needed_kick_from_server_power"; + PermissionType["I_CLIENT_KICK_FROM_CHANNEL_POWER"] = "i_client_kick_from_channel_power"; + PermissionType["I_CLIENT_NEEDED_KICK_FROM_CHANNEL_POWER"] = "i_client_needed_kick_from_channel_power"; + PermissionType["I_CLIENT_BAN_POWER"] = "i_client_ban_power"; + PermissionType["I_CLIENT_NEEDED_BAN_POWER"] = "i_client_needed_ban_power"; + PermissionType["I_CLIENT_MOVE_POWER"] = "i_client_move_power"; + PermissionType["I_CLIENT_NEEDED_MOVE_POWER"] = "i_client_needed_move_power"; + PermissionType["I_CLIENT_COMPLAIN_POWER"] = "i_client_complain_power"; + PermissionType["I_CLIENT_NEEDED_COMPLAIN_POWER"] = "i_client_needed_complain_power"; + PermissionType["B_CLIENT_COMPLAIN_LIST"] = "b_client_complain_list"; + PermissionType["B_CLIENT_COMPLAIN_DELETE_OWN"] = "b_client_complain_delete_own"; + PermissionType["B_CLIENT_COMPLAIN_DELETE"] = "b_client_complain_delete"; + PermissionType["B_CLIENT_BAN_LIST"] = "b_client_ban_list"; + PermissionType["B_CLIENT_BAN_LIST_GLOBAL"] = "b_client_ban_list_global"; + PermissionType["B_CLIENT_BAN_TRIGGER_LIST"] = "b_client_ban_trigger_list"; + PermissionType["B_CLIENT_BAN_CREATE"] = "b_client_ban_create"; + PermissionType["B_CLIENT_BAN_CREATE_GLOBAL"] = "b_client_ban_create_global"; + PermissionType["B_CLIENT_BAN_NAME"] = "b_client_ban_name"; + PermissionType["B_CLIENT_BAN_IP"] = "b_client_ban_ip"; + PermissionType["B_CLIENT_BAN_HWID"] = "b_client_ban_hwid"; + PermissionType["B_CLIENT_BAN_EDIT"] = "b_client_ban_edit"; + PermissionType["B_CLIENT_BAN_EDIT_GLOBAL"] = "b_client_ban_edit_global"; + PermissionType["B_CLIENT_BAN_DELETE_OWN"] = "b_client_ban_delete_own"; + PermissionType["B_CLIENT_BAN_DELETE"] = "b_client_ban_delete"; + PermissionType["B_CLIENT_BAN_DELETE_OWN_GLOBAL"] = "b_client_ban_delete_own_global"; + PermissionType["B_CLIENT_BAN_DELETE_GLOBAL"] = "b_client_ban_delete_global"; + PermissionType["I_CLIENT_BAN_MAX_BANTIME"] = "i_client_ban_max_bantime"; + PermissionType["I_CLIENT_PRIVATE_TEXTMESSAGE_POWER"] = "i_client_private_textmessage_power"; + PermissionType["I_CLIENT_NEEDED_PRIVATE_TEXTMESSAGE_POWER"] = "i_client_needed_private_textmessage_power"; + PermissionType["B_CLIENT_EVEN_TEXTMESSAGE_SEND"] = "b_client_even_textmessage_send"; + PermissionType["B_CLIENT_SERVER_TEXTMESSAGE_SEND"] = "b_client_server_textmessage_send"; + PermissionType["B_CLIENT_CHANNEL_TEXTMESSAGE_SEND"] = "b_client_channel_textmessage_send"; + PermissionType["B_CLIENT_OFFLINE_TEXTMESSAGE_SEND"] = "b_client_offline_textmessage_send"; + PermissionType["I_CLIENT_TALK_POWER"] = "i_client_talk_power"; + PermissionType["I_CLIENT_NEEDED_TALK_POWER"] = "i_client_needed_talk_power"; + PermissionType["I_CLIENT_POKE_POWER"] = "i_client_poke_power"; + PermissionType["I_CLIENT_NEEDED_POKE_POWER"] = "i_client_needed_poke_power"; + PermissionType["B_CLIENT_SET_FLAG_TALKER"] = "b_client_set_flag_talker"; + PermissionType["I_CLIENT_WHISPER_POWER"] = "i_client_whisper_power"; + PermissionType["I_CLIENT_NEEDED_WHISPER_POWER"] = "i_client_needed_whisper_power"; + PermissionType["B_CLIENT_MODIFY_DESCRIPTION"] = "b_client_modify_description"; + PermissionType["B_CLIENT_MODIFY_OWN_DESCRIPTION"] = "b_client_modify_own_description"; + PermissionType["B_CLIENT_USE_BBCODE_ANY"] = "b_client_use_bbcode_any"; + PermissionType["B_CLIENT_USE_BBCODE_URL"] = "b_client_use_bbcode_url"; + PermissionType["B_CLIENT_USE_BBCODE_IMAGE"] = "b_client_use_bbcode_image"; + PermissionType["B_CLIENT_MODIFY_DBPROPERTIES"] = "b_client_modify_dbproperties"; + PermissionType["B_CLIENT_DELETE_DBPROPERTIES"] = "b_client_delete_dbproperties"; + PermissionType["B_CLIENT_CREATE_MODIFY_SERVERQUERY_LOGIN"] = "b_client_create_modify_serverquery_login"; + PermissionType["B_CLIENT_QUERY_CREATE"] = "b_client_query_create"; + PermissionType["B_CLIENT_QUERY_LIST"] = "b_client_query_list"; + PermissionType["B_CLIENT_QUERY_LIST_OWN"] = "b_client_query_list_own"; + PermissionType["B_CLIENT_QUERY_RENAME"] = "b_client_query_rename"; + PermissionType["B_CLIENT_QUERY_RENAME_OWN"] = "b_client_query_rename_own"; + PermissionType["B_CLIENT_QUERY_CHANGE_PASSWORD"] = "b_client_query_change_password"; + PermissionType["B_CLIENT_QUERY_CHANGE_OWN_PASSWORD"] = "b_client_query_change_own_password"; + PermissionType["B_CLIENT_QUERY_CHANGE_PASSWORD_GLOBAL"] = "b_client_query_change_password_global"; + PermissionType["B_CLIENT_QUERY_DELETE"] = "b_client_query_delete"; + PermissionType["B_CLIENT_QUERY_DELETE_OWN"] = "b_client_query_delete_own"; + PermissionType["B_FT_IGNORE_PASSWORD"] = "b_ft_ignore_password"; + PermissionType["B_FT_TRANSFER_LIST"] = "b_ft_transfer_list"; + PermissionType["I_FT_FILE_UPLOAD_POWER"] = "i_ft_file_upload_power"; + PermissionType["I_FT_NEEDED_FILE_UPLOAD_POWER"] = "i_ft_needed_file_upload_power"; + PermissionType["I_FT_FILE_DOWNLOAD_POWER"] = "i_ft_file_download_power"; + PermissionType["I_FT_NEEDED_FILE_DOWNLOAD_POWER"] = "i_ft_needed_file_download_power"; + PermissionType["I_FT_FILE_DELETE_POWER"] = "i_ft_file_delete_power"; + PermissionType["I_FT_NEEDED_FILE_DELETE_POWER"] = "i_ft_needed_file_delete_power"; + PermissionType["I_FT_FILE_RENAME_POWER"] = "i_ft_file_rename_power"; + PermissionType["I_FT_NEEDED_FILE_RENAME_POWER"] = "i_ft_needed_file_rename_power"; + PermissionType["I_FT_FILE_BROWSE_POWER"] = "i_ft_file_browse_power"; + PermissionType["I_FT_NEEDED_FILE_BROWSE_POWER"] = "i_ft_needed_file_browse_power"; + PermissionType["I_FT_DIRECTORY_CREATE_POWER"] = "i_ft_directory_create_power"; + PermissionType["I_FT_NEEDED_DIRECTORY_CREATE_POWER"] = "i_ft_needed_directory_create_power"; + PermissionType["I_FT_QUOTA_MB_DOWNLOAD_PER_CLIENT"] = "i_ft_quota_mb_download_per_client"; + PermissionType["I_FT_QUOTA_MB_UPLOAD_PER_CLIENT"] = "i_ft_quota_mb_upload_per_client"; +})(PermissionType || (PermissionType = {})); +class PermissionInfo { + is_boolean() { return this.name.startsWith("b_"); } + id_grant() { + return this.id | (1 << 15); + } +} +class PermissionGroup { +} +class GroupedPermissions { +} +class PermissionValue { + constructor(type, value) { + this.type = type; + this.value = value; + } + granted(requiredValue, required = true) { + let result; + result = this.value == -1 || this.value >= requiredValue || (this.value == -2 && requiredValue == -2 && !required); + log.trace(LogCategory.PERMISSIONS, _translations.l6YeuZJB || (_translations.l6YeuZJB = tr("Test needed required: %o | %i | %o => %o")), this, requiredValue, required, result); + return result; + } + hasValue() { + return typeof (this.value) !== "undefined" && this.value != -2; + } + hasGrant() { + return typeof (this.granted_value) !== "undefined" && this.granted_value != -2; + } +} +class NeededPermissionValue extends PermissionValue { + constructor(type, value) { + super(type, value); + this.changeListener = []; + } +} +class ChannelPermissionRequest { + constructor() { + this.callback_success = []; + this.callback_error = []; + } +} +class TeaPermissionRequest { +} +class PermissionManager extends connection.AbstractCommandHandler { + constructor(client) { + super(client.serverConnection); + this.permissionList = []; + this.permissionGroups = []; + this.neededPermissions = []; + this.requests_channel_permissions = []; + this.requests_client_permissions = []; + this.requests_client_channel_permissions = []; + this.requests_playlist_permissions = []; + this.initializedListener = []; + //FIXME? Dont register the handler like this? + this.volatile_handler_boss = true; + client.serverConnection.command_handler_boss().register_handler(this); + this.handle = client; + } + static parse_permission_bulk(json, manager) { + let permissions = []; + for (let perm of json) { + if (perm["permid"] === undefined) + continue; + let perm_id = parseInt(perm["permid"]); + let perm_grant = (perm_id & (1 << 15)) > 0; + if (perm_grant) + perm_id &= ~(1 << 15); + let perm_info = manager.resolveInfo(perm_id); + if (!perm_info) { + log.warn(LogCategory.PERMISSIONS, _translations.hiRWWQk0 || (_translations.hiRWWQk0 = tr("Got unknown permission id (%o/%o (%o))!")), perm["permid"], perm_id, perm["permsid"]); + return; + } + let permission; + for (let ref_perm of permissions) { + if (ref_perm.type == perm_info) { + permission = ref_perm; + break; + } + } + if (!permission) { + permission = new PermissionValue(perm_info, 0); + permission.granted_value = undefined; + permission.value = undefined; + permissions.push(permission); + } + if (perm_grant) { + permission.granted_value = parseInt(perm["permvalue"]); + } + else { + permission.value = parseInt(perm["permvalue"]); + permission.flag_negate = perm["permnegated"] == "1"; + permission.flag_skip = perm["permskip"] == "1"; + } + } + return permissions; + } + handle_command(command) { + switch (command.command) { + case "notifyclientneededpermissions": + this.onNeededPermissions(command.arguments); + return true; + case "notifypermissionlist": + this.onPermissionList(command.arguments); + return true; + case "notifychannelpermlist": + this.onChannelPermList(command.arguments); + return true; + case "notifyclientpermlist": + this.onClientPermList(command.arguments); + return true; + case "notifyplaylistpermlist": + this.onPlaylistPermList(command.arguments); + return true; + } + return false; + } + initialized() { + return this.permissionList.length > 0; + } + requestPermissionList() { + this.handle.serverConnection.send_command("permissionlist"); + } + onPermissionList(json) { + this.permissionList = []; + this.permissionGroups = []; + this._group_mapping = PermissionManager.group_mapping.slice(); + let group = log.group(log.LogType.TRACE, LogCategory.PERMISSIONS, _translations.KvTloMLv || (_translations.KvTloMLv = tr("Permission mapping"))); + for (let e of json) { + if (e["group_id_end"]) { + let group = new PermissionGroup(); + group.begin = this.permissionGroups.length ? this.permissionGroups.last().end : 0; + group.end = parseInt(e["group_id_end"]); + group.deep = 0; + group.name = (_translations.MSzE2M5g || (_translations.MSzE2M5g = tr("Group "))) + e["group_id_end"]; + let info = this._group_mapping.pop_front(); + if (info) { + group.name = info.name; + group.deep = info.deep; + } + this.permissionGroups.push(group); + } + let perm = new PermissionInfo(); + perm.name = e["permname"]; + perm.id = parseInt(e["permid"]); + perm.description = e["permdesc"]; + group.log(_translations.Icp51Xyn || (_translations.Icp51Xyn = tr("%i <> %s -> %s")), perm.id, perm.name, perm.description); + this.permissionList.push(perm); + } + group.end(); + log.info(LogCategory.PERMISSIONS, _translations.JCXF8tNn || (_translations.JCXF8tNn = tr("Got %i permissions")), this.permissionList.length); + if (this._cacheNeededPermissions) + this.onNeededPermissions(this._cacheNeededPermissions); + for (let listener of this.initializedListener) + listener(true); + } + onNeededPermissions(json) { + if (this.permissionList.length == 0) { + log.warn(LogCategory.PERMISSIONS, _translations.xW3OtQsi || (_translations.xW3OtQsi = tr("Got needed permissions but don't have a permission list!"))); + this._cacheNeededPermissions = json; + return; + } + this._cacheNeededPermissions = undefined; + let copy = this.neededPermissions.slice(); + let addcount = 0; + let group = log.group(log.LogType.TRACE, LogCategory.PERMISSIONS, _translations.gqaXY6XV || (_translations.gqaXY6XV = tr("Got %d needed permissions.")), json.length); + for (let e of json) { + let entry = undefined; + for (let p of copy) { + if (p.type.id == e["permid"]) { + entry = p; + copy.remove(p); + break; + } + } + if (!entry) { + let info = this.resolveInfo(e["permid"]); + if (info) { + entry = new NeededPermissionValue(info, -2); + this.neededPermissions.push(entry); + } + else { + log.warn(LogCategory.PERMISSIONS, _translations.GQx2LqqU || (_translations.GQx2LqqU = tr("Could not resolve perm for id %s (%o|%o)")), e["permid"], e, info); + continue; + } + addcount++; + } + if (entry.value == parseInt(e["permvalue"])) + continue; + entry.value = parseInt(e["permvalue"]); + //TODO tr + group.log("Update needed permission " + entry.type.name + " to " + entry.value); + for (let listener of entry.changeListener) + listener(entry.value); + } + group.end(); + //TODO tr + log.debug(LogCategory.PERMISSIONS, "Dropping " + copy.length + " needed permissions and added " + addcount + " permissions."); + for (let e of copy) { + e.value = -2; + for (let listener of e.changeListener) + listener(e.value); + } + } + onChannelPermList(json) { + let channelId = parseInt(json[0]["cid"]); + let permissions = PermissionManager.parse_permission_bulk(json, this.handle.permissions); + log.debug(LogCategory.PERMISSIONS, _translations.TU9ekKrB || (_translations.TU9ekKrB = tr("Got channel permissions for channel %o")), channelId); + for (let element of this.requests_channel_permissions) { + if (element.channel_id == channelId) { + for (let l of element.callback_success) + l(permissions); + this.requests_channel_permissions.remove(element); + return; + } + } + log.debug(LogCategory.PERMISSIONS, _translations.ODK68n4X || (_translations.ODK68n4X = tr("Missing channel permission handle for requested channel id %o")), channelId); + } + resolveInfo(key) { + for (let perm of this.permissionList) + if (perm.id == key || perm.name == key) + return perm; + return undefined; + } + requestChannelPermissions(channelId) { + return new Promise((resolve, reject) => { + let request; + for (let element of this.requests_channel_permissions) + if (element.requested + 1000 < Date.now() && element.channel_id == channelId) { + request = element; + break; + } + if (!request) { + request = new ChannelPermissionRequest(); + request.requested = Date.now(); + request.channel_id = channelId; + this.handle.serverConnection.send_command("channelpermlist", { "cid": channelId }); + this.requests_channel_permissions.push(request); + } + request.callback_error.push(reject); + request.callback_success.push(resolve); + }); + } + onClientPermList(json) { + let client = parseInt(json[0]["cldbid"]); + let permissions = PermissionManager.parse_permission_bulk(json, this); + for (let req of this.requests_client_permissions.slice(0)) { + if (req.client_id == client) { + this.requests_client_permissions.remove(req); + req.promise.resolved(permissions); + } + } + } + requestClientPermissions(client_id) { + for (let request of this.requests_client_permissions) + if (request.client_id == client_id && request.promise.time() + 1000 > Date.now()) + return request.promise; + let request = {}; + request.client_id = client_id; + request.promise = new LaterPromise(); + this.handle.serverConnection.send_command("clientpermlist", { cldbid: client_id }).catch(error => { + if (error instanceof CommandResult && error.id == ErrorID.EMPTY_RESULT) + request.promise.resolved([]); + else + request.promise.rejected(error); + }); + this.requests_client_permissions.push(request); + return request.promise; + } + requestClientChannelPermissions(client_id, channel_id) { + for (let request of this.requests_client_channel_permissions) + if (request.client_id == client_id && request.channel_id == channel_id && request.promise.time() + 1000 > Date.now()) + return request.promise; + let request = {}; + request.client_id = client_id; + request.channel_id = channel_id; + request.promise = new LaterPromise(); + this.handle.serverConnection.send_command("channelclientpermlist", { cldbid: client_id, cid: channel_id }).catch(error => { + if (error instanceof CommandResult && error.id == ErrorID.EMPTY_RESULT) + request.promise.resolved([]); + else + request.promise.rejected(error); + }); + this.requests_client_channel_permissions.push(request); + return request.promise; + } + onPlaylistPermList(json) { + let playlist_id = parseInt(json[0]["playlist_id"]); + let permissions = PermissionManager.parse_permission_bulk(json, this); + for (let req of this.requests_playlist_permissions.slice(0)) { + if (req.playlist_id == playlist_id) { + this.requests_playlist_permissions.remove(req); + req.promise.resolved(permissions); + } + } + } + requestPlaylistPermissions(playlist_id) { + for (let request of this.requests_playlist_permissions) + if (request.playlist_id == playlist_id && request.promise.time() + 1000 > Date.now()) + return request.promise; + let request = {}; + request.playlist_id = playlist_id; + request.promise = new LaterPromise(); + this.handle.serverConnection.send_command("playlistpermlist", { playlist_id: playlist_id }).catch(error => { + if (error instanceof CommandResult && error.id == ErrorID.EMPTY_RESULT) + request.promise.resolved([]); + else + request.promise.rejected(error); + }); + this.requests_playlist_permissions.push(request); + return request.promise; + } + neededPermission(key) { + for (let perm of this.neededPermissions) + if (perm.type.id == key || perm.type.name == key || perm.type == key) + return perm; + log.debug(LogCategory.PERMISSIONS, _translations.REzpKcHE || (_translations.REzpKcHE = tr("Could not resolve grant permission %o. Creating a new one.")), key); + let info = key instanceof PermissionInfo ? key : this.resolveInfo(key); + if (!info) { + log.warn(LogCategory.PERMISSIONS, _translations.cFseHpLq || (_translations.cFseHpLq = tr("Requested needed permission with invalid key! (%o)")), key); + return new NeededPermissionValue(undefined, -2); + } + let result = new NeededPermissionValue(info, -2); + this.neededPermissions.push(result); + return result; + } + groupedPermissions() { + let result = []; + let current; + for (let group of this.permissionGroups) { + if (group.deep == 0) { + current = new GroupedPermissions(); + current.group = group; + current.parent = undefined; + current.children = []; + current.permissions = []; + result.push(current); + } + else { + if (!current) { + throw _translations.q7zQFaQp || (_translations.q7zQFaQp = tr("invalid order!")); + } + else { + while (group.deep <= current.group.deep) + current = current.parent; + let parent = current; + current = new GroupedPermissions(); + current.group = group; + current.parent = parent; + current.children = []; + current.permissions = []; + parent.children.push(current); + } + } + for (let permission of this.permissionList) + if (permission.id > current.group.begin && permission.id <= current.group.end) + current.permissions.push(permission); + } + return result; + } + /** + * Generates an enum with all know permission types, used for the enum above + */ + export_permission_types() { + let result = ""; + result = result + "enum PermissionType {\n"; + for (const permission of this.permissionList) { + if (!permission.name) + continue; + result = result + "\t" + permission.name.toUpperCase() + " = \"" + permission.name.toLowerCase() + "\", /* Permission ID: " + permission.id + " */\n"; + } + result = result + "}"; + return result; + } +} +/* Static info mapping until TeaSpeak implements a detailed info */ +//TODO tr +PermissionManager.group_mapping = [ + { name: "Global", deep: 0 }, + { name: "Information", deep: 1 }, + { name: "Virtual server management", deep: 1 }, + { name: "Administration", deep: 1 }, + { name: "Settings", deep: 1 }, + { name: "Virtual Server", deep: 0 }, + { name: "Information", deep: 1 }, + { name: "Administration", deep: 1 }, + { name: "Settings", deep: 1 }, + { name: "Channel", deep: 0 }, + { name: "Information", deep: 1 }, + { name: "Create", deep: 1 }, + { name: "Modify", deep: 1 }, + { name: "Delete", deep: 1 }, + { name: "Access", deep: 1 }, + { name: "Group", deep: 0 }, + { name: "Information", deep: 1 }, + { name: "Create", deep: 1 }, + { name: "Modify", deep: 1 }, + { name: "Delete", deep: 1 }, + { name: "Client", deep: 0 }, + { name: "Information", deep: 1 }, + { name: "Admin", deep: 1 }, + { name: "Basics", deep: 1 }, + { name: "Modify", deep: 1 }, + //TODO Music bot + { name: "File Transfer", deep: 0 }, +]; +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["a81ae99c9fe3d1a6dabcacaa70a4f4effcbf39ca57367d993b18036432881f23"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["a81ae99c9fe3d1a6dabcacaa70a4f4effcbf39ca57367d993b18036432881f23"] = "a81ae99c9fe3d1a6dabcacaa70a4f4effcbf39ca57367d993b18036432881f23"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "NNGAmR6u", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/permission/GroupManager.ts (127,27)" }, { name: "tVu_YwTx", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/permission/GroupManager.ts (197,48)" }, { name: "zZLMJZGq", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/permission/GroupManager.ts (206,47)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +/// +var GroupType; +(function (GroupType) { + GroupType[GroupType["QUERY"] = 0] = "QUERY"; + GroupType[GroupType["TEMPLATE"] = 1] = "TEMPLATE"; + GroupType[GroupType["NORMAL"] = 2] = "NORMAL"; +})(GroupType || (GroupType = {})); +var GroupTarget; +(function (GroupTarget) { + GroupTarget[GroupTarget["SERVER"] = 0] = "SERVER"; + GroupTarget[GroupTarget["CHANNEL"] = 1] = "CHANNEL"; +})(GroupTarget || (GroupTarget = {})); +class GroupProperties { + constructor() { + this.iconid = 0; + this.sortid = 0; + this.savedb = false; + this.namemode = 0; + } +} +class GroupPermissionRequest { +} +class Group { + constructor(handle, id, target, type, name) { + this.properties = new GroupProperties(); + this.requiredModifyPower = 0; + this.requiredMemberAddPower = 0; + this.requiredMemberRemovePower = 0; + this.handle = handle; + this.id = id; + this.target = target; + this.type = type; + this.name = name; + } + updateProperty(key, value) { + JSON.map_field_to(this.properties, value, key); + if (key == "iconid") { + this.properties.iconid = (new Uint32Array([this.properties.iconid]))[0]; + console.log("Icon id " + this.properties.iconid); + this.handle.handle.channelTree.clientsByGroup(this).forEach(client => { + client.updateGroupIcon(this); + }); + } + } +} +class GroupManager extends connection.AbstractCommandHandler { + constructor(client) { + super(client.serverConnection); + this.serverGroups = []; + this.channelGroups = []; + this.requests_group_permissions = []; + client.serverConnection.command_handler_boss().register_handler(this); + this.handle = client; + } + handle_command(command) { + switch (command.command) { + case "notifyservergrouplist": + case "notifychannelgrouplist": + this.handle_grouplist(command.arguments); + return true; + case "notifyservergrouppermlist": + case "notifychannelgrouppermlist": + this.handle_group_permission_list(command.arguments); + return true; + } + return false; + } + requestGroups() { + this.handle.serverConnection.send_command("servergrouplist"); + this.handle.serverConnection.send_command("channelgrouplist"); + } + static sorter() { + return (a, b) => { + if (a.properties.sortid > b.properties.sortid) + return 1; + if (a.properties.sortid < b.properties.sortid) + return -1; + if (a.id < b.id) + return -1; + if (a.id > b.id) + return 1; + return 0; + }; + } + serverGroup(id) { + for (let group of this.serverGroups) + if (group.id == id) + return group; + return undefined; + } + channelGroup(id) { + for (let group of this.channelGroups) + if (group.id == id) + return group; + return undefined; + } + handle_grouplist(json) { + let target; + if (json[0]["sgid"]) + target = GroupTarget.SERVER; + else if (json[0]["cgid"]) + target = GroupTarget.CHANNEL; + else { + console.error(_translations.NNGAmR6u || (_translations.NNGAmR6u = tr("Could not resolve group target! => %o")), json[0]); + return; + } + if (target == GroupTarget.SERVER) + this.serverGroups = []; + else + this.channelGroups = []; + for (let groupData of json) { + let type; + switch (Number.parseInt(groupData["type"])) { + case 0: + type = GroupType.TEMPLATE; + break; + case 1: + type = GroupType.NORMAL; + break; + case 2: + type = GroupType.QUERY; + break; + default: + //TODO tr + console.error("Invalid group type: " + groupData["type"] + " for group " + groupData["name"]); + continue; + } + let group = new Group(this, parseInt(target == GroupTarget.SERVER ? groupData["sgid"] : groupData["cgid"]), target, type, groupData["name"]); + for (let key in groupData) { + if (key == "sgid") + continue; + if (key == "cgid") + continue; + if (key == "type") + continue; + if (key == "name") + continue; + group.updateProperty(key, groupData[key]); + } + group.requiredMemberRemovePower = parseInt(groupData["n_member_removep"]); + group.requiredMemberAddPower = parseInt(groupData["n_member_addp"]); + group.requiredModifyPower = parseInt(groupData["n_modifyp"]); + if (target == GroupTarget.SERVER) + this.serverGroups.push(group); + else + this.channelGroups.push(group); + } + console.log("Got " + json.length + " new " + target + " groups:"); + for (const client of this.handle.channelTree.clients) + client.update_displayed_client_groups(); + } + request_permissions(group) { + for (let request of this.requests_group_permissions) + if (request.group_id == group.id && request.promise.time() + 1000 > Date.now()) + return request.promise; + let req = new GroupPermissionRequest(); + req.group_id = group.id; + req.promise = new LaterPromise(); + this.requests_group_permissions.push(req); + this.handle.serverConnection.send_command(group.target == GroupTarget.SERVER ? "servergrouppermlist" : "channelgrouppermlist", { + cgid: group.id, + sgid: group.id + }).catch(error => { + if (error instanceof CommandResult && error.id == 0x0501) + req.promise.resolved([]); + else + req.promise.rejected(error); + }); + return req.promise; + } + handle_group_permission_list(json) { + let group = json[0]["sgid"] ? this.serverGroup(parseInt(json[0]["sgid"])) : this.channelGroup(parseInt(json[0]["cgid"])); + if (!group) { + log.error(LogCategory.PERMISSIONS, _translations.tVu_YwTx || (_translations.tVu_YwTx = tr("Got group permissions for group %o/%o, but its not a registered group!")), json[0]["sgid"], json[0]["cgid"]); + return; + } + let requests = []; + for (let req of this.requests_group_permissions) + if (req.group_id == group.id) + requests.push(req); + if (requests.length == 0) { + log.warn(LogCategory.PERMISSIONS, _translations.zZLMJZGq || (_translations.zZLMJZGq = tr("Got group permissions for group %o/%o, but it was never requested!")), json[0]["sgid"], json[0]["cgid"]); + return; + } + let permissions = PermissionManager.parse_permission_bulk(json, this.handle.permissions); + for (let req of requests) { + this.requests_group_permissions.remove(req); + req.promise.resolved(permissions); + } + } +} +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["ec835d42b3d6ae771f5f0eae50c26c1e8b071995d5df1245175c0bc10ac5fb84"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["ec835d42b3d6ae771f5f0eae50c26c1e8b071995d5df1245175c0bc10ac5fb84"] = "ec835d42b3d6ae771f5f0eae50c26c1e8b071995d5df1245175c0bc10ac5fb84"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "Aj8PajLX", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/i18n/localize.ts (105,52)" }, { name: "uLm8UOda", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/i18n/localize.ts (106,32)" }, { name: "WxSsQs_w", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/i18n/localize.ts (110,28)" }, { name: "p6yJmpGX", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/i18n/localize.ts (118,40)" }, { name: "HlyUXdnU", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/i18n/localize.ts (122,40)" }, { name: "kcmdR8r1", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/i18n/localize.ts (144,32)" }, { name: "lQdjng16", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/i18n/localize.ts (196,48)" }, { name: "yEYagZjd", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/i18n/localize.ts (199,48)" }, { name: "U6ARXz_h", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/i18n/localize.ts (278,52)" }, { name: "F2K3ghGt", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/i18n/localize.ts (288,44)" }, { name: "lQqId0FO", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/i18n/localize.ts (323,34)" }, { name: "j5y8yWZu", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/i18n/localize.ts (323,60)" }, { name: "ytLhnjvg", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/i18n/localize.ts (323,196)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +/* +"key": { + "message": "Show permission description", + "line": 374, + "character": 30, + "filename": "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPermissionEdit.ts" +}, +"translated": "Berechtigungsbeschreibung anzeigen", +"flags": [ + "google-translate", + "verified" +] + */ +function guid() { + function s4() { + return Math.floor((1 + Math.random()) * 0x10000) + .toString(16) + .substring(1); + } + return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4(); +} +var i18n; +(function (i18n) { + let translations = []; + let fast_translate = {}; + function tr(message, key) { + const sloppy = fast_translate[message]; + if (sloppy) + return sloppy; + log.info(LogCategory.I18N, "Translating \"%s\". Default: \"%s\"", key, message); + let translated = message; + for (const translation of translations) { + if (translation.key.message == message) { + translated = translation.translated; + break; + } + } + fast_translate[message] = translated; + return translated; + } + i18n.tr = tr; + function load_translation_file(url) { + return __awaiter(this, void 0, void 0, function* () { + return new Promise((resolve, reject) => { + $.ajax({ + url: url, + async: true, + success: result => { + try { + const file = (typeof (result) === "string" ? JSON.parse(result) : result); + if (!file) { + reject("Invalid json"); + return; + } + file.url = url; + //TODO validate file + resolve(file); + } + catch (error) { + log.warn(LogCategory.I18N, _translations.Aj8PajLX || (_translations.Aj8PajLX = tr("Failed to load translation file %s. Failed to parse or process json: %o")), url, error); + reject(_translations.uLm8UOda || (_translations.uLm8UOda = tr("Failed to process or parse json!"))); + } + }, + error: (xhr, error) => { + reject((_translations.WxSsQs_w || (_translations.WxSsQs_w = tr("Failed to load file: "))) + error); + } + }); + }); + }); + } + function load_file(url) { + return load_translation_file(url).then(result => { + log.info(LogCategory.I18N, _translations.p6yJmpGX || (_translations.p6yJmpGX = tr("Successfully initialized up translation file from %s")), url); + translations = result.translations; + return Promise.resolve(); + }).catch(error => { + log.warn(LogCategory.I18N, _translations.HlyUXdnU || (_translations.HlyUXdnU = tr("Failed to load translation file from \"%s\". Error: %o")), url, error); + return Promise.reject(error); + }); + } + i18n.load_file = load_file; + function load_repository0(repo, reload) { + return __awaiter(this, void 0, void 0, function* () { + if (!repo.load_timestamp || repo.load_timestamp < 1000 || reload) { + const info_json = yield new Promise((resolve, reject) => { + $.ajax({ + url: repo.url + "/info.json", + async: true, + cache: !reload, + success: result => { + const file = (typeof (result) === "string" ? JSON.parse(result) : result); + if (!file) { + reject("Invalid json"); + return; + } + resolve(file); + }, + error: (xhr, error) => { + reject((_translations.kcmdR8r1 || (_translations.kcmdR8r1 = tr("Failed to load file: "))) + error); + } + }); + }); + Object.assign(repo, info_json); + } + if (!repo.unique_id) + repo.unique_id = guid(); + repo.translations = repo.translations || []; + repo.load_timestamp = Date.now(); + }); + } + function load_repository(url) { + return __awaiter(this, void 0, void 0, function* () { + const result = {}; + result.url = url; + yield load_repository0(result, false); + return result; + }); + } + i18n.load_repository = load_repository; + let config; + (function (config_1) { + const repository_config_key = "i18n.repository"; + let _cached_repository_config; + function repository_config() { + if (_cached_repository_config) + return _cached_repository_config; + const config_string = localStorage.getItem(repository_config_key); + const config = config_string ? JSON.parse(config_string) : {}; + config.repositories = config.repositories || []; + for (const repo of config.repositories) + (repo.repository || { load_timestamp: 0 }).load_timestamp = 0; + if (config.repositories.length == 0) { + //Add the default TeaSpeak repository + load_repository(StaticSettings.instance.static("i18n.default_repository", "i18n/")).then(repo => { + log.info(LogCategory.I18N, _translations.lQdjng16 || (_translations.lQdjng16 = tr("Successfully added default repository from \"%s\".")), repo.url); + register_repository(repo); + }).catch(error => { + log.warn(LogCategory.I18N, _translations.yEYagZjd || (_translations.yEYagZjd = tr("Failed to add default repository. Error: %o")), error); + }); + } + return _cached_repository_config = config; + } + config_1.repository_config = repository_config; + function save_repository_config() { + localStorage.setItem(repository_config_key, JSON.stringify(_cached_repository_config)); + } + config_1.save_repository_config = save_repository_config; + const translation_config_key = "i18n.translation"; + let _cached_translation_config; + function translation_config() { + if (_cached_translation_config) + return _cached_translation_config; + const config_string = localStorage.getItem(translation_config_key); + _cached_translation_config = config_string ? JSON.parse(config_string) : {}; + return _cached_translation_config; + } + config_1.translation_config = translation_config; + function save_translation_config() { + localStorage.setItem(translation_config_key, JSON.stringify(_cached_translation_config)); + } + config_1.save_translation_config = save_translation_config; + })(config = i18n.config || (i18n.config = {})); + function register_repository(repository) { + if (!repository) + return; + for (const repo of config.repository_config().repositories) + if (repo.url == repository.url) + return; + config.repository_config().repositories.push(repository); + config.save_repository_config(); + } + i18n.register_repository = register_repository; + function registered_repositories() { + return config.repository_config().repositories.map(e => e.repository || { url: e.url, load_timestamp: 0 }); + } + i18n.registered_repositories = registered_repositories; + function delete_repository(repository) { + if (!repository) + return; + for (const repo of [...config.repository_config().repositories]) + if (repo.url == repository.url) { + config.repository_config().repositories.remove(repo); + } + config.save_repository_config(); + } + i18n.delete_repository = delete_repository; + function iterate_translations(callback_entry, callback_finish) { + let count = 0; + const update_finish = () => { + if (count == 0 && callback_finish) + callback_finish(); + }; + for (const repo of registered_repositories()) { + count++; + load_repository0(repo, false).then(() => { + for (const translation of repo.translations || []) { + const translation_path = repo.url + "/" + translation.path; + count++; + load_translation_file(translation_path).then(file => { + if (callback_entry) { + try { + callback_entry(repo, file); + } + catch (error) { + console.error(error); + //TODO more error handling? + } + } + count--; + update_finish(); + }).catch(error => { + log.warn(LogCategory.I18N, _translations.U6ARXz_h || (_translations.U6ARXz_h = tr("Failed to load translation file for repository %s. Translation: %s (%s) Error: %o")), repo.name, translation.key, translation_path, error); + count--; + update_finish(); + }); + } + count--; + update_finish(); + }).catch(error => { + log.warn(LogCategory.I18N, _translations.F2K3ghGt || (_translations.F2K3ghGt = tr("Failed to load repository while iteration: %s (%s). Error: %o")), (repo || { name: "unknown" }).name, (repo || { url: "unknown" }).url, error); + count--; + update_finish(); + }); + } + update_finish(); + } + i18n.iterate_translations = iterate_translations; + function select_translation(repository, entry) { + const cfg = config.translation_config(); + if (entry && repository) { + cfg.current_language = entry.info.name; + cfg.current_repository_url = repository.url; + cfg.current_translation_url = entry.url; + } + else { + cfg.current_language = undefined; + cfg.current_repository_url = undefined; + cfg.current_translation_url = undefined; + } + config.save_translation_config(); + } + i18n.select_translation = select_translation; + function initialize() { + return __awaiter(this, void 0, void 0, function* () { + const rcfg = config.repository_config(); /* initialize */ + const cfg = config.translation_config(); + if (cfg.current_translation_url) { + try { + yield load_file(cfg.current_translation_url); + } + catch (error) { + createErrorModal(_translations.lQqId0FO || (_translations.lQqId0FO = tr("Translation System")), (_translations.j5y8yWZu || (_translations.j5y8yWZu = tr("Failed to load current selected translation file."))) + "
    File: " + cfg.current_translation_url + "
    Error: " + error + "
    " + (_translations.ytLhnjvg || (_translations.ytLhnjvg = tr("Using default fallback translations.")))).open(); + } + } + // await load_file("http://localhost/home/TeaSpeak/TeaSpeak/Web-Client/web/environment/development/i18n/de_DE.translation"); + // await load_file("http://localhost/home/TeaSpeak/TeaSpeak/Web-Client/web/environment/development/i18n/test.json"); + }); + } + i18n.initialize = initialize; +})(i18n || (i18n = {})); +const tr = i18n.tr; +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["0608e67a6e07bc39237edb01d392a99930ecb6de98d5577d8ba63f5d84388743"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["0608e67a6e07bc39237edb01d392a99930ecb6de98d5577d8ba63f5d84388743"] = "0608e67a6e07bc39237edb01d392a99930ecb6de98d5577d8ba63f5d84388743"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "Z3yXpqqL", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/utils/tab.ts (26,18)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +/// +if (typeof (customElements) !== "undefined") { + try { + class X_Tab extends HTMLElement { + } + class X_Entry extends HTMLElement { + } + class X_Tag extends HTMLElement { + } + class X_Content extends HTMLElement { + } + customElements.define('x-tab', X_Tab, { extends: 'div' }); + customElements.define('x-entry', X_Entry, { extends: 'div' }); + customElements.define('x-tag', X_Tag, { extends: 'div' }); + customElements.define('x-content', X_Content, { extends: 'div' }); + } + catch (error) { + console.warn("failed to define costum elements"); + } +} +else { + console.warn(_translations.Z3yXpqqL || (_translations.Z3yXpqqL = tr("Could not defied tab customElements!"))); +} +var TabFunctions = { + tabify(template, copy = true) { + console.log("Tabify: copy=" + copy); + console.log(template); + let tag = $.spawn("div"); + tag.addClass("tab"); + let header = $.spawn("div"); + header.addClass("tab-header"); + let content = $.spawn("div"); + content.addClass("tab-content"); + let silentContent = $.spawn("div"); + silentContent.addClass("tab-content-invisible"); + /* add some kind of min height */ + const update_height = () => { + const entries = tag.find("> .tab-content-invisible x-content, > .tab-content x-content"); + console.error(entries); + let max_height = 0; + entries.each((_, _e) => { + const entry = $(_e); + const height = entry.visible_height(); + if (height > max_height) + max_height = height; + }); + console.error("HIGHT: " + max_height); + entries.each((_, _e) => { + const entry = $(_e); + entry.animate({ + 'min-height': max_height + "px" + }, 250); + }); + }; + template.find("x-entry").each((_, _entry) => { + const entry = $(_entry); + let tag_header = $.spawn("div").addClass("entry"); + if (copy) + tag_header.append(entry.find("x-tag").clone(true, true)); + else + tag_header.append(entry.find("x-tag")); + const tag_content = copy ? entry.find("x-content").clone(true, true) : entry.find("x-content"); + content.append(tag_content.hide()); + tag_header.on("click", () => { + if (tag_header.hasClass("selected")) + return; + tag.find(".tab-header .selected").removeClass("selected"); + tag_header.addClass("selected"); + content.find("> x-content").hide(); + /* don't show many nodes at once */ + let entries = tag_content.find(".tab-show-partitional"); + entries.hide(); + const show_next = index => { + console.log("Show " + index); + if (index >= entries.length) + return; + entries.eq(index).show(); + setTimeout(show_next.bind(undefined, index + 1), 0); + }; + show_next(0); + tag_content.trigger('show'); + tag_content.show(); + }); + console.log(this); + header.append(tag_header); + }); + setTimeout(() => header.find(".entry").first().trigger("click"), 0); + tag.append(header); + tag.append(content); + tag.append(silentContent); + tag.on('tab.resize', update_height); + return tag; + } +}; +if (!$.fn.asTabWidget) { + $.fn.asTabWidget = function (copy) { + if ($(this).prop("tagName") == "X-TAB") + return TabFunctions.tabify($(this), typeof (copy) === "boolean" ? copy : true); + else { + throw "Invalid tag! " + $(this).prop("tagName"); + } + }; +} +if (!$.fn.tabify) { + $.fn.tabify = function (copy) { + const wrapped_tag = $.spawn("div").append(this); + wrapped_tag.find("x-tab").each((_, _element) => { + const element = $(_element); + element.replaceWith(element.asTabWidget(copy)); + }); + return wrapped_tag.children(); + }; +} +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["26497305b2d8068b208cb264a896e75dcbd2fc426a0102a57b52777707d986d2"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["26497305b2d8068b208cb264a896e75dcbd2fc426a0102a57b52777707d986d2"] = "26497305b2d8068b208cb264a896e75dcbd2fc426a0102a57b52777707d986d2"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "WVMGeKir", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/profiles/Identity.ts (79,30)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +var profiles; +(function (profiles) { + var identities; + (function (identities) { + let IdentitifyType; + (function (IdentitifyType) { + IdentitifyType[IdentitifyType["TEAFORO"] = 0] = "TEAFORO"; + IdentitifyType[IdentitifyType["TEAMSPEAK"] = 1] = "TEAMSPEAK"; + IdentitifyType[IdentitifyType["NICKNAME"] = 2] = "NICKNAME"; + })(IdentitifyType = identities.IdentitifyType || (identities.IdentitifyType = {})); + function decode_identity(type, data) { + return __awaiter(this, void 0, void 0, function* () { + let identity; + switch (type) { + case IdentitifyType.NICKNAME: + identity = new identities.NameIdentity(); + break; + case IdentitifyType.TEAFORO: + identity = new identities.TeaForumIdentity(undefined, undefined); + break; + case IdentitifyType.TEAMSPEAK: + identity = new identities.TeaSpeakIdentity(undefined, undefined); + break; + } + if (!identity) + return undefined; + try { + yield identity.decode(data); + } + catch (error) { + /* todo better error handling! */ + console.error(error); + return undefined; + } + return identity; + }); + } + identities.decode_identity = decode_identity; + function create_identity(type) { + let identity; + switch (type) { + case IdentitifyType.NICKNAME: + identity = new identities.NameIdentity(); + break; + case IdentitifyType.TEAFORO: + identity = new identities.TeaForumIdentity(undefined, undefined); + break; + case IdentitifyType.TEAMSPEAK: + identity = new identities.TeaSpeakIdentity(undefined, undefined); + break; + } + return identity; + } + identities.create_identity = create_identity; + class HandshakeCommandHandler extends connection.AbstractCommandHandler { + constructor(connection, handle) { + super(connection); + this.handle = handle; + } + handle_command(command) { + if ($.isFunction(this[command.command])) + this[command.command](command.arguments); + else if (command.command == "error") { + return false; + } + else { + console.warn(_translations.WVMGeKir || (_translations.WVMGeKir = tr("Received unknown command while handshaking (%o)")), command); + } + return true; + } + } + identities.HandshakeCommandHandler = HandshakeCommandHandler; + class AbstractHandshakeIdentityHandler { + constructor(connection) { + this.callbacks = []; + this.connection = connection; + } + register_callback(callback) { + this.callbacks.push(callback); + } + trigger_success() { + for (const callback of this.callbacks) + callback(true); + } + trigger_fail(message) { + for (const callback of this.callbacks) + callback(false, message); + } + } + identities.AbstractHandshakeIdentityHandler = AbstractHandshakeIdentityHandler; + })(identities = profiles.identities || (profiles.identities = {})); +})(profiles || (profiles = {})); +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["6e73161c487fad41b7c4c5baf6cc368bdb42dbfc8a59540a353876c15215dff1"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["6e73161c487fad41b7c4c5baf6cc368bdb42dbfc8a59540a353876c15215dff1"] = "6e73161c487fad41b7c4c5baf6cc368bdb42dbfc8a59540a353876c15215dff1"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "KdRLXfeo", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (13,21)" }, { name: "yx_xHhJB", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (39,40)" }, { name: "AbIB7kuK", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (39,54)" }, { name: "pLrbmacb", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (61,46)" }, { name: "H8XKcwqE", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (61,80)" }, { name: "PXQnHjzx", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (74,53)" }, { name: "TNwFGGdq", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (74,119)" }, { name: "LglJTEhF", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (83,46)" }, { name: "n6YP6bgq", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (83,80)" }, { name: "gPFWcPhf", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (127,21)" }, { name: "sGfe77wj", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (165,43)" }, { name: "RTn7ep8V", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (166,39)" }, { name: "qxT8i0h0", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (203,21)" }, { name: "iea9bskW", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (235,80)" }, { name: "LAba6sXO", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (237,84)" }, { name: "d9JSFaA1", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (296,39)" }, { name: "mjG6j0ML", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (306,41)" }, { name: "jyqAJeYM", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (382,27)" }, { name: "kb9gRNI1", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (389,39)" }, { name: "bDG4yJ1S", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (400,35)" }, { name: "tL0bCP54", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (402,35)" }, { name: "cUQD3Itt", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (415,33)" }, { name: "fLXoZ44p", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (442,35)" }, { name: "giEinlmS", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (444,35)" }, { name: "_bYpHOYM", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (456,33)" }, { name: "wNBrz45p", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (459,39)" }, { name: "Mj83gjpx", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (513,37)" }, { name: "R_rvWgki", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (620,33)" }, { name: "dVaJRUpW", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (638,43)" }, { name: "GQ7uZCIp", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (661,46)" }, { name: "pvEhAEg0", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (661,67)" }, { name: "xTmVYl7B", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (687,36)" }, { name: "t8KEieTl", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (709,46)" }, { name: "oGJHPfbq", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (736,46)" }, { name: "fdSBxddp", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (745,70)" }, { name: "j97itdQy", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (881,41)" }, { name: "uq3SlGtZ", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (881,66)" }, { name: "IuhqR8em", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (885,36)" }, { name: "F3qLDw6y", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (885,56)" }, { name: "XNKN8L18", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (896,38)" }, { name: "u6rghx8Y", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (896,55)" }, { name: "aZI_J5tO", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (909,50)" }, { name: "DLdFWwPd", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (909,83)" }, { name: "x8afoFoc", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (921,45)" }, { name: "ynFYOHQs", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (921,70)" }, { name: "mfN6hbkM", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (923,43)" }, { name: "YH0Js1Ll", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (924,46)" }, { name: "ZCXXZ5WL", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (924,81)" }, { name: "tnuGGElr", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (929,36)" }, { name: "GWA7WrRm", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (929,56)" }, { name: "IaVpSbUr", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (1047,34)" }, { name: "DXtYBVnN", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (1047,61)" }, { name: "En9YP_2L", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (1067,32)" }, { name: "tQHWsdmy", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts (1067,53)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +/// +/// +/// +/// +/// +var Modals; +(function (Modals) { + function spawnTeamSpeakIdentityImprove(identity) { + let modal; + let elapsed_timer; + modal = createModal({ + header: _translations.KdRLXfeo || (_translations.KdRLXfeo = tr("Improve identity")), + body: () => { + let template = $("#tmpl_settings-teamspeak_improve").renderTag(); + template = $.spawn("div").append(template); + let active; + const button_start_stop = template.find(".button-start-stop"); + const button_close = template.find(".button-close"); + const input_current_level = template.find(".identity-level input"); + const input_target_level = template.find(".identity-target-level input"); + const input_threads = template.find(".threads input"); + const input_hash_rate = template.find(".hash-rate input"); + const input_elapsed = template.find(".time-elapsed input"); + button_close.on('click', event => { + if (active) + button_start_stop.trigger('click'); + if (modal.shown) + modal.close(); + }); + button_start_stop.on('click', event => { + button_start_stop + .toggleClass('btn-success', active) + .toggleClass('btn-danger', !active) + .text(active ? _translations.yx_xHhJB || (_translations.yx_xHhJB = tr("Start")) : _translations.AbIB7kuK || (_translations.AbIB7kuK = tr("Stop"))); + input_threads.prop("disabled", !active); + input_target_level.prop("disabled", !active); + if (active) { + input_hash_rate.val(0); + clearInterval(elapsed_timer); + active = false; + return; + } + active = true; + input_hash_rate.val("nan"); + const threads = parseInt(input_threads.val()); + const target_level = parseInt(input_target_level.val()); + if (target_level == 0) { + identity.improve_level(-1, threads, () => active, current_level => { + input_current_level.val(current_level); + }, hash_rate => { + input_hash_rate.val(hash_rate); + }).catch(error => { + console.error(error); + createErrorModal(_translations.pLrbmacb || (_translations.pLrbmacb = tr("Failed to improve identity")), (_translations.H8XKcwqE || (_translations.H8XKcwqE = tr("Failed to improve identity.
    Error:"))) + error).open(); + if (active) + button_start_stop.trigger('click'); + }); + } + else { + identity.improve_level(target_level, threads, () => active, current_level => { + input_current_level.val(current_level); + }, hash_rate => { + input_hash_rate.val(hash_rate); + }).then(success => { + if (success) { + identity.level().then(level => { + input_current_level.val(level); + createInfoModal(_translations.PXQnHjzx || (_translations.PXQnHjzx = tr("Identity successfully improved")), MessageHelper.formatMessage(_translations.TNwFGGdq || (_translations.TNwFGGdq = tr("Identity successfully improved to level {}")), level)).open(); + }).catch(error => { + input_current_level.val("error: " + error); + }); + } + if (active) + button_start_stop.trigger('click'); + }).catch(error => { + console.error(error); + createErrorModal(_translations.LglJTEhF || (_translations.LglJTEhF = tr("Failed to improve identity")), (_translations.n6YP6bgq || (_translations.n6YP6bgq = tr("Failed to improve identity.
    Error:"))) + error).open(); + if (active) + button_start_stop.trigger('click'); + }); + } + const begin = Date.now(); + elapsed_timer = setInterval(() => { + const time = (Date.now() - begin) / 1000; + let seconds = Math.floor(time % 60).toString(); + let minutes = Math.floor(time / 60).toString(); + if (seconds.length < 2) + seconds = "0" + seconds; + if (minutes.length < 2) + minutes = "0" + minutes; + input_elapsed.val(minutes + ":" + seconds); + }, 1000); + }); + template.find(".identity-unique-id input").val(identity.uid()); + identity.level().then(level => { + input_current_level.val(level); + }).catch(error => { + input_current_level.val("error: " + error); + }); + return template; + }, + footer: undefined, + width: 750 + }); + modal.close_listener.push(() => modal.htmlTag.find(".button-close").trigger('click')); + modal.open(); + return modal; + } + function spawnTeamSpeakIdentityImport(callback) { + let modal; + let loaded_identity; + modal = createModal({ + header: _translations.gPFWcPhf || (_translations.gPFWcPhf = tr("Import identity")), + body: () => { + let template = $("#tmpl_settings-teamspeak_import").renderTag(); + template = $.spawn("div").append(template); + template.find(".button-load-file").on('click', event => template.find(".input-file").trigger('click')); + const button_import = template.find(".button-import"); + const set_error = message => { + template.find(".success").hide(); + if (message) { + template.find(".error").text(message).show(); + button_import.prop("disabled", true); + } + else + template.find(".error").hide(); + }; + const import_identity = (data, ini) => { + profiles.identities.TeaSpeakIdentity.import_ts(data, ini).then(identity => { + loaded_identity = identity; + set_error(""); + button_import.prop("disabled", false); + template.find(".success").show(); + }).catch(error => { + set_error("Failed to load identity: " + error); + }); + }; + { /* file select button */ + template.find(".input-file").on('change', event => { + const element = event.target; + const file_reader = new FileReader(); + file_reader.onload = function () { + import_identity(file_reader.result, true); + }; + file_reader.onerror = ev => { + console.error(_translations.sGfe77wj || (_translations.sGfe77wj = tr("Failed to read give identity file: %o")), ev); + set_error(_translations.RTn7ep8V || (_translations.RTn7ep8V = tr("Failed to read file!"))); + return; + }; + if (element.files && element.files.length > 0) + file_reader.readAsText(element.files[0]); + }); + } + { /* text input */ + template.find(".button-load-text").on('click', event => { + createInputModal("Import identity from text", "Please paste your idenity bellow
    ", text => text.length > 0 && text.indexOf('V') != -1, result => { + if (result) + import_identity(result, false); + }).open(); + }); + } + button_import.on('click', event => { + modal.close(); + callback(loaded_identity); + }); + set_error(""); + button_import.prop("disabled", true); + return template; + }, + footer: undefined, + width: 750 + }); + modal.open(); + return modal; + } + function spawnSettingsModal() { + let modal; + modal = createModal({ + header: _translations.qxT8i0h0 || (_translations.qxT8i0h0 = tr("Settings")), + body: () => { + let template = $("#tmpl_settings").renderTag({ + client: native_client, + valid_forum_identity: profiles.identities.valid_static_forum_identity(), + forum_path: settings.static("forum_path"), + }); + initialiseVoiceListeners(modal, (template = template.tabify()).find(".settings_audio")); + initialise_translations(template.find(".settings-translations")); + initialise_profiles(modal, template.find(".settings-profiles")); + initialise_global(modal, template.find(".settings-general")); + return template; + }, + footer: undefined, + width: 750 + }); + modal.open(); + return modal; + } + Modals.spawnSettingsModal = spawnSettingsModal; + function initialise_global(modal, tag) { + console.log(tag); + { /* setup the forum */ + const identity = profiles.identities.static_forum_identity(); + if (identity && identity.valid()) { + tag.find(".not-connected").hide(); + tag.find(".property.username .value").text(identity.name()); + const premium_tag = tag.find(".property.premium .value").text(""); + if (identity.is_stuff() || identity.is_premium()) + premium_tag.append($.spawn("div").addClass("premium").text(_translations.iea9bskW || (_translations.iea9bskW = tr("yes")))); + else + premium_tag.append($.spawn("div").addClass("non-premium").text(_translations.LAba6sXO || (_translations.LAba6sXO = tr("no")))); + } + else { + tag.find(".connected").hide(); + } + tag.find(".button-logout").on('click', event => { + window.location.href = settings.static("forum_path") + "auth.php?type=logout"; + }); + tag.find(".button-login").on('click', event => { + window.location.href = settings.static("forum_path") + "login.php"; + }); + } + } + function initialiseVoiceListeners(modal, tag) { + let currentVAD = settings.global("vad_type", "vad"); + { //Initialized voice activation detection + const vad_tag = tag.find(".settings-vad-container"); + vad_tag.find('input[type=radio]').on('change', event => { + const select = event.currentTarget; + { + vad_tag.find(".settings-vad-impl-entry").hide(); + vad_tag.find(".setting-vad-" + select.value).show(); + } + { + settings.changeGlobal("vad_type", select.value); + globalClient.voiceConnection.voiceRecorder.reinitialiseVAD(); + } + switch (select.value) { + case "ppt": + let ppt_settings = settings.global('vad_ppt_settings', undefined); + ppt_settings = ppt_settings ? JSON.parse(ppt_settings) : {}; + vad_tag.find(".vat_ppt_key").text(ppt.key_description(ppt_settings)); + vad_tag.find(".ppt-delay input").val(ppt_settings.delay === undefined ? 300 : ppt_settings.delay); + break; + case "vad": + let slider = vad_tag.find(".vad_vad_slider"); + let vad = globalClient.voiceConnection.voiceRecorder.getVADHandler(); + slider.val(vad.percentageThreshold); + slider.trigger("change"); + globalClient.voiceConnection.voiceRecorder.update(true); + vad.percentage_listener = per => { + vad_tag.find(".vad_vad_bar_filler") + .css("width", (100 - per) + "%"); + }; + break; + } + }); + { //Initialized push to talk + vad_tag.find(".vat_ppt_key").click(function () { + let modal = createModal({ + body: "", + header: () => { + let head = $.spawn("div"); + head.text(_translations.d9JSFaA1 || (_translations.d9JSFaA1 = tr("Type the key you wish"))); + head.css("background-color", "blue"); + return head; + }, + footer: "" + }); + let listener = (event) => { + if (event.type == ppt.EventType.KEY_TYPED) { + settings.changeGlobal('vad_ppt_key', undefined); //TODO remove that because its legacy shit + console.log(_translations.mjG6j0ML || (_translations.mjG6j0ML = tr("Got key %o")), event); + let ppt_settings = settings.global('vad_ppt_settings', undefined); + ppt_settings = ppt_settings ? JSON.parse(ppt_settings) : {}; + Object.assign(ppt_settings, event); + settings.changeGlobal('vad_ppt_settings', ppt_settings); + globalClient.voiceConnection.voiceRecorder.reinitialiseVAD(); + ppt.unregister_key_listener(listener); + modal.close(); + vad_tag.find(".vat_ppt_key").text(ppt.key_description(event)); + } + }; + ppt.register_key_listener(listener); + modal.open(); + }); + vad_tag.find(".ppt-delay input").on('change', event => { + let ppt_settings = settings.global('vad_ppt_settings', undefined); + ppt_settings = ppt_settings ? JSON.parse(ppt_settings) : {}; + ppt_settings.delay = event.target.valueAsNumber; + settings.changeGlobal('vad_ppt_settings', ppt_settings); + globalClient.voiceConnection.voiceRecorder.reinitialiseVAD(); + }); + } + { //Initialized voice activation detection + let slider = vad_tag.find(".vad_vad_slider"); + slider.on("input change", () => { + settings.changeGlobal("vad_threshold", slider.val().toString()); + let vad = globalClient.voiceConnection.voiceRecorder.getVADHandler(); + if (vad instanceof VoiceActivityDetectorVAD) + vad.percentageThreshold = slider.val(); + vad_tag.find(".vad_vad_slider_value").text(slider.val().toString()); + }); + modal.properties.registerCloseListener(() => { + let vad = globalClient.voiceConnection.voiceRecorder.getVADHandler(); + if (vad instanceof VoiceActivityDetectorVAD) + vad.percentage_listener = undefined; + }); + } + let target_tag = vad_tag.find('input[type=radio][name="vad_type"][value="' + currentVAD + '"]'); + if (target_tag.length == 0) { + //TODO tr + console.warn("Failed to find tag for " + currentVAD + ". Using latest tag!"); + target_tag = vad_tag.find('input[type=radio][name="vad_type"]').last(); + } + target_tag.prop("checked", true); + setTimeout(() => target_tag.trigger('change'), 0); + } + const display_error = (message) => { + const alert = tag.find(".settings-device-error").first(); + alert.clone() + .alert() + .css("display", "block") + .insertAfter(alert) + .find(".message") + .text(message); + }; + { //Initialize microphone + const setting_tag = tag.find(".settings-microphone"); + const tag_select = setting_tag.find(".audio-select-microphone"); + const update_devices = () => { + tag_select.empty(); + $.spawn("option") + .attr("device-id", "") + .attr("device-group", "") + .text(_translations.jyqAJeYM || (_translations.jyqAJeYM = tr("No device"))) + .appendTo(tag_select); + navigator.mediaDevices.enumerateDevices().then(devices => { + const active_device = globalClient.voiceConnection.voiceRecorder.device_id(); + for (const device of devices) { + console.debug(_translations.kb9gRNI1 || (_translations.kb9gRNI1 = tr("Got device %s (%s): %s (%o)")), device.deviceId, device.kind, device.label); + if (device.kind !== 'audioinput') + continue; + $.spawn("option") + .attr("device-id", device.deviceId) + .attr("device-group", device.groupId) + .text(device.label) + .prop("selected", device.deviceId == active_device) + .appendTo(tag_select); + } + }).catch(error => { + console.error(_translations.bDG4yJ1S || (_translations.bDG4yJ1S = tr("Could not enumerate over devices!"))); + console.error(error); + display_error(_translations.tL0bCP54 || (_translations.tL0bCP54 = tr("Could not get microphone device list!"))); + }); + if (tag_select.find("option:selected").length == 0) + tag_select.find("option").prop("selected", true); + }; + { + tag_select.on('change', event => { + let selected_tag = tag_select.find("option:selected"); + let deviceId = selected_tag.attr("device-id"); + let groupId = selected_tag.attr("device-group"); + console.log(_translations.cUQD3Itt || (_translations.cUQD3Itt = tr("Selected microphone device: id: %o group: %o")), deviceId, groupId); + globalClient.voiceConnection.voiceRecorder.change_device(deviceId, groupId); + }); + } + update_devices(); + setting_tag.find(".button-device-update").on('click', event => update_devices()); + } + { //Initialize speaker + const setting_tag = tag.find(".settings-speaker"); + const tag_select = setting_tag.find(".audio-select-speaker"); + const update_devices = () => { + tag_select.empty(); + const active_device = audio.player.current_device(); + audio.player.available_devices().then(devices => { + for (const device of devices) { + $.spawn("option") + .attr("device-id", device.device_id) + .text(device.name) + .prop("selected", device.device_id == active_device.device_id) + .appendTo(tag_select); + } + }).catch(error => { + console.error(_translations.fLXoZ44p || (_translations.fLXoZ44p = tr("Could not enumerate over devices!"))); + console.error(error); + display_error(_translations.giEinlmS || (_translations.giEinlmS = tr("Could not get speaker device list!"))); + }); + if (tag_select.find("option:selected").length == 0) + tag_select.find("option").prop("selected", true); + }; + { + tag_select.on('change', event => { + let selected_tag = tag_select.find("option:selected"); + let deviceId = selected_tag.attr("device-id"); + console.log(_translations._bYpHOYM || (_translations._bYpHOYM = tr("Selected speaker device: id: %o")), deviceId); + audio.player.set_device(deviceId).catch(error => { + console.error(error); + display_error(_translations.wNBrz45p || (_translations.wNBrz45p = tr("Failed to change device!"))); + }); + }); + } + update_devices(); + setting_tag.find(".button-device-update").on('click', event => update_devices()); + } + { /* initialize sounds */ + const sound_tag = tag.find(".sound-settings"); + { /* master volume */ + const master_tag = sound_tag.find(".master-volume"); + master_tag.find("input").on('change input', event => { + const value = parseInt(event.target.value); + master_tag.find('a').text("(" + value + "%)"); + sound.set_master_volume(value / 100); + }).val((sound.get_master_volume() * 100).toString()).trigger('change'); + } + { + const overlap_tag = sound_tag.find(".overlap-sounds input"); + overlap_tag.on('change', event => { + const activated = event.target.checked; + sound.set_overlap_activated(activated); + }).prop("checked", sound.overlap_activated()); + } + { + const muted_tag = sound_tag.find(".muted-sounds input"); + muted_tag.on('change', event => { + const activated = event.target.checked; + sound.set_ignore_output_muted(!activated); + }).prop("checked", !sound.ignore_output_muted()); + } + { /* sound elements */ + const template_tag = $("#tmpl_settings-sound_entry"); + const entry_tag = sound_tag.find(".sound-list-entries"); + for (const _sound in Sound) { + const sound_name = Sound[_sound]; + console.log(sound.get_sound_volume(sound_name)); + const data = { + name: sound_name, + activated: sound.get_sound_volume(sound_name) > 0 + }; + const entry = template_tag.renderTag(data); + entry.find("input").on('change', event => { + const activated = event.target.checked; + console.log(_translations.Mj83gjpx || (_translations.Mj83gjpx = tr("Sound %s had changed to %o")), sound_name, activated); + sound.set_sound_volume(sound_name, activated ? 1 : 0); + }); + entry.find(".button-playback").on('click', event => { + sound.play(sound_name); + }); + entry_tag.append(entry); + } + setTimeout(() => { + const entry_container = sound_tag.find(".sound-list-entries-container"); + if (entry_container.hasScrollBar()) + entry_container.addClass("scrollbar"); + }, 100); + /* filter */ + const filter_tag = sound_tag.find(".sound-list-filter input"); + filter_tag.on('change keyup', event => { + const filter = (event.target.value || "").toLowerCase(); + if (!filter) + entry_tag.find(".entry").show(); + else { + entry_tag.find(".entry").each((_, _entry) => { + const entry = $(_entry); + if (entry.text().toLowerCase().indexOf(filter) == -1) + entry.hide(); + else + entry.show(); + }); + } + }); + } + modal.close_listener.push(sound.save); + } + //Initialise microphones + /* + let select_microphone = tag.find(".voice_microphone_select"); + let select_error = tag.find(".voice_microphone_select_error"); + + navigator.mediaDevices.enumerateDevices().then(devices => { + let recoder = globalClient.voiceConnection.voiceRecorder; + + console.log("Got " + devices.length + " devices:"); + for(let device of devices) { + console.log(" - Type: %s Name %s ID: %s Group: %s", device.kind, device.label, device.deviceId, device.groupId); + if(device.kind == "audioinput") { + let dtag = $.spawn("option"); + dtag.attr("device-id", device.deviceId); + dtag.attr("device-group", device.groupId); + dtag.text(device.label); + select_microphone.append(dtag); + + if(recoder) dtag.prop("selected", device.deviceId == recoder.device_id()); + } + } + }).catch(error => { + console.error("Could not enumerate over devices!"); + console.error(error); + select_error.text("Could not get device list!").show(); + }); + + select_microphone.change(event => { + let deviceSelected = select_microphone.find("option:selected"); + let deviceId = deviceSelected.attr("device-id"); + let groupId = deviceSelected.attr("device-group"); + console.log("Selected microphone device: id: %o group: %o", deviceId, groupId); + globalClient.voiceConnection.voiceRecorder.change_device(deviceId, groupId); + }); + */ + //Initialise speakers + } + function initialise_translations(tag) { + { //Initialize the list + const tag_list = tag.find(".setting-list .list"); + const tag_loading = tag.find(".setting-list .loading"); + const template = $("#settings-translations-list-entry"); + const restart_hint = tag.find(".setting-list .restart-note"); + restart_hint.hide(); + const update_list = () => { + tag_list.empty(); + const currently_selected = i18n.config.translation_config().current_translation_url; + { //Default translation + const tag = template.renderTag({ + type: "default", + selected: !currently_selected || currently_selected == "default" + }); + tag.on('click', () => { + i18n.select_translation(undefined, undefined); + tag_list.find(".selected").removeClass("selected"); + tag.addClass("selected"); + restart_hint.show(); + }); + tag.appendTo(tag_list); + } + { + const display_repository_info = (repository) => { + const info_modal = createModal({ + header: _translations.R_rvWgki || (_translations.R_rvWgki = tr("Repository info")), + body: () => { + return $("#settings-translations-list-entry-info").renderTag({ + type: "repository", + name: repository.name, + url: repository.url, + contact: repository.contact, + translations: repository.translations || [] + }); + }, + footer: () => { + let footer = $.spawn("div"); + footer.addClass("modal-button-group"); + footer.css("margin-top", "5px"); + footer.css("margin-bottom", "5px"); + footer.css("text-align", "right"); + let buttonOk = $.spawn("button"); + buttonOk.text(_translations.dVaJRUpW || (_translations.dVaJRUpW = tr("Close"))); + buttonOk.click(() => info_modal.close()); + footer.append(buttonOk); + return footer; + } + }); + info_modal.open(); + }; + tag_loading.show(); + i18n.iterate_translations((repo, entry) => { + let repo_tag = tag_list.find("[repository=\"" + repo.unique_id + "\"]"); + if (repo_tag.length == 0) { + repo_tag = template.renderTag({ + type: "repository", + name: repo.name || repo.url, + id: repo.unique_id + }); + repo_tag.find(".button-delete").on('click', e => { + e.preventDefault(); + Modals.spawnYesNo(_translations.GQ7uZCIp || (_translations.GQ7uZCIp = tr("Are you sure?")), _translations.pvEhAEg0 || (_translations.pvEhAEg0 = tr("Do you really want to delete this repository?")), answer => { + if (answer) { + i18n.delete_repository(repo); + update_list(); + } + }); + }); + repo_tag.find(".button-info").on('click', e => { + e.preventDefault(); + display_repository_info(repo); + }); + tag_list.append(repo_tag); + } + const tag = template.renderTag({ + type: "translation", + name: entry.info.name || entry.url, + id: repo.unique_id, + selected: i18n.config.translation_config().current_translation_url == entry.url + }); + tag.find(".button-info").on('click', e => { + e.preventDefault(); + const info_modal = createModal({ + header: _translations.xTmVYl7B || (_translations.xTmVYl7B = tr("Translation info")), + body: () => { + const tag = $("#settings-translations-list-entry-info").renderTag({ + type: "translation", + name: entry.info.name, + url: entry.url, + repository_name: repo.name, + contributors: entry.info.contributors || [] + }); + tag.find(".button-info").on('click', () => display_repository_info(repo)); + return tag; + }, + footer: () => { + let footer = $.spawn("div"); + footer.addClass("modal-button-group"); + footer.css("margin-top", "5px"); + footer.css("margin-bottom", "5px"); + footer.css("text-align", "right"); + let buttonOk = $.spawn("button"); + buttonOk.text(_translations.t8KEieTl || (_translations.t8KEieTl = tr("Close"))); + buttonOk.click(() => info_modal.close()); + footer.append(buttonOk); + return footer; + } + }); + info_modal.open(); + }); + tag.on('click', e => { + if (e.isDefaultPrevented()) + return; + i18n.select_translation(repo, entry); + tag_list.find(".selected").removeClass("selected"); + tag.addClass("selected"); + restart_hint.show(); + }); + tag.insertAfter(repo_tag); + }, () => { + tag_loading.hide(); + }); + } + }; + { + tag.find(".button-add-repository").on('click', () => { + createInputModal("Enter URL", _translations.oGJHPfbq || (_translations.oGJHPfbq = tr("Enter repository URL:
    ")), text => true, url => { + if (!url) + return; + tag_loading.show(); + i18n.load_repository(url).then(repository => { + i18n.register_repository(repository); + update_list(); + }).catch(error => { + tag_loading.hide(); + createErrorModal("Failed to load repository", (_translations.fdSBxddp || (_translations.fdSBxddp = tr("Failed to query repository.
    Ensure that this repository is valid and reachable.
    Error: "))) + error).open(); + }); + }).open(); + }); + } + restart_hint.find(".button-reload").on('click', () => { + location.reload(); + }); + update_list(); + } + } + function initialise_profiles(modal, tag) { + const settings_tag = tag.find(".profile-settings"); + let selected_profile; + let nickname_listener; + let status_listener; + const display_settings = (profile) => { + selected_profile = profile; + settings_tag.find(".setting-name").val(profile.profile_name); + settings_tag.find(".setting-default-nickname").val(profile.default_username); + settings_tag.find(".setting-default-password").val(profile.default_password); + { + //change listener + const select_tag = settings_tag.find(".select-container select")[0]; + const type = profile.selected_identity_type.toLowerCase(); + select_tag.onchange = () => { + console.log("Selected: " + select_tag.value); + settings_tag.find(".identity-settings.active").removeClass("active"); + settings_tag.find(".identity-settings-" + select_tag.value).addClass("active"); + profile.selected_identity_type = select_tag.value.toLowerCase(); + const selected_type = profile.selected_type(); + const identity = profile.selected_identity(); + profiles.mark_need_save(); + let tag; + if (selected_type == profiles.identities.IdentitifyType.TEAFORO) { + const forum_tag = tag = settings_tag.find(".identity-settings-teaforo"); + forum_tag.find(".connected, .disconnected").hide(); + if (identity && identity.valid()) { + forum_tag.find(".connected").show(); + } + else { + forum_tag.find(".disconnected").show(); + } + } + else if (selected_type == profiles.identities.IdentitifyType.TEAMSPEAK) { + console.log("Set: " + identity); + const teamspeak_tag = tag = settings_tag.find(".identity-settings-teamspeak"); + teamspeak_tag.find(".identity_string").val(""); + if (identity) + identity.export_ts().then(e => teamspeak_tag.find(".identity_string").val(e)); + } + else if (selected_type == profiles.identities.IdentitifyType.NICKNAME) { + const name_tag = tag = settings_tag.find(".identity-settings-nickname"); + if (identity) + name_tag.find("input").val(identity.name()); + else + name_tag.find("input").val(""); + } + if (tag) + tag.trigger('show'); + }; + select_tag.value = type; + select_tag.onchange(undefined); + } + }; + const update_profile_list = () => { + const profile_list = tag.find(".profile-list .list").empty(); + const profile_template = $("#settings-profile-list-entry"); + for (const profile of profiles.profiles()) { + const list_tag = profile_template.renderTag({ + profile_name: profile.profile_name, + id: profile.id + }); + const profile_status_update = () => { + list_tag.find(".status").hide(); + if (profile.valid()) + list_tag.find(".status-valid").show(); + else + list_tag.find(".status-invalid").show(); + }; + list_tag.on('click', event => { + /* update ui */ + profile_list.find(".selected").removeClass("selected"); + list_tag.addClass("selected"); + if (profile == selected_profile) + return; + nickname_listener = () => list_tag.find(".name").text(profile.profile_name); + status_listener = profile_status_update; + display_settings(profile); + }); + profile_list.append(list_tag); + if ((!selected_profile && profile.id == "default") || selected_profile == profile) + setTimeout(() => list_tag.trigger('click'), 1); + profile_status_update(); + } + }; + const display_error = (error) => { + if (error) { + settings_tag.find(".settings-profile-error").show().find(".message").html(error); + } + else + settings_tag.find(".settings-profile-error").hide(); + status_listener(); + }; + /* identity settings */ + { + { //TeamSpeak change listener + const teamspeak_tag = settings_tag.find(".identity-settings-teamspeak"); + const identity_info_tag = teamspeak_tag.find(".identity-info"); + const button_export = teamspeak_tag.find(".button-export"); + const button_import = teamspeak_tag.find(".button-import"); + const button_generate = teamspeak_tag.find(".button-generate"); + const button_improve = teamspeak_tag.find(".button-improve"); + button_import.on('click', event => { + const profile = selected_profile.selected_identity(profiles.identities.IdentitifyType.TEAMSPEAK); + const set_identity = (identity) => { + selected_profile.set_identity(profiles.identities.IdentitifyType.TEAMSPEAK, identity); + teamspeak_tag.trigger('show'); + createInfoModal(_translations.j97itdQy || (_translations.j97itdQy = tr("Identity imported")), _translations.uq3SlGtZ || (_translations.uq3SlGtZ = tr("Your identity has been successfully imported!"))).open(); + }; + if (profile && profile.valid()) { + Modals.spawnYesNo(_translations.IuhqR8em || (_translations.IuhqR8em = tr("Are you sure")), _translations.F3qLDw6y || (_translations.F3qLDw6y = tr("Do you really want to import a new identity and override the old identity?")), result => { + if (result) + spawnTeamSpeakIdentityImport(set_identity); + }); + } + else + spawnTeamSpeakIdentityImport(set_identity); + }); + button_export.on('click', event => { + const profile = selected_profile.selected_identity(profiles.identities.IdentitifyType.TEAMSPEAK); + if (!profile) + return; + createInputModal(_translations.XNKN8L18 || (_translations.XNKN8L18 = tr("File name")), _translations.u6rghx8Y || (_translations.u6rghx8Y = tr("Please enter the file name")), text => !!text, name => { + if (name) { + profile.export_ts(true).then(data => { + const element = $.spawn("a") + .text("donwload") + .attr("href", "data:test/plain;charset=utf-8," + encodeURIComponent(data)) + .attr("download", name + ".ini") + .css("display", "none") + .appendTo($("body")); + element[0].click(); + element.detach(); + }).catch(error => { + console.error(error); + createErrorModal(_translations.aZI_J5tO || (_translations.aZI_J5tO = tr("Failed to export identity")), (_translations.DLdFWwPd || (_translations.DLdFWwPd = tr("Failed to export and save identity.
    Error: "))) + error).open(); + }); + } + }).open(); + }); + button_generate.on('click', event => { + const profile = selected_profile.selected_identity(profiles.identities.IdentitifyType.TEAMSPEAK); + const generate_identity = () => { + profiles.identities.TeaSpeakIdentity.generate_new().then(identity => { + selected_profile.set_identity(profiles.identities.IdentitifyType.TEAMSPEAK, identity); + teamspeak_tag.trigger('show'); + createInfoModal(_translations.x8afoFoc || (_translations.x8afoFoc = tr("Identity generate")), _translations.ynFYOHQs || (_translations.ynFYOHQs = tr("A new identity had been successfully generated"))).open(); + }).catch(error => { + console.error(_translations.mfN6hbkM || (_translations.mfN6hbkM = tr("Failed to generate a new identity. Error object: %o")), error); + createErrorModal(_translations.YH0Js1Ll || (_translations.YH0Js1Ll = tr("Failed to generate identity")), (_translations.ZCXXZ5WL || (_translations.ZCXXZ5WL = tr("Failed to generate a new identity.
    Error:"))) + error).open(); + }); + }; + if (profile && profile.valid()) { + Modals.spawnYesNo(_translations.tnuGGElr || (_translations.tnuGGElr = tr("Are you sure")), _translations.GWA7WrRm || (_translations.GWA7WrRm = tr("Do you really want to generate a new identity and override the old identity?")), result => { + if (result) + generate_identity(); + }); + } + else + generate_identity(); + }); + button_improve.on('click', event => { + const profile = selected_profile.selected_identity(profiles.identities.IdentitifyType.TEAMSPEAK); + if (!profile) + return; + spawnTeamSpeakIdentityImprove(profile).close_listener.push(() => teamspeak_tag.trigger('show')); + }); + /* updates the data */ + teamspeak_tag.on('show', event => { + const profile = selected_profile.selected_identity(profiles.identities.IdentitifyType.TEAMSPEAK); + if (!profile || !profile.valid()) { + identity_info_tag.hide(); + teamspeak_tag.find(".identity-undefined").show(); + button_export.prop("disabled", true); + } + else { + identity_info_tag.show(); + teamspeak_tag.find(".identity-undefined").hide(); + button_export.prop("disabled", false); + identity_info_tag.find(".unique-id input").val(profile.uid()); + const input_level = identity_info_tag.find(".level input").val("loading..."); + profile.level().then(level => input_level.val(level.toString())).catch(error => input_level.val("error: " + error)); + } + display_error(); + }); + } + { //The forum + const teaforo_tag = settings_tag.find(".identity-settings-teaforo"); + if (native_client) { + teaforo_tag.find(".native-teaforo-login").on('click', event => { + setTimeout(() => { + const forum = require("teaforo.js"); + const call = () => { + if (modal.shown) { + display_settings(selected_profile); + status_listener(); + } + }; + forum.register_callback(call); + forum.open(); + }, 0); + }); + } + teaforo_tag.on('show', event => { + display_error(); /* clear error */ + }); + } + { //The name + const name_tag = settings_tag.find(".identity-settings-nickname"); + name_tag.find(".setting-name").on('change keyup', event => { + const name = name_tag.find(".setting-name").val(); + selected_profile.set_identity(profiles.identities.IdentitifyType.NICKNAME, new profiles.identities.NameIdentity(name)); + profiles.mark_need_save(); + if (name.length < 3) { + display_error("Name must be at least 3 characters long!"); + return; + } + display_error(); + }); + name_tag.on('show', event => { + const profile = selected_profile.selected_identity(profiles.identities.IdentitifyType.NICKNAME); + if (!profile) + display_error("invalid profile"); + else if (!profile.valid()) + display_error("Name must be at least 3 characters long!"); + else + display_error(); + }); + } + } + /* general settings */ + { + settings_tag.find(".setting-name").on('change', event => { + const value = settings_tag.find(".setting-name").val(); + if (value && selected_profile) { + selected_profile.profile_name = value; + if (nickname_listener) + nickname_listener(); + profiles.mark_need_save(); + status_listener(); + } + }); + settings_tag.find(".setting-default-nickname").on('change', event => { + const value = settings_tag.find(".setting-default-nickname").val(); + if (value && selected_profile) { + selected_profile.default_username = value; + profiles.mark_need_save(); + status_listener(); + } + }); + settings_tag.find(".setting-default-password").on('change', event => { + const value = settings_tag.find(".setting-default-password").val(); + if (value && selected_profile) { + selected_profile.default_username = value; + profiles.mark_need_save(); + status_listener(); + } + }); + } + /* general buttons */ + { + tag.find(".button-add-profile").on('click', event => { + createInputModal(_translations.IaVpSbUr || (_translations.IaVpSbUr = tr("Please enter a name")), _translations.DXtYBVnN || (_translations.DXtYBVnN = tr("Please enter a name for the new profile:
    ")), text => text.length > 0 && !profiles.find_profile_by_name(text), value => { + if (value) { + display_settings(profiles.create_new_profile(value)); + update_profile_list(); + profiles.mark_need_save(); + } + }).open(); + }); + tag.find(".button-set-default").on('click', event => { + if (selected_profile && selected_profile.id != 'default') { + profiles.set_default_profile(selected_profile); + update_profile_list(); + profiles.mark_need_save(); + } + }); + tag.find(".button-delete").on('click', event => { + if (selected_profile && selected_profile.id != 'default') { + event.preventDefault(); + Modals.spawnYesNo(_translations.En9YP_2L || (_translations.En9YP_2L = tr("Are you sure?")), _translations.tQHWsdmy || (_translations.tQHWsdmy = tr("Do you really want to delete this profile?")), result => { + if (result) { + profiles.delete_profile(selected_profile); + update_profile_list(); + } + }); + } + }); + } + modal.close_listener.push(() => { + if (profiles.requires_save()) + profiles.save(); + }); + update_profile_list(); + } +})(Modals || (Modals = {})); +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["8066716c36e5b50be5b873a38c0887fa3845473643d72e3e801f31873194ce41"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["8066716c36e5b50be5b873a38c0887fa3845473643d72e3e801f31873194ce41"] = "8066716c36e5b50be5b873a38c0887fa3845473643d72e3e801f31873194ce41"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "xEzPwX5F", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalBanList.ts (36,29)" }, { name: "_zgMdWvL", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalBanList.ts (50,38)" }, { name: "cBb82yEw", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalBanList.ts (54,25)" }, { name: "LknfHAUI", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalBanList.ts (56,29)" }, { name: "crqIN56n", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalBanList.ts (72,38)" }, { name: "IfovotkL", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalBanList.ts (76,25)" }, { name: "N0nYzXYj", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalBanList.ts (84,34)" }, { name: "xmKQAikZ", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalBanList.ts (92,29)" }, { name: "nmdJ5Rwk", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalBanList.ts (176,26)" }, { name: "Ba0xrSlB", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalBanList.ts (185,26)" }, { name: "BqwjkvXy", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalBanList.ts (191,21)" }, { name: "fKqJzgya", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalBanList.ts (233,25)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +var Modals; +(function (Modals) { + function openBanList(client) { + let update; + const modal = spawnBanListModal(() => update(), () => { + Modals.spawnBanCreate(undefined, result => { + if (result.server_id < 0) + result.server_id = undefined; + console.log(_translations.xEzPwX5F || (_translations.xEzPwX5F = tr("Adding ban %o")), result); + client.serverConnection.send_command("banadd", { + ip: result.ip, + name: result.name, + uid: result.unique_id, + hwid: result.hardware_id, + banreason: result.reason, + time: result.timestamp_expire.getTime() > 0 ? (result.timestamp_expire.getTime() - result.timestamp_created.getTime()) / 1000 : 0, + sid: result.server_id + }).then(() => { + update(); + }).catch(error => { + //TODO tr + createErrorModal(_translations._zgMdWvL || (_translations._zgMdWvL = tr("Failed to add ban")), "Failed to add ban.
    Reason: " + (error instanceof CommandResult ? error.extra_message || error.message : error)).open(); + }); + }); + }, ban => { + console.log(_translations.cBb82yEw || (_translations.cBb82yEw = tr("Editing ban %o")), ban); + Modals.spawnBanCreate(ban, result => { + console.log(_translations.LknfHAUI || (_translations.LknfHAUI = tr("Apply edit changes %o")), result); + if (result.server_id < 0) + result.server_id = undefined; + client.serverConnection.send_command("banedit", { + banid: result.banid, + ip: result.ip, + name: result.name, + uid: result.unique_id, + hwid: result.hardware_id, + banreason: result.reason, + time: result.timestamp_expire.getTime() > 0 ? (result.timestamp_expire.getTime() - result.timestamp_created.getTime()) / 1000 : 0, + sid: result.server_id + }).then(() => { + update(); + }).catch(error => { + //TODO tr + createErrorModal(_translations.crqIN56n || (_translations.crqIN56n = tr("Failed to edit ban")), "Failed to edit ban.
    Reason: " + (error instanceof CommandResult ? error.extra_message || error.message : error)).open(); + }); + }); + }, ban => { + console.log(_translations.IfovotkL || (_translations.IfovotkL = tr("Deleting ban %o")), ban); + client.serverConnection.send_command("bandel", { + banid: ban.banid, + sid: ban.server_id + }).then(() => { + update(); + }).catch(error => { + //TODO tr + createErrorModal(_translations.N0nYzXYj || (_translations.N0nYzXYj = tr("Failed to delete ban")), "Failed to delete ban.
    Reason: " + (error instanceof CommandResult ? error.extra_message || error.message : error)).open(); + }); + }); + const single_handler = { + command: "notifybanlist", + function: command => { + const json = command.arguments; + console.log(_translations.xmKQAikZ || (_translations.xmKQAikZ = tr("Got banlist: %o")), json); + let bans = []; + for (const entry of json) { + /* + notify[index]["sid"] = elm->serverId; + notify[index]["banid"] = elm->banId; + if(allow_ip) + notify[index]["ip"] = elm->ip; + else + notify[index]["ip"] = "hidden"; + notify[index]["name"] = elm->name; + notify[index]["uid"] = elm->uid; + notify[index]["lastnickname"] = elm->name; //Maybe update? + + notify[index]["created"] = chrono::duration_cast(elm->created.time_since_epoch()).count(); + if (elm->until.time_since_epoch().count() != 0) + notify[index]["duration"] = chrono::duration_cast(elm->until - elm->created).count(); + else + notify[index]["duration"] = 0; + + notify[index]["reason"] = elm->reason; + notify[index]["enforcements"] = elm->triggered; + + notify[index]["invokername"] = elm->invokerName; + notify[index]["invokercldbid"] = elm->invokerDbId; + notify[index]["invokeruid"] = elm->invokerUid; + */ + bans.push({ + server_id: parseInt(entry["sid"]), + banid: parseInt(entry["banid"]), + ip: entry["ip"], + name: entry["name"], + unique_id: entry["uid"], + hardware_id: entry["hwid"], + timestamp_created: new Date(parseInt(entry["created"]) * 1000), + timestamp_expire: new Date(parseInt(entry["duration"]) > 0 ? parseInt(entry["created"]) * 1000 + parseInt(entry["duration"]) * 1000 : 0), + invoker_name: entry["invokername"], + invoker_database_id: parseInt(entry["invokercldbid"]), + invoker_unique_id: entry["invokeruid"], + reason: entry["reason"], + enforcements: parseInt(entry["enforcements"]), + flag_own: entry["invokeruid"] == client.getClient().properties.client_unique_identifier + }); + } + modal.addbans(bans); + return false; + } + }; + client.serverConnection.command_handler_boss().register_single_handler(single_handler); + modal.modal.close_listener.push(() => { + client.serverConnection.command_handler_boss().remove_single_handler(single_handler); + }); + update = () => { + //TODO test permission + modal.clear(); + client.serverConnection.send_command("banlist", { sid: 0 }); //Global ban list + client.serverConnection.send_command("banlist").catch(error => { + if (error instanceof CommandResult) { + } + else { + console.error(error); + } + }); + }; + update(); + } + Modals.openBanList = openBanList; + function spawnBanListModal(callback_update, callback_add, callback_edit, callback_delete) { + let result = {}; + let entries = []; + const _callback_edit = ban_id => { + for (const entry of entries) + if (entry.banid == ban_id) { + callback_edit(entry); + return; + } + console.warn(_translations.nmdJ5Rwk || (_translations.nmdJ5Rwk = tr("Missing ban entry with id %d")), ban_id); + }; + const _callback_delete = ban_id => { + for (const entry of entries) + if (entry.banid == ban_id) { + callback_delete(entry); + return; + } + console.warn(_translations.Ba0xrSlB || (_translations.Ba0xrSlB = tr("Missing ban entry with id %d")), ban_id); + }; + let update_function; + let modal; + modal = createModal({ + header: _translations.BqwjkvXy || (_translations.BqwjkvXy = tr("Banlist")), + body: () => { + let template = $("#tmpl_ban_list").renderTag(); + apply_filter(template.find(".entry-filter"), template.find(".filter-flag-force-own"), template.find(".filter-flag-highlight-own"), template.find(".ban-entry-list")); + update_function = apply_buttons(template.find(".manage-buttons"), template.find(".entry-container .entries"), callback_add, _callback_edit, _callback_delete); + template.find(".button-close").on('click', _ => modal.close()); + template.find(".button-refresh").on('click', () => callback_update()); + return template; + }, + footer: undefined, + width: "80%", + height: "80%" + }); + modal.open(); + modal.close_listener.push(() => entries = []); + const template_entry = $("#tmpl_ban_entry"); + result.addbans = (bans) => { + for (const entry of bans) { + entries.push(entry); + template_entry.renderTag(entry).appendTo(modal.htmlTag.find(".entry-container .entries")); + } + modal.htmlTag.find(".entry-filter").trigger("change"); + update_function(); + }; + result.clear = () => { + entries = []; + modal.htmlTag.find(".entry-container .entries").children().detach(); + update_function(); + }; + result.modal = modal; + return result; + } + Modals.spawnBanListModal = spawnBanListModal; + function apply_filter(input, show_own_bans, highlight_own_bans, elements) { + input.on('keyup change', event => { + const filter = input.val().trim(); + const show_own_only = show_own_bans.prop("checked"); + const highlight_own = highlight_own_bans.prop("checked"); + console.log(_translations.fKqJzgya || (_translations.fKqJzgya = tr("Search for filter %s")), filter); + let shown = 0, hidden = 0; + elements.find(".ban-entry").each((_idx, _entry) => { + const entry = $(_entry); + if (entry.hasClass("ban-entry-own")) { + if (highlight_own) + entry.addClass("ban-entry-own-bold"); + else + entry.removeClass("ban-entry-own-bold"); + } + else if (show_own_only) { + if (entry.hide().hasClass("selected")) + entry.trigger("click"); + hidden++; + return; + } + if (filter.length == 0 || entry.text().indexOf(filter) > 0) { + entry.show(); + shown++; + } + else { + if (entry.hide().hasClass("selected")) + entry.trigger("click"); + hidden++; + } + }); + $(".entry-count-info").text((shown + hidden) + " entries. " + shown + " entries shown"); + }); + show_own_bans.on('click', () => input.trigger('change')); + highlight_own_bans.on('click', () => input.trigger('change')); + } + function apply_buttons(tag, elements, cb_add, cb_edit, cb_delete) { + const update = () => { + console.log(elements.find(".ban-entry.selected").length); + $(".button-edit, .button-remove").prop("disabled", elements.find(".ban-entry.selected").length == 0); + }; + tag.find(".button-add").on('click', event => cb_add()); + tag.find(".button-edit").on('click', event => { + const selected = elements.find(".ban-entry.selected"); + if (!selected) + return; + cb_edit(parseInt(selected.attr("ban-id"))); + }); + tag.find(".button-remove").on('click', event => { + const selected = elements.find(".ban-entry.selected"); + if (!selected) + return; + cb_delete(parseInt(selected.attr("ban-id"))); + }); + const element_selected = element => { + elements.find(".ban-entry").removeClass("selected"); + if (element.is(":visible")) + element.addClass("selected"); + update(); + }; + const click_handler = event => element_selected($(event.currentTarget)); + const context_handler = event => { + const element = $(event.currentTarget); + element_selected(element); + event.preventDefault(); + spawn_context_menu(event.pageX, event.pageY, { + name: "Edit", + type: MenuEntryType.ENTRY, + callback: () => cb_edit(parseInt(element.attr("ban-id"))) + }, { + name: "Delete", + type: MenuEntryType.ENTRY, + callback: () => cb_delete(parseInt(element.attr("ban-id"))) + }); + }; + return () => { + elements.find(".ban-entry").each((_idx, _entry) => { + _entry.addEventListener("click", click_handler); + _entry.addEventListener("contextmenu", context_handler); + }); + update(); + }; + } +})(Modals || (Modals = {})); +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["ea246f47b86a1f3980314e24ff4859690e9e4f0a7be06be3102c8e81d6541f83"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["ea246f47b86a1f3980314e24ff4859690e9e4f0a7be06be3102c8e81d6541f83"] = "ea246f47b86a1f3980314e24ff4859690e9e4f0a7be06be3102c8e81d6541f83"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "my8hxlKB", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/ControlBar.ts (109,26)" }, { name: "AWWxOq6S", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/ControlBar.ts (109,50)" }, { name: "UZAOab6m", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/ControlBar.ts (230,30)" }, { name: "J6wF_VJg", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/ControlBar.ts (230,63)" }, { name: "ZlcA0t6X", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/ControlBar.ts (273,26)" }, { name: "wK8ikYh2", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/ControlBar.ts (273,43)" }, { name: "Y59uaHGW", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/ControlBar.ts (279,37)" }, { name: "lv404I8O", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/ControlBar.ts (279,54)" }, { name: "s4M7Bo9c", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/ControlBar.ts (282,38)" }, { name: "osnGlNqU", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/ControlBar.ts (288,26)" }, { name: "qiooa_qH", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/ControlBar.ts (288,49)" }, { name: "RW7ji6sK", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/ControlBar.ts (306,30)" }, { name: "SHNh0XMm", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/ControlBar.ts (306,66)" }, { name: "k6lZeW4L", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/ControlBar.ts (313,30)" }, { name: "YRGt3SGU", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/ControlBar.ts (313,58)" }, { name: "Ooqjp5G0", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/ControlBar.ts (327,30)" }, { name: "GNCPCtA5", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/ControlBar.ts (327,62)" }, { name: "WLOZ7vRh", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/ControlBar.ts (447,30)" }, { name: "mwo0IEKd", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/ControlBar.ts (447,66)" }, { name: "CK1J9YhU", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/ControlBar.ts (456,30)" }, { name: "ODydgt3V", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/ControlBar.ts (456,62)" }, { name: "_VLMFimn", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/ControlBar.ts (464,30)" }, { name: "nEfbnQ1a", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/frames/ControlBar.ts (464,62)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +/// +/// +/// +/* + client_output_hardware Value: '1' + client_output_muted Value: '0' + client_outputonly_muted Value: '0' + + client_input_hardware Value: '1' + client_input_muted Value: '0' + + client_away Value: '0' + client_away_message Value: '' + */ +class ControlBar { + constructor(handle, htmlTag) { + this.codec_supported = false; + this.support_playback = false; + this.support_record = false; + this.handle = handle; + this.htmlTag = htmlTag; + } + initialise() { + this.htmlTag.find(".btn_connect").on('click', this.onConnect.bind(this)); + this.htmlTag.find(".btn_disconnect").on('click', this.onDisconnect.bind(this)); + this.htmlTag.find(".btn_mute_input").on('click', this.onInputMute.bind(this)); + this.htmlTag.find(".btn_mute_output").on('click', this.onOutputMute.bind(this)); + this.htmlTag.find(".btn_open_settings").on('click', this.onOpenSettings.bind(this)); + this.htmlTag.find(".btn_permissions").on('click', this.onPermission.bind(this)); + this.htmlTag.find(".btn_banlist").on('click', this.onBanlist.bind(this)); + this.htmlTag.find(".button-playlist-manage").on('click', this.on_playlist_manage.bind(this)); + { + let tokens = this.htmlTag.find(".btn_token"); + tokens.find(".button-dropdown").on('click', () => { + tokens.find(".dropdown").addClass("displayed"); + }); + tokens.on('mouseleave', () => { + tokens.find(".dropdown").removeClass("displayed"); + }); + tokens.find(".btn_token_use").on('click', this.on_token_use.bind(this)); + tokens.find(".btn_token_list").on('click', this.on_token_list.bind(this)); + } + { + let away = this.htmlTag.find(".btn_away"); + away.find(".button-dropdown").on('click', () => { + away.find(".dropdown").addClass("displayed"); + }); + away.on('mouseleave', () => { + away.find(".dropdown").removeClass("displayed"); + }); + away.find(".btn_away_toggle").on('click', this.on_away_toggle.bind(this)); + away.find(".btn_away_message").on('click', this.on_away_set_message.bind(this)); + } + { + let bookmark = this.htmlTag.find(".btn_bookmark"); + bookmark.find(".button-dropdown").on('click', () => { + bookmark.find("> .dropdown").addClass("displayed"); + }); + bookmark.on('mouseleave', () => { + bookmark.find("> .dropdown").removeClass("displayed"); + }); + bookmark.find(".btn_bookmark_list").on('click', this.on_bookmark_manage.bind(this)); + bookmark.find(".btn_bookmark_add").on('click', this.on_bookmark_server_add.bind(this)); + this.update_bookmarks(); + this.update_bookmark_status(); + } + { + let query = this.htmlTag.find(".btn_query"); + query.find(".button-dropdown").on('click', () => { + query.find(".dropdown").addClass("displayed"); + }); + query.on('mouseleave', () => { + query.find(".dropdown").removeClass("displayed"); + }); + query.find(".btn_query_toggle").on('click', this.on_query_visibility_toggle.bind(this)); + query.find(".btn_query_create").on('click', this.on_query_create.bind(this)); + query.find(".btn_query_manage").on('click', this.on_query_manage.bind(this)); + } + //Need an initialise + this.muteInput = settings.static_global("mute_input", false); + this.muteOutput = settings.static_global("mute_output", false); + this.query_visible = settings.static_global("show_server_queries", false); + } + on_away_toggle() { + this._awayMessage = ""; + this.away = !this._away; + } + on_away_set_message() { + createInputModal(_translations.my8hxlKB || (_translations.my8hxlKB = tr("Set away message")), _translations.AWWxOq6S || (_translations.AWWxOq6S = tr("Please enter the away message")), message => true, message => { + if (message) + this.away = message; + }).open(); + } + onInputMute() { + this.muteInput = !this._muteInput; + } + onOutputMute() { + this.muteOutput = !this._muteOutput; + } + set muteInput(flag) { + if (this._muteInput == flag) + return; + this._muteInput = flag; + let tag = this.htmlTag.find(".btn_mute_input"); + if (flag) { + if (!tag.hasClass("activated")) + tag.addClass("activated"); + tag.find(".icon_x32").attr("class", "icon_x32 client-input_muted"); + } + else { + if (tag.hasClass("activated")) + tag.removeClass("activated"); + tag.find(".icon_x32").attr("class", "icon_x32 client-capture"); + } + if (this.handle.serverConnection.connected) + this.handle.serverConnection.send_command("clientupdate", { + client_input_muted: this._muteInput + }); + settings.changeGlobal("mute_input", this._muteInput); + this.updateMicrophoneRecordState(); + } + get muteOutput() { return this._muteOutput; } + set muteOutput(flag) { + if (this._muteOutput == flag) + return; + this._muteOutput = flag; + let tag = this.htmlTag.find(".btn_mute_output"); + if (flag) { + if (!tag.hasClass("activated")) + tag.addClass("activated"); + tag.find(".icon_x32").attr("class", "icon_x32 client-output_muted"); + } + else { + if (tag.hasClass("activated")) + tag.removeClass("activated"); + tag.find(".icon_x32").attr("class", "icon_x32 client-volume"); + } + if (this.handle.serverConnection.connected) + this.handle.serverConnection.send_command("clientupdate", { + client_output_muted: this._muteOutput + }); + settings.changeGlobal("mute_output", this._muteOutput); + this.updateMicrophoneRecordState(); + } + set away(value) { + if (typeof (value) == "boolean") { + if (this._away == value) + return; + this._away = value; + this._awayMessage = ""; + } + else { + this._awayMessage = value; + this._away = true; + } + let tag = this.htmlTag.find(".btn_away_toggle"); + if (this._away) { + tag.addClass("activated"); + } + else { + tag.removeClass("activated"); + } + if (this.handle.serverConnection.connected) + this.handle.serverConnection.send_command("clientupdate", { + client_away: this._away, + client_away_message: this._awayMessage + }); + this.updateMicrophoneRecordState(); + } + updateMicrophoneRecordState() { + let enabled = !this._muteInput && !this._muteOutput && !this._away; + this.handle.voiceConnection.voiceRecorder.update(enabled); + } + updateProperties() { + if (this.handle.serverConnection.connected) + this.handle.serverConnection.send_command("clientupdate", { + client_input_muted: this._muteInput, + client_output_muted: this._muteOutput, + client_away: this._away, + client_away_message: this._awayMessage, + client_input_hardware: this.codec_supported && this.support_record, + client_output_hardware: this.codec_supported && this.support_playback + }); + } + updateVoice(targetChannel) { + if (!targetChannel) + targetChannel = this.handle.getClient().currentChannel(); + let client = this.handle.getClient(); + this.codec_supported = targetChannel ? this.handle.voiceConnection.codecSupported(targetChannel.properties.channel_codec) : true; + this.support_record = this.handle.voiceConnection.voice_send_support(); + this.support_playback = this.handle.voiceConnection.voice_playback_support(); + this.htmlTag.find(".btn_mute_input").prop("disabled", !this.codec_supported || !this.support_playback || !this.support_record); + this.htmlTag.find(".btn_mute_output").prop("disabled", !this.codec_supported || !this.support_playback); + this.handle.serverConnection.send_command("clientupdate", { + client_input_hardware: this.codec_supported && this.support_record, + client_output_hardware: this.codec_supported && this.support_playback + }); + if (!this.codec_supported) + createErrorModal(_translations.UZAOab6m || (_translations.UZAOab6m = tr("Channel codec unsupported")), _translations.J6wF_VJg || (_translations.J6wF_VJg = tr("This channel has an unsupported codec.
    You cant speak or listen to anybody within this channel!"))).open(); + /* Update these properties anyways (for case the server fails to handle the command) */ + client.updateVariables({ key: "client_input_hardware", value: (this.codec_supported && this.support_record) + "" }, { key: "client_output_hardware", value: (this.codec_supported && this.support_playback) + "" }); + } + onOpenSettings() { + Modals.spawnSettingsModal(); + } + onConnect() { + this.handle.cancel_reconnect(); + Modals.spawnConnectModal({ + url: "ts.TeaSpeak.de", + enforce: false + }); + } + update_connection_state() { + switch (this.handle.serverConnection ? this.handle.serverConnection._connectionState : ConnectionState.UNCONNECTED) { + case ConnectionState.CONNECTED: + case ConnectionState.CONNECTING: + case ConnectionState.INITIALISING: + this.htmlTag.find(".btn_disconnect").show(); + this.htmlTag.find(".btn_connect").hide(); + break; + default: + this.htmlTag.find(".btn_disconnect").hide(); + this.htmlTag.find(".btn_connect").show(); + } + } + onDisconnect() { + this.handle.cancel_reconnect(); + this.handle.handleDisconnect(DisconnectReason.REQUESTED); //TODO message? + this.update_connection_state(); + sound.play(Sound.CONNECTION_DISCONNECTED); + } + on_token_use() { + createInputModal(_translations.ZlcA0t6X || (_translations.ZlcA0t6X = tr("Use token")), _translations.wK8ikYh2 || (_translations.wK8ikYh2 = tr("Please enter your token/priviledge key")), message => message.length > 0, result => { + if (!result) + return; + if (this.handle.serverConnection.connected) + this.handle.serverConnection.send_command("tokenuse", { + token: result + }).then(() => { + createInfoModal(_translations.Y59uaHGW || (_translations.Y59uaHGW = tr("Use token")), _translations.lv404I8O || (_translations.lv404I8O = tr("Toke successfully used!"))).open(); + }).catch(error => { + //TODO tr + createErrorModal(_translations.s4M7Bo9c || (_translations.s4M7Bo9c = tr("Use token")), "Failed to use token: " + (error instanceof CommandResult ? error.message : error)).open(); + }); + }).open(); + } + on_token_list() { + createErrorModal(_translations.osnGlNqU || (_translations.osnGlNqU = tr("Not implemented")), _translations.qiooa_qH || (_translations.qiooa_qH = tr("Token list is not implemented yet!"))).open(); + } + onPermission() { + let button = this.htmlTag.find(".btn_permissions"); + button.addClass("activated"); + setTimeout(() => { + Modals.spawnPermissionEdit().open(); + button.removeClass("activated"); + }, 0); + } + onBanlist() { + if (!this.handle.serverConnection) + return; + if (this.handle.permissions.neededPermission(PermissionType.B_CLIENT_BAN_LIST).granted(1)) { + Modals.openBanList(this.handle); + } + else { + createErrorModal(_translations.RW7ji6sK || (_translations.RW7ji6sK = tr("You dont have the permission")), _translations.SHNh0XMm || (_translations.SHNh0XMm = tr("You dont have the permission to view the ban list"))).open(); + sound.play(Sound.ERROR_INSUFFICIENT_PERMISSIONS); + } + } + on_bookmark_server_add() { + if (globalClient && globalClient.connected) { + createInputModal(_translations.k6lZeW4L || (_translations.k6lZeW4L = tr("Enter bookmarks name")), _translations.YRGt3SGU || (_translations.YRGt3SGU = tr("Please enter the bookmarks name:
    ")), text => true, result => { + if (result) { + const bookmark = bookmarks.create_bookmark(result, bookmarks.bookmarks(), { + server_port: globalClient.serverConnection._remote_address.port, + server_address: globalClient.serverConnection._remote_address.host, + server_password: "", + server_password_hash: "" + }, globalClient.getClient().clientNickName()); + bookmarks.save_bookmark(bookmark); + this.update_bookmarks(); + } + }).open(); + } + else { + createErrorModal(_translations.Ooqjp5G0 || (_translations.Ooqjp5G0 = tr("You have to be connected")), _translations.GNCPCtA5 || (_translations.GNCPCtA5 = tr("You have to be connected!"))).open(); + } + } + update_bookmark_status() { + this.htmlTag.find(".btn_bookmark_add").removeClass("hidden").addClass("disabled"); + this.htmlTag.find(".btn_bookmark_remove").addClass("hidden"); + } + update_bookmarks() { + // + let tag_bookmark = this.htmlTag.find(".btn_bookmark .dropdown"); + tag_bookmark.find(".bookmark, .directory").detach(); + const build_entry = (bookmark) => { + if (bookmark.type == bookmarks.BookmarkType.ENTRY) { + const mark = bookmark; + return $.spawn("div") + .addClass("bookmark") + .append($.spawn("div").addClass("icon client-server")) + .append($.spawn("div") + .addClass("name") + .text(bookmark.display_name) + .on('click', event => { + this.htmlTag.find(".btn_bookmark").find(".dropdown").removeClass("displayed"); + const profile = profiles.find_profile(mark.connect_profile) || profiles.default_profile(); + if (profile.valid()) { + this.handle.startConnection(mark.server_properties.server_address + ":" + mark.server_properties.server_port, profile, mark.nickname, { + password: mark.server_properties.server_password_hash, + hashed: true + }); + } + else { + Modals.spawnConnectModal({ + url: mark.server_properties.server_address + ":" + mark.server_properties.server_port, + enforce: true + }, { + profile: profile, + enforce: true + }); + } + })); + } + else { + const mark = bookmark; + const container = $.spawn("div").addClass("sub-menu dropdown"); + for (const member of mark.content) + container.append(build_entry(member)); + return $.spawn("div") + .addClass("directory") + .append($.spawn("div").addClass("icon client-folder")) + .append($.spawn("div") + .addClass("name") + .text(bookmark.display_name)) + .append($.spawn("div").addClass("arrow right")) + .append($.spawn("div").addClass("sub-container") + .append(container)); + } + }; + for (const bookmark of bookmarks.bookmarks().content) { + const entry = build_entry(bookmark); + tag_bookmark.append(entry); + } + } + on_bookmark_manage() { + Modals.spawnBookmarkModal(); + } + get query_visible() { + return this._query_visible; + } + set query_visible(flag) { + console.error(flag); + if (this._query_visible == flag) + return; + this._query_visible = flag; + settings.changeGlobal("show_server_queries", flag); + this.update_query_visibility_button(); + this.handle.channelTree.toggle_server_queries(flag); + } + on_query_visibility_toggle() { + this.query_visible = !this._query_visible; + this.update_query_visibility_button(); + } + update_query_visibility_button() { + let tag = this.htmlTag.find(".btn_query_toggle"); + if (this._query_visible) { + tag.addClass("activated"); + } + else { + tag.removeClass("activated"); + } + } + on_query_create() { + if (this.handle.permissions.neededPermission(PermissionType.B_CLIENT_CREATE_MODIFY_SERVERQUERY_LOGIN).granted(1)) { + Modals.spawnQueryCreate(); + } + else { + createErrorModal(_translations.WLOZ7vRh || (_translations.WLOZ7vRh = tr("You dont have the permission")), _translations.mwo0IEKd || (_translations.mwo0IEKd = tr("You dont have the permission to create a server query login"))).open(); + sound.play(Sound.ERROR_INSUFFICIENT_PERMISSIONS); + } + } + on_query_manage() { + if (globalClient && globalClient.connected) { + Modals.spawnQueryManage(globalClient); + } + else { + createErrorModal(_translations.CK1J9YhU || (_translations.CK1J9YhU = tr("You have to be connected")), _translations.ODydgt3V || (_translations.ODydgt3V = tr("You have to be connected!"))).open(); + } + } + on_playlist_manage() { + if (this.handle && this.handle.connected) { + Modals.spawnPlaylistManage(this.handle); + } + else { + createErrorModal(_translations._VLMFimn || (_translations._VLMFimn = tr("You have to be connected")), _translations.nEfbnQ1a || (_translations.nEfbnQ1a = tr("You have to be connected to use this function!"))).open(); + } + } +} +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["c2be6d3793b763169d17f03b4957ab4eb0699f1817032fe7c2b6e0c635416ce8"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["c2be6d3793b763169d17f03b4957ab4eb0699f1817032fe7c2b6e0c635416ce8"] = "c2be6d3793b763169d17f03b4957ab4eb0699f1817032fe7c2b6e0c635416ce8"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "JAEWtQTW", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/client.ts (99,21)" }, { name: "bV4lkvkA", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/client.ts (107,34)" }, { name: "u8qFbvGn", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/client.ts (107,70)" }, { name: "p_L1zpOY", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/client.ts (144,30)" }, { name: "mkYBZI51", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/client.ts (183,51)" }, { name: "i13Qq5lP", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/client.ts (186,31)" }, { name: "cVoTk97h", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/client.ts (190,25)" }, { name: "KCk709tI", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/client.ts (191,25)" }, { name: "mq0BoYHj", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/client.ts (196,25)" }, { name: "wCe7uH8c", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/client.ts (206,31)" }, { name: "Jx6FIucL", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/client.ts (208,21)" }, { name: "ckq4sOQG", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/client.ts (209,21)" }, { name: "CpO5hsYt", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/client.ts (213,31)" }, { name: "gQT1woZd", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/client.ts (215,21)" }, { name: "d4MTpRCT", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/client.ts (216,21)" }, { name: "JT_pws6H", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/client.ts (223,31)" }, { name: "rUpUHlzi", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/client.ts (226,21)" }, { name: "_lZjyLc0", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/client.ts (227,21)" }, { name: "NeJK3Ye8", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/client.ts (232,47)" }, { name: "PsDVUZ4O", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/client.ts (234,21)" }, { name: "k9_p6t0P", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/client.ts (243,47)" }, { name: "vgqAaBSb", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/client.ts (244,34)" }, { name: "nYEz_XI9", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/client.ts (244,57)" }, { name: "Lq3w511A", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/client.ts (253,47)" }, { name: "tqIlSIVg", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/client.ts (260,47)" }, { name: "rLg_S2Tb", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/client.ts (266,31)" }, { name: "AwKnUotx", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/client.ts (267,31)" }, { name: "bMtuaii5", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/client.ts (281,29)" }, { name: "uS396luz", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/client.ts (284,45)" }, { name: "dDHTCdwB", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/client.ts (286,25)" }, { name: "BmUuHG2D", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/client.ts (294,49)" }, { name: "Zt58aq4G", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/client.ts (295,29)" }, { name: "AWIMAHNY", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/client.ts (304,45)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +var DisconnectReason; +(function (DisconnectReason) { + DisconnectReason[DisconnectReason["REQUESTED"] = 0] = "REQUESTED"; + DisconnectReason[DisconnectReason["CONNECT_FAILURE"] = 1] = "CONNECT_FAILURE"; + DisconnectReason[DisconnectReason["CONNECTION_CLOSED"] = 2] = "CONNECTION_CLOSED"; + DisconnectReason[DisconnectReason["CONNECTION_FATAL_ERROR"] = 3] = "CONNECTION_FATAL_ERROR"; + DisconnectReason[DisconnectReason["CONNECTION_PING_TIMEOUT"] = 4] = "CONNECTION_PING_TIMEOUT"; + DisconnectReason[DisconnectReason["CLIENT_KICKED"] = 5] = "CLIENT_KICKED"; + DisconnectReason[DisconnectReason["CLIENT_BANNED"] = 6] = "CLIENT_BANNED"; + DisconnectReason[DisconnectReason["HANDSHAKE_FAILED"] = 7] = "HANDSHAKE_FAILED"; + DisconnectReason[DisconnectReason["SERVER_CLOSED"] = 8] = "SERVER_CLOSED"; + DisconnectReason[DisconnectReason["SERVER_REQUIRES_PASSWORD"] = 9] = "SERVER_REQUIRES_PASSWORD"; + DisconnectReason[DisconnectReason["UNKNOWN"] = 10] = "UNKNOWN"; +})(DisconnectReason || (DisconnectReason = {})); +var ConnectionState; +(function (ConnectionState) { + ConnectionState[ConnectionState["UNCONNECTED"] = 0] = "UNCONNECTED"; + ConnectionState[ConnectionState["CONNECTING"] = 1] = "CONNECTING"; + ConnectionState[ConnectionState["INITIALISING"] = 2] = "INITIALISING"; + ConnectionState[ConnectionState["CONNECTED"] = 3] = "CONNECTED"; + ConnectionState[ConnectionState["DISCONNECTING"] = 4] = "DISCONNECTING"; +})(ConnectionState || (ConnectionState = {})); +var ViewReasonId; +(function (ViewReasonId) { + ViewReasonId[ViewReasonId["VREASON_USER_ACTION"] = 0] = "VREASON_USER_ACTION"; + ViewReasonId[ViewReasonId["VREASON_MOVED"] = 1] = "VREASON_MOVED"; + ViewReasonId[ViewReasonId["VREASON_SYSTEM"] = 2] = "VREASON_SYSTEM"; + ViewReasonId[ViewReasonId["VREASON_TIMEOUT"] = 3] = "VREASON_TIMEOUT"; + ViewReasonId[ViewReasonId["VREASON_CHANNEL_KICK"] = 4] = "VREASON_CHANNEL_KICK"; + ViewReasonId[ViewReasonId["VREASON_SERVER_KICK"] = 5] = "VREASON_SERVER_KICK"; + ViewReasonId[ViewReasonId["VREASON_BAN"] = 6] = "VREASON_BAN"; + ViewReasonId[ViewReasonId["VREASON_SERVER_STOPPED"] = 7] = "VREASON_SERVER_STOPPED"; + ViewReasonId[ViewReasonId["VREASON_SERVER_LEFT"] = 8] = "VREASON_SERVER_LEFT"; + ViewReasonId[ViewReasonId["VREASON_CHANNEL_UPDATED"] = 9] = "VREASON_CHANNEL_UPDATED"; + ViewReasonId[ViewReasonId["VREASON_EDITED"] = 10] = "VREASON_EDITED"; + ViewReasonId[ViewReasonId["VREASON_SERVER_SHUTDOWN"] = 11] = "VREASON_SERVER_SHUTDOWN"; +})(ViewReasonId || (ViewReasonId = {})); +class TSClient { + constructor() { + this._clientId = 0; + this._reconnect_attempt = false; + this.selectInfo = new InfoBar(this, $("#select_info")); + this.channelTree = new ChannelTree(this, $("#channelTree")); + this.serverConnection = new connection.ServerConnection(this); + this.fileManager = new FileManager(this); + this.permissions = new PermissionManager(this); + this.groups = new GroupManager(this); + this.voiceConnection = new VoiceConnection(this); + this._ownEntry = new LocalClientEntry(this); + this.controlBar = new ControlBar(this, $("#control_bar")); + this.channelTree.registerClient(this._ownEntry); + } + setup() { + this.controlBar.initialise(); + } + startConnection(addr, profile, name, password) { + this.cancel_reconnect(); + this._reconnect_attempt = false; + if (this.serverConnection) + this.handleDisconnect(DisconnectReason.REQUESTED); + let idx = addr.lastIndexOf(':'); + let port; + let host; + if (idx != -1) { + port = parseInt(addr.substr(idx + 1)); + host = addr.substr(0, idx); + } + else { + host = addr; + port = 9987; + } + console.log(_translations.JAEWtQTW || (_translations.JAEWtQTW = tr("Start connection to %s:%d")), host, port); + this.channelTree.initialiseHead(addr, { host, port }); + if (password && !password.hashed) { + helpers.hashPassword(password.password).then(password => { + /* errors will be already handled via the handle disconnect thing */ + this.serverConnection.connect({ host, port }, new connection.HandshakeHandler(profile, name, password)); + }).catch(error => { + createErrorModal(_translations.bV4lkvkA || (_translations.bV4lkvkA = tr("Error while hashing password")), (_translations.u8qFbvGn || (_translations.u8qFbvGn = tr("Failed to hash server password!
    "))) + error).open(); + }); + } + else { + /* errors will be already handled via the handle disconnect thing */ + this.serverConnection.connect({ host, port }, new connection.HandshakeHandler(profile, name, password ? password.password : undefined)); + } + } + getClient() { return this._ownEntry; } + getClientId() { return this._clientId; } //TODO here + set clientId(id) { + this._clientId = id; + this._ownEntry["_clientId"] = id; + } + get clientId() { + return this._clientId; + } + getServerConnection() { return this.serverConnection; } + /** + * LISTENER + */ + onConnected() { + console.log("Client connected!"); + this.channelTree.registerClient(this._ownEntry); + settings.setServer(this.channelTree.server); + this.permissions.requestPermissionList(); + this.serverConnection.send_command("channelsubscribeall"); + if (this.groups.serverGroups.length == 0) + this.groups.requestGroups(); + this.controlBar.updateProperties(); + if (!this.voiceConnection.current_encoding_supported()) + createErrorModal(_translations.p_L1zpOY || (_translations.p_L1zpOY = tr("Codec encode type not supported!")), tr("Codec encode type " + VoiceConnectionType[this.voiceConnection.type] + " not supported by this browser!
    Choose another one!")).open(); //TODO tr + } + get connected() { + return this.serverConnection && this.serverConnection.connected(); + } + certAcceptUrl() { + const properties = { + connect_default: true, + connect_profile: this.serverConnection._handshakeHandler.profile.id, + connect_address: this.serverConnection._remote_address.host + ":" + this.serverConnection._remote_address.port + }; + const parameters = []; + for (const key in properties) + parameters.push(key + "=" + encodeURIComponent(properties[key])); + // document.URL + let callback = document.URL; + if (document.location.search.length == 0) + callback += "?" + parameters.join("&"); + else + callback += "&" + parameters.join("&"); + return "https://" + this.serverConnection._remote_address.host + ":" + this.serverConnection._remote_address.port + "/?forward_url=" + encodeURIComponent(callback); + } + handleDisconnect(type, data = {}) { + let auto_reconnect = false; + switch (type) { + case DisconnectReason.REQUESTED: + break; + case DisconnectReason.CONNECT_FAILURE: + if (this._reconnect_attempt) { + auto_reconnect = true; + chat.serverChat().appendError(_translations.mkYBZI51 || (_translations.mkYBZI51 = tr("Connect failed"))); + break; + } + console.error(_translations.i13Qq5lP || (_translations.i13Qq5lP = tr("Could not connect to remote host! Exception: %o")), data); + if (native_client) { + createErrorModal(_translations.cVoTk97h || (_translations.cVoTk97h = tr("Could not connect")), _translations.KCk709tI || (_translations.KCk709tI = tr("Could not connect to remote host (Connection refused)"))).open(); + } + else { + //TODO tr + createErrorModal(_translations.mq0BoYHj || (_translations.mq0BoYHj = tr("Could not connect")), "Could not connect to remote host (Connection refused)
    " + + "If you're sure that the remote host is up, than you may not allow unsigned certificates.
    " + + "Click here to accept the remote certificate").open(); + } + sound.play(Sound.CONNECTION_REFUSED); + break; + case DisconnectReason.HANDSHAKE_FAILED: + //TODO sound + console.error(_translations.wCe7uH8c || (_translations.wCe7uH8c = tr("Failed to process handshake: %o")), data); + createErrorModal(_translations.Jx6FIucL || (_translations.Jx6FIucL = tr("Could not connect")), (_translations.ckq4sOQG || (_translations.ckq4sOQG = tr("Failed to process handshake: "))) + data).open(); + break; + case DisconnectReason.CONNECTION_CLOSED: + console.error(_translations.CpO5hsYt || (_translations.CpO5hsYt = tr("Lost connection to remote server!"))); + createErrorModal(_translations.gQT1woZd || (_translations.gQT1woZd = tr("Connection closed")), _translations.d4MTpRCT || (_translations.d4MTpRCT = tr("The connection was closed by remote host"))).open(); + sound.play(Sound.CONNECTION_DISCONNECTED); + auto_reconnect = true; + break; + case DisconnectReason.CONNECTION_PING_TIMEOUT: + console.error(_translations.JT_pws6H || (_translations.JT_pws6H = tr("Connection ping timeout"))); + sound.play(Sound.CONNECTION_DISCONNECTED_TIMEOUT); + createErrorModal(_translations.rUpUHlzi || (_translations.rUpUHlzi = tr("Connection lost")), _translations._lZjyLc0 || (_translations._lZjyLc0 = tr("Lost connection to remote host (Ping timeout)
    Even possible?"))).open(); + break; + case DisconnectReason.SERVER_CLOSED: + chat.serverChat().appendError(_translations.NeJK3Ye8 || (_translations.NeJK3Ye8 = tr("Server closed ({0})")), data.reasonmsg); + createErrorModal(_translations.PsDVUZ4O || (_translations.PsDVUZ4O = tr("Server closed")), "The server is closed.
    " + //TODO tr + "Reason: " + data.reasonmsg).open(); + sound.play(Sound.CONNECTION_DISCONNECTED); + auto_reconnect = true; + break; + case DisconnectReason.SERVER_REQUIRES_PASSWORD: + chat.serverChat().appendError(_translations.k9_p6t0P || (_translations.k9_p6t0P = tr("Server requires password"))); + createInputModal(_translations.vgqAaBSb || (_translations.vgqAaBSb = tr("Server password")), _translations.nYEz_XI9 || (_translations.nYEz_XI9 = tr("Enter server password:")), password => password.length != 0, password => { + if (!(typeof password === "string")) + return; + this.startConnection(this.serverConnection._remote_address.host + ":" + this.serverConnection._remote_address.port, this.serverConnection._handshakeHandler.profile, this.serverConnection._handshakeHandler.name, { password: password, hashed: false }); + }).open(); + break; + case DisconnectReason.CLIENT_KICKED: + chat.serverChat().appendError(_translations.Lq3w511A || (_translations.Lq3w511A = tr("You got kicked from the server by {0}{1}")), ClientEntry.chatTag(data["invokerid"], data["invokername"], data["invokeruid"]), data["reasonmsg"] ? " (" + data["reasonmsg"] + ")" : ""); + sound.play(Sound.SERVER_KICKED); + auto_reconnect = true; + break; + case DisconnectReason.CLIENT_BANNED: + chat.serverChat().appendError(_translations.tqIlSIVg || (_translations.tqIlSIVg = tr("You got banned from the server by {0}{1}")), ClientEntry.chatTag(data["invokerid"], data["invokername"], data["invokeruid"]), data["reasonmsg"] ? " (" + data["reasonmsg"] + ")" : ""); + sound.play(Sound.CONNECTION_BANNED); //TODO findout if it was a disconnect or a connect refuse + break; + default: + console.error(_translations.rLg_S2Tb || (_translations.rLg_S2Tb = tr("Got uncaught disconnect!"))); + console.error(_translations.AwKnUotx || (_translations.AwKnUotx = tr("Type: %o Data:")), type); + console.error(data); + break; + } + this.channelTree.reset(); + this.voiceConnection.dropSession(); + if (this.serverConnection) + this.serverConnection.disconnect(); + this.controlBar.update_connection_state(); + this.selectInfo.setCurrentSelected(null); + this.selectInfo.update_banner(); + if (auto_reconnect) { + if (!this.serverConnection) { + console.log(_translations.bMtuaii5 || (_translations.bMtuaii5 = tr("Allowed to auto reconnect but cant reconnect because we dont have any information left..."))); + return; + } + chat.serverChat().appendMessage(_translations.uS396luz || (_translations.uS396luz = tr("Reconnecting in 5 seconds"))); + console.log(_translations.dDHTCdwB || (_translations.dDHTCdwB = tr("Allowed to auto reconnect. Reconnecting in 5000ms"))); + const server_address = this.serverConnection._remote_address; + const profile = this.serverConnection._handshakeHandler.profile; + const name = this.serverConnection._handshakeHandler.name; + const password = this.serverConnection._handshakeHandler.server_password; + this._reconnect_timer = setTimeout(() => { + this._reconnect_timer = undefined; + chat.serverChat().appendMessage(_translations.BmUuHG2D || (_translations.BmUuHG2D = tr("Reconnecting..."))); + console.log(_translations.Zt58aq4G || (_translations.Zt58aq4G = tr("Reconnecting..."))); + this.startConnection(server_address.host + ":" + server_address.port, profile, name, password ? { password: password, hashed: true } : undefined); + this._reconnect_attempt = true; + }, 5000); + } + } + cancel_reconnect() { + if (this._reconnect_timer) { + chat.serverChat().appendMessage(_translations.AWIMAHNY || (_translations.AWIMAHNY = tr("Reconnect canceled"))); + clearTimeout(this._reconnect_timer); + this._reconnect_timer = undefined; + } + } +} +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["f2b04bedfeb84a7179b0b6218f04ced236c258941a594c1d99341a91a2ea7311"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["f2b04bedfeb84a7179b0b6218f04ced236c258941a594c1d99341a91a2ea7311"] = "f2b04bedfeb84a7179b0b6218f04ced236c258941a594c1d99341a91a2ea7311"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "y8J0eI9A", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/FileManager.ts (52,23)" }, { name: "hc7aVYby", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/FileManager.ts (70,27)" }, { name: "hqRdxWxT", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/FileManager.ts (96,22)" }, { name: "dRSVSPXL", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/FileManager.ts (103,45)" }, { name: "NT5S_zSi", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/FileManager.ts (183,27)" }, { name: "LO41aNOW", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/FileManager.ts (202,27)" }, { name: "c90b64RT", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/FileManager.ts (352,35)" }, { name: "XS1yfMFG", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/FileManager.ts (353,51)" }, { name: "DtVBEPYe", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/FileManager.ts (374,31)" }, { name: "z_jAHQFu", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/FileManager.ts (375,47)" }, { name: "tNuA8Hvx", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/FileManager.ts (401,27)" }, { name: "b0o29_VA", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/FileManager.ts (414,31)" }, { name: "AI0C0oqC", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/FileManager.ts (416,31)" }, { name: "f9lF4foN", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/FileManager.ts (425,31)" }, { name: "FXXPuv5A", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/FileManager.ts (452,21)" }, { name: "H1BS6cr_", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/FileManager.ts (499,35)" }, { name: "FA4tiZqm", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/FileManager.ts (500,51)" }, { name: "ynLLTaB0", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/FileManager.ts (528,31)" }, { name: "kQSaQY_Z", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/FileManager.ts (529,47)" }, { name: "D7ibedPu", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/FileManager.ts (551,31)" }, { name: "e2jUF1F6", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/FileManager.ts (566,35)" }, { name: "yZ0tGu8j", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/FileManager.ts (578,31)" }, { name: "u5eqNg06", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/FileManager.ts (580,68)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +/// +/// +class FileEntry { +} +class FileListRequest { +} +class DownloadFileTransfer { + constructor(handle, id) { + this.currentSize = 0; + this.on_start = () => { }; + this.on_complete = () => { }; + this.on_fail = (_) => { }; + this.on_data = (_) => { }; + this.transferId = id; + this._handle = handle; + } + startTransfer() { + if (!this.remoteHost || !this.remotePort || !this.transferKey || !this.totalSize) { + this.on_fail("Missing data!"); + return; + } + console.debug(_translations.y8J0eI9A || (_translations.y8J0eI9A = tr("Create new file download to %s:%s (Key: %s, Expect %d bytes)")), this.remoteHost, this.remotePort, this.transferId, this.totalSize); + this._active = true; + this._socket = new WebSocket("wss://" + this.remoteHost + ":" + this.remotePort); + this._socket.onopen = this.onOpen.bind(this); + this._socket.onclose = this.onClose.bind(this); + this._socket.onmessage = this.onMessage.bind(this); + this._socket.onerror = this.onError.bind(this); + } + onOpen() { + if (!this._active) + return; + this._socket.send(this.transferKey); + this.on_start(); + } + onMessage(data) { + if (!this._active) { + console.error(_translations.hc7aVYby || (_translations.hc7aVYby = tr("Got data, but socket closed?"))); + return; + } + this._parseActive = true; + let fileReader = new FileReader(); + fileReader.onload = (event) => { + this.onBinaryData(new Uint8Array(event.target.result)); + //if(this._socket.readyState != WebSocket.OPEN && !this._succeed) this.on_fail("unexpected close"); + this._parseActive = false; + }; + fileReader.readAsArrayBuffer(data.data); + } + onBinaryData(data) { + this.currentSize += data.length; + this.on_data(data); + if (this.currentSize == this.totalSize) { + this._succeed = true; + this.on_complete(); + this.disconnect(); + } + } + onError() { + if (!this._active) + return; + this.on_fail(_translations.hqRdxWxT || (_translations.hqRdxWxT = tr("an error occurent"))); + this.disconnect(); + } + onClose() { + if (!this._active) + return; + if (!this._parseActive) + this.on_fail(_translations.dRSVSPXL || (_translations.dRSVSPXL = tr("unexpected close (remote closed)"))); + this.disconnect(); + } + disconnect() { + this._active = false; + //this._socket.close(); + } +} +class FileManager extends connection.AbstractCommandHandler { + constructor(client) { + super(client.serverConnection); + this.listRequests = []; + this.pendingDownloadTransfers = []; + this.downloadCounter = 0; + this.handle = client; + this.icons = new IconManager(this); + this.avatars = new AvatarManager(this); + this.connection.command_handler_boss().register_handler(this); + } + handle_command(command) { + switch (command.command) { + case "notifyfilelist": + this.notifyFileList(command.arguments); + return true; + case "notifyfilelistfinished": + this.notifyFileListFinished(command.arguments); + return true; + case "notifystartdownload": + this.notifyStartDownload(command.arguments); + return true; + } + return false; + } + /******************************** File list ********************************/ + //TODO multiple requests (same path) + requestFileList(path, channel, password) { + const _this = this; + return new Promise((accept, reject) => { + let req = new FileListRequest(); + req.path = path; + req.entries = []; + req.callback = accept; + _this.listRequests.push(req); + _this.handle.serverConnection.send_command("ftgetfilelist", { "path": path, "cid": (channel ? channel.channelId : "0"), "cpw": (password ? password : "") }).then(() => { }).catch(reason => { + _this.listRequests.remove(req); + if (reason instanceof CommandResult) { + if (reason.id == 0x0501) { + accept([]); //Empty result + return; + } + } + reject(reason); + }); + }); + } + notifyFileList(json) { + let entry = undefined; + for (let e of this.listRequests) { + if (e.path == json[0]["path"]) { + entry = e; + break; + } + } + if (!entry) { + console.error(_translations.NT5S_zSi || (_translations.NT5S_zSi = tr("Invalid file list entry. Path: %s")), json[0]["path"]); + return; + } + for (let e of json) + entry.entries.push(e); + } + notifyFileListFinished(json) { + let entry = undefined; + for (let e of this.listRequests) { + if (e.path == json[0]["path"]) { + entry = e; + this.listRequests.remove(e); + break; + } + } + if (!entry) { + console.error(_translations.LO41aNOW || (_translations.LO41aNOW = tr("Invalid file list entry finish. Path: ")), json[0]["path"]); + return; + } + entry.callback(entry.entries); + } + /******************************** File download ********************************/ + requestFileDownload(path, file, channel, password) { + const _this = this; + let transfer = new DownloadFileTransfer(this, this.downloadCounter++); + this.pendingDownloadTransfers.push(transfer); + return new Promise((resolve, reject) => { + transfer["_promiseCallback"] = resolve; + _this.handle.serverConnection.send_command("ftinitdownload", { + "path": path, + "name": file, + "cid": (channel ? channel.channelId : "0"), + "cpw": (password ? password : ""), + "clientftfid": transfer.transferId + }).catch(reason => { + _this.pendingDownloadTransfers.remove(transfer); + reject(reason); + }); + }); + } + notifyStartDownload(json) { + json = json[0]; + let transfer; + for (let e of this.pendingDownloadTransfers) + if (e.transferId == json["clientftfid"]) { + transfer = e; + break; + } + transfer.serverTransferId = json["serverftfid"]; + transfer.transferKey = json["ftkey"]; + transfer.totalSize = json["size"]; + transfer.remotePort = json["port"]; + transfer.remoteHost = (json["ip"] ? json["ip"] : "").replace(/,/g, ""); + if (!transfer.remoteHost || transfer.remoteHost == '0.0.0.0' || transfer.remoteHost == '127.168.0.0') + transfer.remoteHost = this.handle.serverConnection._remote_address.host; + transfer["_promiseCallback"](transfer); + this.pendingDownloadTransfers.remove(transfer); + } +} +class Icon { +} +var ImageType; +(function (ImageType) { + ImageType[ImageType["UNKNOWN"] = 0] = "UNKNOWN"; + ImageType[ImageType["BITMAP"] = 1] = "BITMAP"; + ImageType[ImageType["PNG"] = 2] = "PNG"; + ImageType[ImageType["GIF"] = 3] = "GIF"; + ImageType[ImageType["SVG"] = 4] = "SVG"; + ImageType[ImageType["JPEG"] = 5] = "JPEG"; +})(ImageType || (ImageType = {})); +function media_image_type(type) { + switch (type) { + case ImageType.BITMAP: + return "bmp"; + case ImageType.GIF: + return "gif"; + case ImageType.SVG: + return "svg+xml"; + case ImageType.JPEG: + return "jpeg"; + case ImageType.UNKNOWN: + case ImageType.PNG: + default: + return "png"; + } +} +function image_type(base64) { + const bin = atob(base64); + if (bin.length < 10) + return ImageType.UNKNOWN; + if (bin[0] == String.fromCharCode(66) && bin[1] == String.fromCharCode(77)) { + return ImageType.BITMAP; + } + else if (bin.substr(0, 8) == "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a") { + return ImageType.PNG; + } + else if (bin.substr(0, 4) == "\x47\x49\x46\x38" && (bin[4] == '\x37' || bin[4] == '\x39') && bin[5] == '\x61') { + return ImageType.GIF; + } + else if (bin[0] == '\x3c') { + return ImageType.SVG; + } + else if (bin[0] == '\xFF' && bin[1] == '\xd8') { + return ImageType.JPEG; + } + return ImageType.UNKNOWN; +} +class IconManager { + constructor(handle) { + this.loading_icons = []; + this.handle = handle; + } + iconList() { + return this.handle.requestFileList("/icons"); + } + downloadIcon(id) { + return this.handle.requestFileDownload("", "/icon_" + id); + } + resolveCached(id) { + let icon = localStorage.getItem("icon_" + id); + if (icon) { + let i = JSON.parse(icon); + if (i.base64.length > 0) { //TODO timestamp? + return i; + } + } + return undefined; + } + load_finished(id) { + for (let entry of this.loading_icons) + if (entry.id == id) + this.loading_icons.remove(entry); + } + loadIcon(id) { + for (let entry of this.loading_icons) + if (entry.id == id) + return entry.promise; + let promise = new Promise((resolve, reject) => { + let icon = this.resolveCached(id); + if (icon) { + this.load_finished(id); + resolve(icon); + return; + } + this.downloadIcon(id).then(ft => { + let array = new Uint8Array(0); + ft.on_fail = reason => { + this.load_finished(id); + console.error(_translations.c90b64RT || (_translations.c90b64RT = tr("Could not download icon %s -> %s")), id, tr(reason)); + chat.serverChat().appendError(_translations.XS1yfMFG || (_translations.XS1yfMFG = tr("Fail to download icon {0}. ({1})")), id, JSON.stringify(reason)); + reject(reason); + }; + ft.on_start = () => { }; + ft.on_data = (data) => { + array = concatenate(Uint8Array, array, data); + }; + ft.on_complete = () => { + let base64 = btoa(String.fromCharCode.apply(null, array)); + let icon = new Icon(); + icon.base64 = base64; + icon.id = id; + icon.name = "icon_" + id; + localStorage.setItem("icon_" + id, JSON.stringify(icon)); + this.load_finished(id); + resolve(icon); + }; + ft.startTransfer(); + }).catch(reason => { + console.error(_translations.DtVBEPYe || (_translations.DtVBEPYe = tr("Error while downloading icon! (%s)")), tr(JSON.stringify(reason))); + chat.serverChat().appendError(_translations.z_jAHQFu || (_translations.z_jAHQFu = tr("Failed to request download for icon {0}. ({1})")), id, tr(JSON.stringify(reason))); + reject(reason); + }); + }); + this.loading_icons.push({ promise: promise, id: id }); + return promise; + } + //$("\"tick\"") + generateTag(id) { + if (id == 0) + return $.spawn("div").addClass("icon_empty"); + else if (id < 1000) + return $.spawn("div").addClass("icon client-group_" + id); + let tag = $.spawn("div"); + tag.addClass("icon-container icon_empty"); + let img = $.spawn("img"); + img.attr("width", 16).attr("height", 16).attr("alt", ""); + let icon = this.resolveCached(id); + if (icon) { + const type = image_type(icon.base64); + const media = media_image_type(type); + console.debug(_translations.tNuA8Hvx || (_translations.tNuA8Hvx = tr("Icon has an image type of %o (media: %o)")), type, media); + img.attr("src", "data:image/" + media + ";base64," + icon.base64); + tag.append(img).removeClass("icon_empty"); + } + else { + img.attr("src", "file://null"); + let loader = $.spawn("div"); + loader.addClass("icon_loading"); + tag.append(loader); + this.loadIcon(id).then(icon => { + const type = image_type(icon.base64); + const media = media_image_type(type); + console.debug(_translations.b0o29_VA || (_translations.b0o29_VA = tr("Icon has an image type of %o (media: %o)")), type, media); + img.attr("src", "data:image/" + media + ";base64," + icon.base64); + console.debug(_translations.AI0C0oqC || (_translations.AI0C0oqC = tr("Icon %o loaded :)")), id); + img.css("opacity", 0); + tag.append(img).removeClass("icon_empty"); + loader.animate({ opacity: 0 }, 50, function () { + $(this).detach(); + img.animate({ opacity: 1 }, 150); + }); + }).catch(reason => { + console.error(_translations.f9lF4foN || (_translations.f9lF4foN = tr("Could not load icon %o. Reason: %p")), id, reason); + loader.removeClass("icon_loading").addClass("icon client-warning").attr("tag", "Could not load icon " + id); + }); + } + return tag; + } +} +class Avatar { +} +class AvatarManager { + constructor(handle) { + this.loading_avatars = []; + this.loaded_urls = []; + this.handle = handle; + } + downloadAvatar(client) { + console.log(_translations.FXXPuv5A || (_translations.FXXPuv5A = tr("Downloading avatar %s")), client.avatarId()); + return this.handle.requestFileDownload("", "/avatar_" + client.avatarId()); + } + resolveCached(client) { + let avatar = localStorage.getItem("avatar_" + client.properties.client_unique_identifier); + if (avatar) { + let i = JSON.parse(avatar); + //TODO timestamp? + if (i.avatarId != client.properties.client_flag_avatar) + return undefined; + if (i.base64) { + if (i.base64.length > 0) + return i; + else + i.base64 = undefined; + } + if (i.url) { + for (let url of this.loaded_urls) + if (url == i.url) + return i; + } + } + return undefined; + } + load_finished(name) { + for (let entry of this.loading_avatars) + if (entry.name == name) + this.loading_avatars.remove(entry); + } + loadAvatar(client) { + let name = client.avatarId(); + for (let promise of this.loading_avatars) + if (promise.name == name) + return promise.promise; + let promise = new Promise((resolve, reject) => { + let avatar = this.resolveCached(client); + if (avatar) { + this.load_finished(name); + resolve(avatar); + return; + } + this.downloadAvatar(client).then(ft => { + let array = new Uint8Array(0); + ft.on_fail = reason => { + this.load_finished(name); + console.error(_translations.H1BS6cr_ || (_translations.H1BS6cr_ = tr("Could not download avatar %o -> %s")), client.properties.client_flag_avatar, reason); + chat.serverChat().appendError(_translations.FA4tiZqm || (_translations.FA4tiZqm = tr("Fail to download avatar for {0}. ({1})")), client.clientNickName(), JSON.stringify(reason)); + reject(reason); + }; + ft.on_start = () => { }; + ft.on_data = (data) => { + array = concatenate(Uint8Array, array, data); + }; + ft.on_complete = () => { + let avatar = new Avatar(); + if (array.length >= 1024 * 1024) { + let blob_image = new Blob([array]); + avatar.url = URL.createObjectURL(blob_image); + avatar.blob = blob_image; + this.loaded_urls.push(avatar.url); + } + else { + avatar.base64 = btoa(String.fromCharCode.apply(null, array)); + } + avatar.clientUid = client.clientUid(); + avatar.avatarId = client.properties.client_flag_avatar; + localStorage.setItem("avatar_" + client.properties.client_unique_identifier, JSON.stringify(avatar)); + this.load_finished(name); + resolve(avatar); + }; + ft.startTransfer(); + }).catch(reason => { + this.load_finished(name); + console.error(_translations.ynLLTaB0 || (_translations.ynLLTaB0 = tr("Error while downloading avatar! (%s)")), JSON.stringify(reason)); + chat.serverChat().appendError(_translations.kQSaQY_Z || (_translations.kQSaQY_Z = tr("Failed to request avatar download for {0}. ({1})")), client.clientNickName(), JSON.stringify(reason)); + reject(reason); + }); + }); + this.loading_avatars.push({ promise: promise, name: name }); + return promise; + } + generateTag(client) { + let tag = $.spawn("div"); + let img = $.spawn("img"); + img.attr("alt", ""); + let avatar = this.resolveCached(client); + if (avatar) { + if (avatar.url) + img.attr("src", avatar.url); + else { + const type = image_type(avatar.base64); + const media = media_image_type(type); + console.debug(_translations.D7ibedPu || (_translations.D7ibedPu = tr("avatar has an image type of %o (media: %o)")), type, media); + img.attr("src", "data:image/" + media + ";base64," + avatar.base64); + } + tag.append(img); + } + else { + let loader = $.spawn("img"); + loader.attr("src", "img/loading_image.svg").css("width", "75%"); + tag.append(loader); + this.loadAvatar(client).then(avatar => { + if (avatar.url) + img.attr("src", avatar.url); + else { + const type = image_type(avatar.base64); + const media = media_image_type(type); + console.debug(_translations.e2jUF1F6 || (_translations.e2jUF1F6 = tr("Avatar has an image type of %o (media: %o)")), type, media); + img.attr("src", "data:image/" + media + ";base64," + avatar.base64); + } + console.debug("Avatar " + client.clientNickName() + " loaded :)"); + img.css("opacity", 0); + tag.append(img); + loader.animate({ opacity: 0 }, 50, function () { + $(this).detach(); + img.animate({ opacity: 1 }, 150); + }); + }).catch(reason => { + console.error(_translations.yZ0tGu8j || (_translations.yZ0tGu8j = tr("Could not load avatar for %s. Reason: %s")), client.clientNickName(), reason); + //TODO Broken image + loader.addClass("icon client-warning").attr("tag", (_translations.u5eqNg06 || (_translations.u5eqNg06 = tr("Could not load avatar "))) + client.clientNickName()); + }); + } + return tag; + } +} +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["571623c0409102f319b482787637afa231f4d6ca51d374eba8c1e5d7c07fcd45"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["571623c0409102f319b482787637afa231f4d6ca51d374eba8c1e5d7c07fcd45"] = "571623c0409102f319b482787637afa231f4d6ca51d374eba8c1e5d7c07fcd45"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "xpLU9Tla", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/PPTListener.ts (41,31)" }, { name: "_szPq66H", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/PPTListener.ts (43,31)" }, { name: "jKer8fsK", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/PPTListener.ts (45,31)" }, { name: "wVOUWzw9", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/PPTListener.ts (47,31)" }, { name: "PGifhkad", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/PPTListener.ts (49,58)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +var ppt; +(function (ppt) { + let EventType; + (function (EventType) { + EventType[EventType["KEY_PRESS"] = 0] = "KEY_PRESS"; + EventType[EventType["KEY_RELEASE"] = 1] = "KEY_RELEASE"; + EventType[EventType["KEY_TYPED"] = 2] = "KEY_TYPED"; + })(EventType = ppt.EventType || (ppt.EventType = {})); + let SpecialKey; + (function (SpecialKey) { + SpecialKey[SpecialKey["CTRL"] = 0] = "CTRL"; + SpecialKey[SpecialKey["WINDOWS"] = 1] = "WINDOWS"; + SpecialKey[SpecialKey["SHIFT"] = 2] = "SHIFT"; + SpecialKey[SpecialKey["ALT"] = 3] = "ALT"; + })(SpecialKey = ppt.SpecialKey || (ppt.SpecialKey = {})); + function key_description(key) { + let result = ""; + if (key.key_shift) + result += " + " + (_translations.xpLU9Tla || (_translations.xpLU9Tla = tr("Shift"))); + if (key.key_alt) + result += " + " + (_translations._szPq66H || (_translations._szPq66H = tr("Alt"))); + if (key.key_ctrl) + result += " + " + (_translations.jKer8fsK || (_translations.jKer8fsK = tr("CTRL"))); + if (key.key_windows) + result += " + " + (_translations.wVOUWzw9 || (_translations.wVOUWzw9 = tr("Win"))); + result += " + " + (key.key_code ? key.key_code : _translations.PGifhkad || (_translations.PGifhkad = tr("unset"))); + return result.substr(3); + } + ppt.key_description = key_description; + /* + export declare function initialize() : Promise; + export declare function finalize(); // most the times not really required + + export declare function register_key_listener(listener: (_: KeyEvent) => any); + export declare function unregister_key_listener(listener: (_: KeyEvent) => any); + + export declare function register_key_hook(hook: KeyHook); + export declare function unregister_key_hook(hook: KeyHook); + + export declare function key_pressed(code: string | SpecialKey) : boolean; + */ +})(ppt || (ppt = {})); +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["e54bd5e9d10abe8513ba0439aa8300d50df4deef8e354ea912eb1d498e7ca4e5"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["e54bd5e9d10abe8513ba0439aa8300d50df4deef8e354ea912eb1d498e7ca4e5"] = "e54bd5e9d10abe8513ba0439aa8300d50df4deef8e354ea912eb1d498e7ca4e5"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of []) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +var bookmarks; +(function (bookmarks_1) { + function guid() { + function s4() { + return Math + .floor((1 + Math.random()) * 0x10000) + .toString(16) + .substring(1); + } + return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4(); + } + let BookmarkType; + (function (BookmarkType) { + BookmarkType[BookmarkType["ENTRY"] = 0] = "ENTRY"; + BookmarkType[BookmarkType["DIRECTORY"] = 1] = "DIRECTORY"; + })(BookmarkType = bookmarks_1.BookmarkType || (bookmarks_1.BookmarkType = {})); + let _bookmark_config; + function bookmark_config() { + if (_bookmark_config) + return _bookmark_config; + let bookmark_json = localStorage.getItem("bookmarks"); + let bookmarks = JSON.parse(bookmark_json) || {}; + _bookmark_config = bookmarks; + _bookmark_config.root_bookmark = _bookmark_config.root_bookmark || { content: [], display_name: "root", type: BookmarkType.DIRECTORY }; + if (!_bookmark_config.default_added) { + _bookmark_config.default_added = true; + create_bookmark("TeaSpeak official Test-Server", _bookmark_config.root_bookmark, { + server_address: "ts.teaspeak.de", + server_port: 9987 + }, "Another TeaSpeak user"); + save_config(); + } + return _bookmark_config; + } + function save_config() { + localStorage.setItem("bookmarks", JSON.stringify(bookmark_config())); + } + function bookmarks() { + return bookmark_config().root_bookmark; + } + bookmarks_1.bookmarks = bookmarks; + function find_bookmark_recursive(parent, uuid) { + for (const entry of parent.content) { + if (entry.unique_id == uuid) + return entry; + if (entry.type == BookmarkType.DIRECTORY) { + const result = find_bookmark_recursive(entry, uuid); + if (result) + return result; + } + } + return undefined; + } + function find_bookmark(uuid) { + return find_bookmark_recursive(bookmarks(), uuid); + } + bookmarks_1.find_bookmark = find_bookmark; + function parent_bookmark(bookmark) { + const books = [bookmarks()]; + while (!books.length) { + const directory = books.pop_front(); + if (directory.type == BookmarkType.DIRECTORY) { + const cast = directory; + if (cast.content.indexOf(bookmark) != -1) + return cast; + books.push(...cast.content); + } + } + return bookmarks(); + } + bookmarks_1.parent_bookmark = parent_bookmark; + function create_bookmark(display_name, directory, server_properties, nickname) { + const bookmark = { + display_name: display_name, + server_properties: server_properties, + nickname: nickname, + type: BookmarkType.ENTRY, + connect_profile: "default", + unique_id: guid() + }; + directory.content.push(bookmark); + return bookmark; + } + bookmarks_1.create_bookmark = create_bookmark; + function create_bookmark_directory(parent, name) { + const bookmark = { + type: BookmarkType.DIRECTORY, + display_name: name, + content: [], + unique_id: guid() + }; + parent.content.push(bookmark); + return bookmark; + } + bookmarks_1.create_bookmark_directory = create_bookmark_directory; + //TODO test if the new parent is within the old bookmark + function change_directory(parent, bookmark) { + delete_bookmark(bookmark); + parent.content.push(bookmark); + } + bookmarks_1.change_directory = change_directory; + function save_bookmark(bookmark) { + save_config(); /* nvm we dont give a fuck... saving everything */ + } + bookmarks_1.save_bookmark = save_bookmark; + function delete_bookmark_recursive(parent, bookmark) { + const index = parent.content.indexOf(bookmark); + if (index != -1) + parent.content.remove(bookmark); + else + for (const entry of parent.content) + if (entry.type == BookmarkType.DIRECTORY) + delete_bookmark_recursive(entry, bookmark); + } + function delete_bookmark(bookmark) { + delete_bookmark_recursive(bookmarks(), bookmark); + } + bookmarks_1.delete_bookmark = delete_bookmark; +})(bookmarks || (bookmarks = {})); +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["b908bdb2f5592807ec050e926a55d436c86d4c5313c4b46534504e355d917ef2"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["b908bdb2f5592807ec050e926a55d436c86d4c5313c4b46534504e355d917ef2"] = "b908bdb2f5592807ec050e926a55d436c86d4c5313c4b46534504e355d917ef2"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "o9aqigfL", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/chat.ts (68,30)" }, { name: "_OL5avmw", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/chat.ts (73,25)" }, { name: "Ugzovx8b", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/chat.ts (231,23)" }, { name: "DBMAxrab", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/chat.ts (241,27)" }, { name: "xhzWf49Y", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/chat.ts (251,23)" }, { name: "S7KM8qoZ", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/chat.ts (274,21)" }, { name: "aiwUHpzW", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/chat.ts (283,21)" }, { name: "MGIa7CAP", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/chat.ts (354,47)" }, { name: "EfA3bz33", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/chat.ts (361,49)" }, { name: "sZZ04N8U", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/chat.ts (362,31)" }, { name: "XY0rgaAe", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/chat.ts (365,34)" }, { name: "YUpKiux0", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/chat.ts (369,48)" }, { name: "wtDGBoN6", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/chat.ts (374,50)" }, { name: "AqmT7vNM", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/chat.ts (375,31)" }, { name: "CoEg7HKO", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/chat.ts (378,35)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +var ChatType; +(function (ChatType) { + ChatType[ChatType["GENERAL"] = 0] = "GENERAL"; + ChatType[ChatType["SERVER"] = 1] = "SERVER"; + ChatType[ChatType["CHANNEL"] = 2] = "CHANNEL"; + ChatType[ChatType["CLIENT"] = 3] = "CLIENT"; +})(ChatType || (ChatType = {})); +var MessageHelper; +(function (MessageHelper) { + function htmlEscape(message) { + const div = document.createElement('div'); + div.innerText = message; + message = div.innerHTML; + return message.replace(/ /g, ' ').split(/
    /); + } + MessageHelper.htmlEscape = htmlEscape; + function formatElement(object, escape_html = true) { + if ($.isArray(object)) { + let result = []; + for (let element of object) + result.push(...formatElement(element, escape_html)); + return result; + } + else if (typeof (object) == "string") { + if (object.length == 0) + return []; + return escape_html ? + htmlEscape(object).map((entry, idx, array) => $.spawn("a").css("display", (idx == 0 || idx + 1 == array.length ? "inline" : "") + "block").html(entry == "" && idx != 0 ? " " : entry)) : + [$.spawn("div").css("display", "inline-block").html(object)]; + } + else if (typeof (object) === "object") { + if (object instanceof $) + return [object]; + return formatElement(""); + } + else if (typeof (object) === "function") + return formatElement(object(), escape_html); + else if (typeof (object) === "undefined") + return formatElement(""); + else if (typeof (object) === "number") + return [$.spawn("a").text(object)]; + return formatElement(""); + } + MessageHelper.formatElement = formatElement; + function formatMessage(pattern, ...objects) { + let begin = 0, found = 0; + let result = []; + do { + found = pattern.indexOf('{', found); + if (found == -1 || pattern.length <= found + 1) { + result.push(...formatElement(pattern.substr(begin))); + break; + } + if (found > 0 && pattern[found - 1] == '\\') { + //TODO remove the escape! + found++; + continue; + } + result.push(...formatElement(pattern.substr(begin, found - begin))); //Append the text + let number; + let offset = 0; + while ("0123456789".includes(pattern[found + 1 + offset])) + offset++; + number = parseInt(offset > 0 ? pattern.substr(found + 1, offset) : "0"); + if (pattern[found + offset + 1] != '}') { + found++; + continue; + } + if (objects.length < number) + console.warn(_translations.o9aqigfL || (_translations.o9aqigfL = tr("Message to format contains invalid index (%o)")), number); + result.push(...formatElement(objects[number])); + found = found + 1 + offset; + begin = found + 1; + console.log(_translations._OL5avmw || (_translations._OL5avmw = tr("Offset: %d Number: %d")), offset, number); + } while (found++); + return result; + } + MessageHelper.formatMessage = formatMessage; + function bbcode_chat(message) { + let result = XBBCODE.process({ + text: message, + escapeHtml: true, + addInLineBreaks: false, + /* TODO make this configurable and allow IMG */ + tag_whitelist: [ + "b", + "i", + "u", + "color", + "url" + ] + }); + if (result.error) { + console.log("BBCode parse error: %o", result.errorQueue); + return formatElement(message); + } + return result.html.split("\n").map((entry, idx, array) => $.spawn("a").css("display", (idx == 0 ? "inline" : "") + "block").html(entry == "" && idx != 0 ? " " : entry)); + } + MessageHelper.bbcode_chat = bbcode_chat; +})(MessageHelper || (MessageHelper = {})); +class ChatMessage { + constructor(message) { + this.date = new Date(); + this.message = message; + } + num(num) { + let str = num.toString(); + while (str.length < 2) + str = '0' + str; + return str; + } + get htmlTag() { + if (this._htmlTag) + return this._htmlTag; + let tag = $.spawn("div"); + tag.addClass("message"); + let dateTag = $.spawn("div"); + dateTag.text("<" + this.num(this.date.getUTCHours()) + ":" + this.num(this.date.getUTCMinutes()) + ":" + this.num(this.date.getUTCSeconds()) + "> "); + dateTag.css("margin-right", "4px"); + dateTag.css("color", "dodgerblue"); + this._htmlTag = tag; + tag.append(dateTag); + this.message.forEach(e => e.appendTo(tag)); + tag.hide(); + return tag; + } +} +class ChatEntry { + constructor(handle, type, key) { + this.handle = handle; + this.type = type; + this.key = key; + this._name = key; + this.history = []; + this.onClose = function () { return true; }; + } + appendError(message, ...args) { + let entries = MessageHelper.formatMessage(message, ...args); + entries.forEach(e => e.css("color", "red")); + this.pushChatMessage(new ChatMessage(entries)); + } + appendMessage(message, fmt = true, ...args) { + this.pushChatMessage(new ChatMessage(MessageHelper.formatMessage(message, ...args))); + } + pushChatMessage(entry) { + this.history.push(entry); + while (this.history.length > 100) { + let elm = this.history.pop_front(); + elm.htmlTag.animate({ opacity: 0 }, 200, function () { + $(this).detach(); + }); + } + if (this.handle.activeChat === this) { + let box = $(this.handle.htmlTag).find(".messages"); + let mbox = $(this.handle.htmlTag).find(".message_box"); + let bottom = box.scrollTop() + box.height() + 1 >= mbox.height(); + mbox.append(entry.htmlTag); + entry.htmlTag.show().css("opacity", "0").animate({ opacity: 1 }, 100); + if (bottom) + box.scrollTop(mbox.height()); + } + else { + this.unread = true; + } + } + displayHistory() { + this.unread = false; + let box = $(this.handle.htmlTag).find(".messages"); + let mbox = $(this.handle.htmlTag).find(".message_box"); + mbox.empty(); + for (let e of this.history) { + mbox.append(e.htmlTag); + if (e.htmlTag.is(":hidden")) + e.htmlTag.show(); + } + box.scrollTop(mbox.height()); + } + get htmlTag() { + if (this._htmlTag) + return this._htmlTag; + let tag = $.spawn("div"); + tag.addClass("chat"); + tag.append("
    "); + tag.append("" + this._name + ""); + let closeTag = $.spawn("div"); + closeTag.addClass("btn_close icon client-tab_close_button"); + if (!this._closeable) + closeTag.hide(); + tag.append(closeTag); + const _this = this; + tag.click(function () { + _this.handle.activeChat = _this; + }); + tag.on("contextmenu", function (e) { + e.preventDefault(); + let actions = []; + actions.push({ + type: MenuEntryType.ENTRY, + icon: "", + name: _translations.Ugzovx8b || (_translations.Ugzovx8b = tr("Clear")), + callback: () => { + _this.history = []; + _this.displayHistory(); + } + }); + if (_this.closeable) { + actions.push({ + type: MenuEntryType.ENTRY, + icon: "client-tab_close_button", + name: _translations.DBMAxrab || (_translations.DBMAxrab = tr("Close")), + callback: () => { + chat.deleteChat(_this); + } + }); + } + actions.push({ + type: MenuEntryType.ENTRY, + icon: "client-tab_close_button", + name: _translations.xhzWf49Y || (_translations.xhzWf49Y = tr("Close all private tabs")), + callback: () => { + //TODO Implement this? + } + }); + spawn_context_menu(e.pageX, e.pageY, ...actions); + }); + closeTag.click(function () { + if ($.isFunction(_this.onClose) && !_this.onClose()) + return; + _this.handle.deleteChat(_this); + }); + this._htmlTag = tag; + return tag; + } + focus() { + this.handle.activeChat = this; + this.handle.htmlTag.find(".input_box").focus(); + } + set name(newName) { + console.log(_translations.S7KM8qoZ || (_translations.S7KM8qoZ = tr("Change name!"))); + this._name = newName; + this.htmlTag.find(".name").text(this._name); + } + set closeable(flag) { + if (this._closeable == flag) + return; + this._closeable = flag; + console.log((_translations.aiwUHpzW || (_translations.aiwUHpzW = tr("Set closeable: "))) + this._closeable); + if (flag) + this.htmlTag.find(".btn_close").show(); + else + this.htmlTag.find(".btn_close").hide(); + } + set unread(flag) { + if (this._unread == flag) + return; + this._unread = flag; + this.htmlTag.find(".chatIcon").attr("class", "chatIcon icon " + this.chatIcon()); + if (flag) { + this.htmlTag.find(".name").css("color", "blue"); + } + else { + this.htmlTag.find(".name").css("color", "black"); + } + } + chatIcon() { + if (this._unread) { + switch (this.type) { + case ChatType.CLIENT: + return "client-new_chat"; + } + } + switch (this.type) { + case ChatType.SERVER: + return "client-server_log"; + case ChatType.CHANNEL: + return "client-channel_chat"; + case ChatType.CLIENT: + return "client-player_chat"; + case ChatType.GENERAL: + return "client-channel_chat"; + } + return ""; + } +} +class ChatBox { + constructor(htmlTag) { + this.htmlTag = htmlTag; + this._button_send = this.htmlTag.find(".button-send"); + this._input_message = this.htmlTag.find(".input-message"); + this._button_send.click(this.onSend.bind(this)); + this._input_message.keypress(event => { + if (event.keyCode == 13 /* Enter */ && !event.shiftKey) { + this.onSend(); + return false; + } + }).on('input', (event) => { + let text = $(event.target).val().toString(); + if (this.testMessage(text)) + this._button_send.removeAttr("disabled"); + else + this._button_send.attr("disabled", "true"); + }).trigger("input"); + this.chats = []; + this._activeChat = undefined; + this.createChat("chat_server", ChatType.SERVER).onMessageSend = (text) => { + if (!globalClient.serverConnection) { + chat.serverChat().appendError(_translations.MGIa7CAP || (_translations.MGIa7CAP = tr("Could not send chant message (Not connected)"))); + return; + } + globalClient.serverConnection.command_helper.sendMessage(text, ChatType.SERVER).catch(error => { + if (error instanceof CommandResult) + return; + chat.serverChat().appendMessage(_translations.EfA3bz33 || (_translations.EfA3bz33 = tr("Failed to send text message."))); + console.error(_translations.sZZ04N8U || (_translations.sZZ04N8U = tr("Failed to send server text message: %o")), error); + }); + }; + this.serverChat().name = _translations.XY0rgaAe || (_translations.XY0rgaAe = tr("Server chat")); + this.createChat("chat_channel", ChatType.CHANNEL).onMessageSend = (text) => { + if (!globalClient.serverConnection) { + chat.channelChat().appendError(_translations.YUpKiux0 || (_translations.YUpKiux0 = tr("Could not send chant message (Not connected)"))); + return; + } + globalClient.serverConnection.command_helper.sendMessage(text, ChatType.CHANNEL, globalClient.getClient().currentChannel()).catch(error => { + chat.channelChat().appendMessage(_translations.wtDGBoN6 || (_translations.wtDGBoN6 = tr("Failed to send text message."))); + console.error(_translations.AqmT7vNM || (_translations.AqmT7vNM = tr("Failed to send channel text message: %o")), error); + }); + }; + this.channelChat().name = _translations.CoEg7HKO || (_translations.CoEg7HKO = tr("Channel chat")); + globalClient.permissions.initializedListener.push(flag => { + if (flag) + this.activeChat0(this._activeChat); + }); + } + createChat(key, type = ChatType.CLIENT) { + let chat = new ChatEntry(this, type, key); + this.chats.push(chat); + this.htmlTag.find(".chats").append(chat.htmlTag); + if (!this._activeChat) + this.activeChat = chat; + return chat; + } + findChat(key) { + for (let e of this.chats) + if (e.key == key) + return e; + return undefined; + } + deleteChat(chat) { + this.chats.remove(chat); + chat.htmlTag.detach(); + if (this._activeChat === chat) { + if (this.chats.length > 0) + this.activeChat = this.chats.last(); + else + this.activeChat = undefined; + } + } + onSend() { + let text = this._input_message.val().toString(); + if (!this.testMessage(text)) + return; + this._input_message.val(""); + this._input_message.trigger("input"); + if (this._activeChat && $.isFunction(this._activeChat.onMessageSend)) + this._activeChat.onMessageSend(text); + } + set activeChat(chat) { + if (this.chats.indexOf(chat) === -1) + return; + if (this._activeChat == chat) + return; + this.activeChat0(chat); + } + activeChat0(chat) { + this._activeChat = chat; + for (let e of this.chats) + e.htmlTag.removeClass("active"); + let flagAllowSend = false; + if (this._activeChat) { + this._activeChat.htmlTag.addClass("active"); + this._activeChat.displayHistory(); + if (globalClient && globalClient.permissions && globalClient.permissions.initialized()) + switch (this._activeChat.type) { + case ChatType.CLIENT: + flagAllowSend = true; + break; + case ChatType.SERVER: + flagAllowSend = globalClient.permissions.neededPermission(PermissionType.B_CLIENT_SERVER_TEXTMESSAGE_SEND).granted(1); + break; + case ChatType.CHANNEL: + flagAllowSend = globalClient.permissions.neededPermission(PermissionType.B_CLIENT_CHANNEL_TEXTMESSAGE_SEND).granted(1); + break; + } + } + this._input_message.prop("disabled", !flagAllowSend); + } + get activeChat() { return this._activeChat; } + channelChat() { + return this.findChat("chat_channel"); + } + serverChat() { + return this.findChat("chat_server"); + } + focus() { + this._input_message.focus(); + } + testMessage(message) { + message = message + .replace(/ /gi, "") + .replace(/
    /gi, "") + .replace(/\n/gi, "") + .replace(//gi, ""); + return message.length > 0; + } +} +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["99e5c97edd3a1838be9eaa78a48faf59c9bbe7ed486b8c7683192cf4d5717219"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["99e5c97edd3a1838be9eaa78a48faf59c9bbe7ed486b8c7683192cf4d5717219"] = "99e5c97edd3a1838be9eaa78a48faf59c9bbe7ed486b8c7683192cf4d5717219"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "VrIqB5fQ", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalConnect.ts (108,22)" }, { name: "bTCq29_B", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalConnect.ts (135,29)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +/// +var Modals; +(function (Modals) { + function spawnConnectModal(defaultHost = { url: "ts.TeaSpeak.de", enforce: false }, connect_profile) { + let selected_profile; + const random_id = (() => { + const array = new Uint32Array(10); + window.crypto.getRandomValues(array); + return array.join(""); + })(); + const connect_modal = $("#tmpl_connect").renderTag({ + client: native_client, + forum_path: settings.static("forum_path"), + password_id: random_id + }).modalize((header, body, footer) => { + const button_connect = footer.find(".button-connect"); + const button_manage = body.find(".button-manage-profiles"); + const input_profile = body.find(".container-select-profile select"); + const input_address = body.find(".container-address input"); + const input_nickname = body.find(".container-nickname input"); + const input_password = body.find(".container-password input"); + let updateFields = function () { + console.log("Updating"); + if (selected_profile) + input_nickname.attr("placeholder", selected_profile.default_username); + else + input_nickname.attr("placeholder", ""); + let address = input_address.val().toString(); + settings.changeGlobal("connect_address", address); + let flag_address = !!address.match(Regex.IP_V4) || !!address.match(Regex.DOMAIN); + let nickname = input_nickname.val().toString(); + settings.changeGlobal("connect_name", nickname); + let flag_nickname = (nickname.length == 0 && selected_profile && selected_profile.default_username.length > 0) || nickname.length >= 3 && nickname.length <= 32; + input_address.attr('pattern', flag_address ? null : '^[a]{1000}$').toggleClass('is-invalid', !flag_address); + input_nickname.attr('pattern', flag_nickname ? null : '^[a]{1000}$').toggleClass('is-invalid', !flag_nickname); + if (!flag_nickname || !flag_address || !selected_profile || !selected_profile.valid()) { + button_connect.prop("disabled", true); + } + else { + button_connect.prop("disabled", false); + } + }; + input_nickname.val(settings.static_global("connect_name", undefined)); + input_address.val(defaultHost.enforce ? defaultHost.url : settings.static_global("connect_address", defaultHost.url)); + input_address + .on("keyup", () => updateFields()) + .on('keydown', event => { + if (event.keyCode == 13 /* Enter */ && !event.shiftKey) + button_connect.trigger('click'); + }); + button_manage.on('click', event => { + const modal = Modals.spawnSettingsModal(); + setTimeout(() => { + modal.htmlTag.find(".tab-profiles").parent(".entry").trigger('click'); + }, 100); + modal.close_listener.push(() => { + input_profile.trigger('change'); + }); + return true; + }); + { + for (const profile of profiles.profiles()) { + input_profile.append($.spawn("option").text(profile.profile_name).val(profile.id)); + } + input_profile.on('change', event => { + selected_profile = profiles.find_profile(input_profile.val()); + input_profile.toggleClass("is-invalid", !selected_profile || !selected_profile.valid()); + updateFields(); + }); + input_profile.val(connect_profile && connect_profile.enforce ? connect_profile.profile.id : connect_profile && connect_profile.profile ? connect_profile.profile.id : 'default').trigger('change'); + } + input_nickname.on("keyup", () => updateFields()); + setTimeout(() => updateFields(), 100); + button_connect.on('click', event => { + connect_modal.close(); + globalClient.startConnection(input_address.val().toString(), selected_profile, input_nickname.val().toString() || selected_profile.default_username, { password: input_password.val().toString(), hashed: false }); + }); + }, { + width: '70%' + }); + connect_modal.open(); + return; + const connectModal = createModal({ + header: (_translations.VrIqB5fQ || (_translations.VrIqB5fQ = tr("Create a new connection"))), + body: function () { + const random_id = (() => { + const array = new Uint32Array(10); + window.crypto.getRandomValues(array); + return array.join(""); + })(); + let tag = $("#tmpl_connect").renderTag({ + client: native_client, + forum_path: settings.static("forum_path"), + password_id: random_id + }); + //connect_address + return tag; + }, + footer: function () { + let tag = $.spawn("div"); + tag.css("text-align", "right"); + tag.css("margin-top", "3px"); + tag.css("margin-bottom", "6px"); + tag.addClass("modal-button-group"); + let button = $.spawn("button"); + button.addClass("connect_connect_button"); + button.text(_translations.bTCq29_B || (_translations.bTCq29_B = tr("Connect"))); + button.on("click", function () { + connectModal.close(); + let field_address = tag.parents(".modal-content").find(".connect_address"); + let address = field_address.val().toString(); + globalClient.startConnection(address, selected_profile, tag.parents(".modal-content").find(".connect_nickname").val().toString() || selected_profile.default_username, { password: tag.parents(".modal-content").find(".connect_password").val().toString(), hashed: false }); + }); + tag.append(button); + return tag; + }, + width: '70%', + }); + connectModal.open(); + } + Modals.spawnConnectModal = spawnConnectModal; + let Regex = { + //DOMAIN<:port> + DOMAIN: /^(localhost|((([a-zA-Z0-9_-]{0,63}\.){0,253})?[a-zA-Z0-9_-]{0,63}\.[a-zA-Z]{2,5}))(|:(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|6[0-4][0-9]{3}|[0-5]?[0-9]{1,4}))$/, + //IP<:port> + IP_V4: /(^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))(|:(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|6[0-4][0-9]{3}|[0-5]?[0-9]{1,4}))$/, + IP_V6: /(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))/, + IP: /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$|^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$|^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/, + }; +})(Modals || (Modals = {})); +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["b8e4f60078c1425a1d8af9663d67add823c93e182cd404cdbdebb0fb94615d1c"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["b8e4f60078c1425a1d8af9663d67add823c93e182cd404cdbdebb0fb94615d1c"] = "b8e4f60078c1425a1d8af9663d67add823c93e182cd404cdbdebb0fb94615d1c"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "b5sCmZ9x", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalBanCreate.ts (8,46)" }, { name: "bTAny5Zt", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalBanCreate.ts (8,63)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +var Modals; +(function (Modals) { + function spawnBanCreate(base, callback) { + let result = {}; + result.banid = base ? base.banid : 0; + let modal; + modal = createModal({ + header: base && base.banid > 0 ? _translations.b5sCmZ9x || (_translations.b5sCmZ9x = tr("Edit ban")) : _translations.bTAny5Zt || (_translations.bTAny5Zt = tr("Add ban")), + body: () => { + let template = $("#tmpl_ban_create").renderTag(); + const input_name = template.find(".input-name"); + const input_name_type = template.find(".input-name-type"); + const input_ip = template.find(".input-ip"); + const input_uid = template.find(".input-uid"); + const input_reason = template.find(".input-reason"); + const input_time = template.find(".input-time"); + const input_time_type = template.find(".input-time-unit"); + const input_hwid = template.find(".input-hwid"); + const input_global = template.find(".input-global"); + { + let maxTime = 0; //globalClient.permissions.neededPermission(PermissionType.I_CLIENT_BAN_MAX_BANTIME).value; + let unlimited = maxTime == 0 || maxTime == -1; + if (unlimited) + maxTime = 0; + input_time_type.find("option[value=\"sec\"]").prop("disabled", !unlimited && 1 > maxTime) + .attr("duration-scale", 1) + .attr("duration-max", maxTime); + input_time_type.find("option[value=\"min\"]").prop("disabled", !unlimited && 60 > maxTime) + .attr("duration-scale", 60) + .attr("duration-max", maxTime / 60); + input_time_type.find("option[value=\"hours\"]").prop("disabled", !unlimited && 60 * 60 > maxTime) + .attr("duration-scale", 60 * 60) + .attr("duration-max", maxTime / (60 * 60)); + input_time_type.find("option[value=\"days\"]").prop("disabled", !unlimited && 60 * 60 * 24 > maxTime) + .attr("duration-scale", 60 * 60 * 24) + .attr("duration-max", maxTime / (60 * 60 * 24)); + input_time_type.find("option[value=\"perm\"]").prop("disabled", !unlimited) + .attr("duration-scale", 0); + input_time_type.change(event => { + let element = $(event.target.selectedOptions.item(0)); + if (element.val() !== "perm") { + input_time.prop("disabled", false); + let current = input_time.val(); + let max = parseInt(element.attr("duration-max")); + if (max > 0 && current > max) + input_time.val(max); + else if (current <= 0) + input_time.val(1); + input_time.attr("max", max); + } + else { + input_time.prop("disabled", true); + } + }); + } + template.find('input, textarea').on('keyup change', event => { + let valid = false; + if (input_name.val() || input_ip.val() || input_uid.val()) + valid = true; + modal.htmlTag.find(".button-success").prop("disabled", !valid); + }); + if (base) { + input_ip.val(base.ip); + input_uid.val(base.unique_id); + input_name.val(base.name); + input_hwid.val(base.hardware_id); + input_name_type[0].selectedIndex = base.name_type || 0; + input_reason.val(base.reason); + if (base.timestamp_expire.getTime() == 0) { + input_time_type.find("option[value=\"perm\"]").prop("selected", true); + } + else { + const time = (base.timestamp_expire.getTime() - base.timestamp_created.getTime()) / 1000; + if (time % (60 * 60 * 24) === 0) { + input_time_type.find("option[value=\"days\"]").prop("selected", true); + input_time.val(time / (60 * 60 * 24)); + } + else if (time % (60 * 60) === 0) { + input_time_type.find("option[value=\"hours\"]").prop("selected", true); + input_time.val(time / (60 * 60)); + } + else if (time % (60) === 0) { + input_time_type.find("option[value=\"min\"]").prop("selected", true); + input_time.val(time / (60)); + } + else { + input_time_type.find("option[value=\"sec\"]").prop("selected", true); + input_time.val(time); + } + } + template.find(".container-global").detach(); //We cant edit this + input_global.prop("checked", base.server_id == 0); + } + if (globalClient && globalClient.permissions) + input_global.prop("disabled", !globalClient.permissions.neededPermission(base ? PermissionType.B_CLIENT_BAN_EDIT_GLOBAL : PermissionType.B_CLIENT_BAN_CREATE_GLOBAL)); + return template; + }, + footer: undefined + }); + modal.htmlTag.find(".button-close").on('click', () => modal.close()); + modal.htmlTag.find(".button-success").on('click', () => { + { + let length = modal.htmlTag.find(".input-time").val(); + let duration = modal.htmlTag.find(".input-time-unit option:selected"); + console.log(duration); + console.log(length + "*" + duration.attr("duration-scale")); + const time = length * parseInt(duration.attr("duration-scale")); + if (!result.timestamp_created) + result.timestamp_created = new Date(); + if (time > 0) + result.timestamp_expire = new Date(result.timestamp_created.getTime() + time * 1000); + else + result.timestamp_expire = new Date(0); + } + { + result.name = modal.htmlTag.find(".input-name").val(); + { + const name_type = modal.htmlTag.find(".input-name-type"); + result.name_type = name_type[0].selectedIndex; + } + result.ip = modal.htmlTag.find(".input-ip").val(); + result.unique_id = modal.htmlTag.find(".input-uid").val(); + result.reason = modal.htmlTag.find(".input-reason").val(); + result.hardware_id = modal.htmlTag.find(".input-hwid").val(); + result.server_id = modal.htmlTag.find(".input-global").prop("checked") ? 0 : -1; + } + modal.close(); + if (callback) + callback(result); + }); + modal.htmlTag.find("input").trigger("change"); + modal.open(); + } + Modals.spawnBanCreate = spawnBanCreate; +})(Modals || (Modals = {})); +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["b1eccee991e042e75ec3bb4e9a36bffeb9655687560ce4b5f831f3b55f9695bd"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["b1eccee991e042e75ec3bb4e9a36bffeb9655687560ce4b5f831f3b55f9695bd"] = "b1eccee991e042e75ec3bb4e9a36bffeb9655687560ce4b5f831f3b55f9695bd"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "oY1dCM4N", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalBanClient.ts (15,24)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +/// +/// +/// +var Modals; +(function (Modals) { + function spawnBanClient(name, callback) { + const connectModal = createModal({ + header: function () { + return _translations.oY1dCM4N || (_translations.oY1dCM4N = tr("Ban client")); + }, + body: function () { + let tag = $("#tmpl_client_ban").renderTag({ + client_name: $.isArray(name) ? '"' + name.join('", "') + '"' : name + }); + let maxTime = 0; //globalClient.permissions.neededPermission(PermissionType.I_CLIENT_BAN_MAX_BANTIME).value; + let unlimited = maxTime == 0 || maxTime == -1; + if (unlimited) + maxTime = 0; + let banTag = tag.find(".ban_duration_type"); + let durationTag = tag.find(".ban_duration"); + banTag.find("option[value=\"sec\"]").prop("disabled", !unlimited && 1 > maxTime) + .attr("duration-scale", 1) + .attr("duration-max", maxTime); + banTag.find("option[value=\"min\"]").prop("disabled", !unlimited && 60 > maxTime) + .attr("duration-scale", 60) + .attr("duration-max", maxTime / 60); + banTag.find("option[value=\"hours\"]").prop("disabled", !unlimited && 60 * 60 > maxTime) + .attr("duration-scale", 60 * 60) + .attr("duration-max", maxTime / (60 * 60)); + banTag.find("option[value=\"days\"]").prop("disabled", !unlimited && 60 * 60 * 24 > maxTime) + .attr("duration-scale", 60 * 60 * 24) + .attr("duration-max", maxTime / (60 * 60 * 24)); + banTag.find("option[value=\"perm\"]").prop("disabled", !unlimited) + .attr("duration-scale", 0); + durationTag.change(() => banTag.trigger('change')); + banTag.change(event => { + let element = $(event.target.selectedOptions.item(0)); + if (element.val() !== "perm") { + durationTag.prop("disabled", false); + let current = durationTag.val(); + let max = parseInt(element.attr("duration-max")); + if (max > 0 && current > max) + durationTag.val(max); + else if (current <= 0) + durationTag.val(1); + durationTag.attr("max", max); + } + else { + durationTag.prop("disabled", true); + } + }); + return tag; + }, + footer: function () { + let tag = $.spawn("div"); + tag.css("text-align", "right"); + tag.css("margin-top", "3px"); + tag.css("margin-bottom", "6px"); + tag.addClass("modal-button-group"); + let buttonCancel = $.spawn("button"); + buttonCancel.text("Cancel"); + buttonCancel.on("click", () => connectModal.close()); + tag.append(buttonCancel); + let buttonOk = $.spawn("button"); + buttonOk.text("OK").addClass("btn_success"); + tag.append(buttonOk); + return tag; + }, + width: 450 + }); + connectModal.open(); + connectModal.htmlTag.find(".btn_success").on('click', () => { + connectModal.close(); + let length = connectModal.htmlTag.find(".ban_duration").val(); + let duration = connectModal.htmlTag.find(".ban_duration_type option:selected"); + console.log(duration); + console.log(length + "*" + duration.attr("duration-scale")); + callback({ + length: length * parseInt(duration.attr("duration-scale")), + reason: connectModal.htmlTag.find(".ban_reason").val(), + no_hwid: !connectModal.htmlTag.find(".ban-type-hardware-id").prop("checked"), + no_ip: !connectModal.htmlTag.find(".ban-type-ip").prop("checked"), + no_name: !connectModal.htmlTag.find(".ban-type-nickname").prop("checked") + }); + }); + } + Modals.spawnBanClient = spawnBanClient; +})(Modals || (Modals = {})); +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["65037f2c6d919416a95acc097f67bbba896dd13dbfecd2adeb8837e042710bd5"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["65037f2c6d919416a95acc097f67bbba896dd13dbfecd2adeb8837e042710bd5"] = "65037f2c6d919416a95acc097f67bbba896dd13dbfecd2adeb8837e042710bd5"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "ihb8iu3f", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalYesNo.ts (12,69)" }, { name: "aM9nGh0r", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalYesNo.ts (13,67)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +/// +var Modals; +(function (Modals) { + function spawnYesNo(header, body, callback, properties) { + properties = properties || {}; + const props = ModalFunctions.warpProperties({}); + props.template_properties || (props.template_properties = {}); + props.template_properties.text_yes = properties.text_yes || (_translations.ihb8iu3f || (_translations.ihb8iu3f = tr("Yes"))); + props.template_properties.text_no = properties.text_no || (_translations.aM9nGh0r || (_translations.aM9nGh0r = tr("No"))); + props.template = "#tmpl_modal_yesno"; + props.header = header; + props.template_properties.question = ModalFunctions.jqueriefy(body); + const modal = createModal(props); + let submited = false; + const button_yes = modal.htmlTag.find(".button-yes"); + const button_no = modal.htmlTag.find(".button-no"); + button_yes.on('click', event => { + if (!submited) { + submited = true; + callback(true); + } + modal.close(); + }); + button_no.on('click', event => { + if (!submited) { + submited = true; + callback(false); + } + modal.close(); + }); + modal.close_listener.push(() => button_no.trigger('click')); + modal.open(); + return modal; + } + Modals.spawnYesNo = spawnYesNo; +})(Modals || (Modals = {})); +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["b66fb0e58435bfead237d2b8cad56e8fc65416f10f426108cc9a389a32365d95"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["b66fb0e58435bfead237d2b8cad56e8fc65416f10f426108cc9a389a32365d95"] = "b66fb0e58435bfead237d2b8cad56e8fc65416f10f426108cc9a389a32365d95"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "XXGJLzMB", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/main.ts (107,23)" }, { name: "OKomiF7N", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/main.ts (116,28)" }, { name: "sfdo9OmQ", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/main.ts (117,23)" }, { name: "tfe6lvUm", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/main.ts (127,28)" }, { name: "B4PHs4eG", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/main.ts (137,23)" }, { name: "MAC72mNf", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/main.ts (138,30)" }, { name: "XYBSTh0P", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/main.ts (293,45)" }, { name: "yBDIX0TS", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/main.ts (295,35)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +let settings; +let globalClient; +let chat; +const js_render = window.jsrender || $; +const native_client = window.require !== undefined; +function getUserMediaFunction() { + if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) + return (settings, success, fail) => { navigator.mediaDevices.getUserMedia(settings).then(success).catch(fail); }; + return navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia; +} +function setup_close() { + window.onbeforeunload = event => { + if (profiles.requires_save()) + profiles.save(); + if (!settings.static(Settings.KEY_DISABLE_UNLOAD_DIALOG, false)) { + if (!globalClient.serverConnection || !globalClient.serverConnection.connected) + return; + if (!native_client) { + event.returnValue = "Are you really sure?
    You're still connected!"; + } + else { + event.preventDefault(); + event.returnValue = "question"; + const { remote } = require('electron'); + const dialog = remote.dialog; + dialog.showMessageBox(remote.getCurrentWindow(), { + 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(); + } + }); + } + } + }; +} +function setup_jsrender() { + if (!js_render) { + displayCriticalError("Missing jsrender extension!"); + return false; + } + if (!js_render.views) { + displayCriticalError("Missing jsrender viewer extension!"); + return false; + } + js_render.views.settings.allowCode(true); + js_render.views.tags("rnd", (argument) => { + 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; +} +function initialize() { + return __awaiter(this, void 0, void 0, function* () { + const display_load_error = message => { + if (typeof (display_critical_load) !== "undefined") + display_critical_load(message); + else + displayCriticalError(message); + }; + settings = new Settings(); + try { + yield i18n.initialize(); + } + catch (error) { + console.error(_translations.XXGJLzMB || (_translations.XXGJLzMB = 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(_translations.OKomiF7N || (_translations.OKomiF7N = tr("Failed to setup jsrender"))); + console.error(_translations.sfdo9OmQ || (_translations.sfdo9OmQ = tr("Failed to load jsrender! %o")), error); + return; + } + try { //Initialize main template + const main = $("#tmpl_main").renderTag().dividerfy(); + $("body").append(main); + } + catch (error) { + console.error(error); + display_load_error(_translations.tfe6lvUm || (_translations.tfe6lvUm = tr("Failed to setup main page!"))); + return; + } + AudioController.initializeAudioController(); + yield profiles.load(); + try { + yield ppt.initialize(); + } + catch (error) { + console.error(_translations.B4PHs4eG || (_translations.B4PHs4eG = tr("Failed to initialize ppt!\nError: %o")), error); + displayCriticalError(_translations.MAC72mNf || (_translations.MAC72mNf = tr("Failed to initialize ppt!"))); + return; + } + 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) { + 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, pad) { + 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 + globalClient = new TSClient(); + /** Setup the XF forum identity **/ + profiles.identities.setup_forum(); + chat = new ChatBox($("#chat")); + globalClient.setup(); + if (settings.static("connect_default", false) && settings.static("connect_address", "")) { + const profile_uuid = settings.static("connect_profile"); + console.log("UUID: %s", profile_uuid); + const profile = profiles.find_profile(profile_uuid) || profiles.default_profile(); + const address = settings.static("connect_address", ""); + const username = settings.static("connect_username", "Another TeaSpeak user"); + const password = settings.static("connect_password", ""); + const password_hashed = settings.static("connect_password_hashed", false); + if (profile && profile.valid()) { + globalClient.startConnection(address, profile, username, password.length > 0 ? { + password: password, + hashed: password_hashed + } : undefined); + } + else { + Modals.spawnConnectModal({ + url: address, + enforce: true + }, { + profile: profile, + enforce: true + }); + } + } + let _resize_timeout; + $(window).on('resize', () => { + if (_resize_timeout) + clearTimeout(_resize_timeout); + _resize_timeout = setTimeout(() => { + globalClient.channelTree.handle_resized(); + }, 1000); + }); + 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); + }); +} +loader.register_task(loader.Stage.LOADED, { + name: "async main invoke", + function: () => __awaiter(this, void 0, void 0, function* () { + try { + yield initialize(); + main(); + if (!audio.player.initialized()) { + log.info(LogCategory.VOICE, _translations.XYBSTh0P || (_translations.XYBSTh0P = tr("Initialize audio controller later!"))); + if (!audio.player.initializeFromGesture) { + console.error(_translations.yBDIX0TS || (_translations.yBDIX0TS = 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:
    " + ex); + } + }), + priority: 10 +}); +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["22225479565e3b4bafc85629870ed7c1fbd292de3ee4e385bac4ec01beab7af6"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["22225479565e3b4bafc85629870ed7c1fbd292de3ee4e385bac4ec01beab7af6"] = "22225479565e3b4bafc85629870ed7c1fbd292de3ee4e385bac4ec01beab7af6"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "sCcGqyZs", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/stats.ts (76,38)" }, { name: "hYfNfpY2", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/stats.ts (113,50)" }, { name: "ed4qDxmJ", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/stats.ts (123,50)" }, { name: "X1087nBI", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/stats.ts (133,50)" }, { name: "YQ1xbSKD", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/stats.ts (144,55)" }, { name: "McuKHkxC", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/stats.ts (173,42)" }, { name: "dYrfWrvw", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/stats.ts (177,46)" }, { name: "VMpPaDl0", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/stats.ts (215,48)" }, { name: "qpgGDXwk", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/stats.ts (218,43)" }, { name: "DLaaN9c_", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/stats.ts (234,46)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +var stats; +(function (stats) { + const LOG_PREFIX = "[Statistics] "; + let CloseCodes; + (function (CloseCodes) { + CloseCodes[CloseCodes["UNSET"] = 3000] = "UNSET"; + CloseCodes[CloseCodes["RECONNECT"] = 3001] = "RECONNECT"; + CloseCodes[CloseCodes["INTERNAL_ERROR"] = 3002] = "INTERNAL_ERROR"; + CloseCodes[CloseCodes["BANNED"] = 3100] = "BANNED"; + })(CloseCodes = stats.CloseCodes || (stats.CloseCodes = {})); + let ConnectionState; + (function (ConnectionState) { + ConnectionState[ConnectionState["CONNECTING"] = 0] = "CONNECTING"; + ConnectionState[ConnectionState["INITIALIZING"] = 1] = "INITIALIZING"; + ConnectionState[ConnectionState["CONNECTED"] = 2] = "CONNECTED"; + ConnectionState[ConnectionState["UNSET"] = 3] = "UNSET"; + })(ConnectionState || (ConnectionState = {})); + class SessionConfig { + } + stats.SessionConfig = SessionConfig; + class Config extends SessionConfig { + } + stats.Config = Config; + let reconnect_timer; + let current_config; + let last_user_count_update; + let user_count_listener = []; + const DEFAULT_CONFIG = { + verbose: true, + reconnect_interval: 5000, + anonymize_ip_addresses: true, + volatile_collection_only: false + }; + function initialize_config_object(target_object, source_object) { + for (const key of Object.keys(source_object)) { + if (typeof (source_object[key]) === 'object') + initialize_config_object(target_object[key] || (target_object[key] = {}), source_object[key]); + if (typeof (target_object[key]) !== 'undefined') + continue; + target_object[key] = source_object[key]; + } + return target_object; + } + function initialize(config) { + current_config = initialize_config_object(config || {}, DEFAULT_CONFIG); + if (current_config.verbose) + console.log(LOG_PREFIX + (_translations.sCcGqyZs || (_translations.sCcGqyZs = tr("Initializing statistics with this config: %o"))), current_config); + connection.start_connection(); + } + stats.initialize = initialize; + function register_user_count_listener(listener) { + user_count_listener.push(listener); + } + stats.register_user_count_listener = register_user_count_listener; + function all_user_count_listener() { + return user_count_listener; + } + stats.all_user_count_listener = all_user_count_listener; + function deregister_user_count_listener(listener) { + user_count_listener.remove(listener); + } + stats.deregister_user_count_listener = deregister_user_count_listener; + let connection; + (function (connection_2) { + let connection; + connection_2.connection_state = ConnectionState.UNSET; + function start_connection() { + cancel_reconnect(); + close_connection(); + connection_2.connection_state = ConnectionState.CONNECTING; + connection = new WebSocket('wss://web-stats.teaspeak.de:27790'); + if (!connection) + connection = new WebSocket('wss://localhost:27788'); + { + const connection_copy = connection; + connection.onclose = (event) => { + if (connection_copy !== connection) + return; + if (current_config.verbose) + console.log(LOG_PREFIX + (_translations.hYfNfpY2 || (_translations.hYfNfpY2 = tr("Lost connection to statistics server (Connection closed). Reason: %o. Event object: %o"))), CloseCodes[event.code] || event.code, event); + if (event.code != CloseCodes.BANNED) + invoke_reconnect(); + }; + connection.onopen = () => { + if (connection_copy !== connection) + return; + if (current_config.verbose) + console.log(LOG_PREFIX + (_translations.ed4qDxmJ || (_translations.ed4qDxmJ = tr("Successfully connected to server. Initializing session.")))); + connection_2.connection_state = ConnectionState.INITIALIZING; + initialize_session(); + }; + connection.onerror = (event) => { + if (connection_copy !== connection) + return; + if (current_config.verbose) + console.log(LOG_PREFIX + (_translations.X1087nBI || (_translations.X1087nBI = tr("Received an error. Closing connection. Object: %o"))), event); + connection.close(CloseCodes.INTERNAL_ERROR); + invoke_reconnect(); + }; + connection.onmessage = (event) => { + if (connection_copy !== connection) + return; + if (typeof (event.data) !== 'string') { + if (current_config.verbose) + console.warn(LOG_PREFIX + (_translations.YQ1xbSKD || (_translations.YQ1xbSKD = tr("Received an message which isn't a string. Event object: %o"))), event); + return; + } + handle_message(event.data); + }; + } + } + connection_2.start_connection = start_connection; + function close_connection() { + if (connection) { + const connection_copy = connection; + connection = undefined; + try { + connection_copy.close(3001); + } + catch (_) { } + } + } + connection_2.close_connection = close_connection; + function invoke_reconnect() { + close_connection(); + if (reconnect_timer) { + clearTimeout(reconnect_timer); + reconnect_timer = undefined; + } + if (current_config.verbose) + console.log(LOG_PREFIX + (_translations.McuKHkxC || (_translations.McuKHkxC = tr("Scheduled reconnect in %dms"))), current_config.reconnect_interval); + reconnect_timer = setTimeout(() => { + if (current_config.verbose) + console.log(LOG_PREFIX + (_translations.dYrfWrvw || (_translations.dYrfWrvw = tr("Reconnecting")))); + start_connection(); + }, current_config.reconnect_interval); + } + function cancel_reconnect() { + if (reconnect_timer) { + clearTimeout(reconnect_timer); + reconnect_timer = undefined; + } + } + connection_2.cancel_reconnect = cancel_reconnect; + function send_message(type, data) { + connection.send(JSON.stringify({ + type: type, + data: data + })); + } + function initialize_session() { + const config_object = {}; + for (const key in SessionConfig) { + if (SessionConfig.hasOwnProperty(key)) + config_object[key] = current_config[key]; + } + send_message('initialize', { + config: config_object + }); + } + function handle_message(message) { + const data_object = JSON.parse(message); + const type = data_object.type; + const data = data_object.data; + if (typeof (handler[type]) === 'function') { + if (current_config.verbose) + console.debug(LOG_PREFIX + (_translations.VMpPaDl0 || (_translations.VMpPaDl0 = tr("Handling message of type %s"))), type); + handler[type](data); + } + else if (current_config.verbose) { + console.warn(LOG_PREFIX + (_translations.qpgGDXwk || (_translations.qpgGDXwk = tr("Received message with an unknown type (%s). Dropping message. Full message: %o"))), type, data_object); + } + } + let handler; + (function (handler) { + function handle_notify_user_count(data) { + last_user_count_update = Date.now(); + for (const listener of [...user_count_listener]) + listener(data); + } + function handle_notify_initialized(json) { + if (current_config.verbose) + console.log(LOG_PREFIX + (_translations.DLaaN9c_ || (_translations.DLaaN9c_ = tr("Session successfully initialized.")))); + connection_2.connection_state = ConnectionState.CONNECTED; + } + handler["notifyinitialized"] = handle_notify_initialized; + handler["notifyusercount"] = handle_notify_user_count; + })(handler || (handler = {})); + })(connection || (connection = {})); +})(stats || (stats = {})); +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["7a121df37aea016cf9035da97ff8c312caed0597dd07d2e78dcb684543854f7b"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["7a121df37aea016cf9035da97ff8c312caed0597dd07d2e78dcb684543854f7b"] = "7a121df37aea016cf9035da97ff8c312caed0597dd07d2e78dcb684543854f7b"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "c4oCx1uR", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/codec/BasicCodec.ts (52,74)" }, { name: "pzkU8E2k", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/codec/BasicCodec.ts (53,101)" }, { name: "cePIMcCz", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/codec/BasicCodec.ts (77,39)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +/// +class AVGCalculator { + constructor() { + this.history_size = 100; + this.history = []; + } + push(entry) { + while (this.history.length > this.history_size) + this.history.pop(); + this.history.unshift(entry); + } + avg() { + let count = 0; + for (let entry of this.history) + count += entry; + return count / this.history.length; + } +} +class BasicCodec { + constructor(codecSampleRate) { + this._latenz = new AVGCalculator(); + this.on_encoded_data = $ => { }; + this.channelCount = 1; + this.samplesPerUnit = 960; + this.channelCount = 1; + this.samplesPerUnit = 960; + this._audioContext = new (window.webkitOfflineAudioContext || window.OfflineAudioContext)(audio.player.destination().channelCount, 1024, audio.player.context().sampleRate); + this._codecSampleRate = codecSampleRate; + this._decodeResampler = new AudioResampler(audio.player.context().sampleRate); + this._encodeResampler = new AudioResampler(codecSampleRate); + } + encodeSamples(cache, pcm) { + this._encodeResampler.resample(pcm).catch(error => console.error(_translations.c4oCx1uR || (_translations.c4oCx1uR = tr("Could not resample PCM data for codec. Error: %o")), error)) + .then(buffer => this.encodeSamples0(cache, buffer)).catch(error => console.error(_translations.pzkU8E2k || (_translations.pzkU8E2k = tr("Could not encode PCM data for codec. Error: %o")), error)); + } + encodeSamples0(cache, buffer) { + cache._chunks.push(new BufferChunk(buffer)); //TODO multi channel! + while (cache.bufferedSamples(this.samplesPerUnit) >= this.samplesPerUnit) { + let buffer = this._audioContext.createBuffer(this.channelCount, this.samplesPerUnit, this._codecSampleRate); + let index = 0; + while (index < this.samplesPerUnit) { + let buf = cache._chunks[0]; + let cpyBytes = buf.copyRangeTo(buffer, this.samplesPerUnit - index, index); + index += cpyBytes; + buf.index += cpyBytes; + if (buf.index == buf.buffer.length) + cache._chunks.pop_front(); + } + let encodeBegin = Date.now(); + this.encode(buffer).then(result => { + if (result instanceof Uint8Array) { + let time = Date.now() - encodeBegin; + if (time > 20) + console.error(_translations.cePIMcCz || (_translations.cePIMcCz = tr("Required time: %d")), time); + //if(time > 20) + // chat.serverChat().appendMessage("Required decode time: " + time); + this.on_encoded_data(result); + } + else + console.error("[Codec][" + this.name() + "] Could not encode buffer. Result: " + result); //TODO tr + }); + } + return true; + } + decodeSamples(cache, data) { + return this.decode(data).then(buffer => this._decodeResampler.resample(buffer)); + } +} +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["aab3a372abbb05d1f95e507d5b92d24b652b81c75a3f0d8163d1344cf0046b79"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["aab3a372abbb05d1f95e507d5b92d24b652b81c75a3f0d8163d1344cf0046b79"] = "aab3a372abbb05d1f95e507d5b92d24b652b81c75a3f0d8163d1344cf0046b79"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of []) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +/// +class CodecWrapperRaw extends BasicCodec { + constructor(codecSampleRate) { + super(codecSampleRate); + this.bufferSize = 4096 * 4; + } + name() { + return "raw"; + } + initialise() { + this.converterRaw = Module._malloc(this.bufferSize); + this.converter = new Uint8Array(Module.HEAPU8.buffer, this.converterRaw, this.bufferSize); + return new Promise(resolve => resolve()); + } + initialized() { + return true; + } + deinitialise() { } + decode(data) { + return new Promise((resolve, reject) => { + this.converter.set(data); + let buf = Module.HEAPF32.slice(this.converter.byteOffset / 4, (this.converter.byteOffset / 4) + data.length / 4); + let audioBuf = this._audioContext.createBuffer(1, data.length / 4, this._codecSampleRate); + audioBuf.copyToChannel(buf, 0); + resolve(audioBuf); + }); + } + encode(data) { + return new Promise(resolve => resolve(new Uint8Array(data.getChannelData(0)))); + } + reset() { return true; } + processLatency() { + return 0; + } +} +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["7ad8220e27cab46acc322af547c49bd0c5d1136722ba934f57c1a3a43669f66b"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["7ad8220e27cab46acc322af547c49bd0c5d1136722ba934f57c1a3a43669f66b"] = "7ad8220e27cab46acc322af547c49bd0c5d1136722ba934f57c1a3a43669f66b"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "mVOeydNI", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/codec/CodecWrapperWorker.ts (156,26)" }, { name: "UY6zlrk1", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/codec/CodecWrapperWorker.ts (158,27)" }, { name: "yWCPu1Vl", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/codec/CodecWrapperWorker.ts (164,29)" }, { name: "k3gMhK6X", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/codec/CodecWrapperWorker.ts (179,25)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +/// +class CodecWrapperWorker extends BasicCodec { + constructor(type) { + super(48000); + this._workerListener = []; + this._workerCallbackToken = "callback_token"; + this._workerTokeIndex = 0; + this._initialized = false; + this.type = type; + switch (type) { + case CodecType.OPUS_MUSIC: + this.channelCount = 2; + break; + case CodecType.OPUS_VOICE: + this.channelCount = 1; + break; + default: + throw "invalid codec type!"; + } + } + name() { + return "Worker for " + CodecType[this.type] + " Channels " + this.channelCount; + } + initialise() { + if (this._initializePromise) + return this._initializePromise; + return this._initializePromise = this.spawnWorker().then(() => new Promise((resolve, reject) => { + const token = this.generateToken(); + this.sendWorkerMessage({ + command: "initialise", + type: this.type, + channelCount: this.channelCount, + token: token + }); + this._workerListener.push({ + token: token, + resolve: data => { + this._initialized = data["success"] == true; + if (data["success"] == true) + resolve(); + else + reject(data.message); + } + }); + })); + } + initialized() { + return this._initialized; + } + deinitialise() { + this.sendWorkerMessage({ + command: "deinitialise" + }); + } + decode(data) { + let token = this.generateToken(); + let result = new Promise((resolve, reject) => { + this._workerListener.push({ + token: token, + resolve: (data) => { + if (data.success) { + let array = new Float32Array(data.dataLength); + for (let index = 0; index < array.length; index++) + array[index] = data.data[index]; + let audioBuf = this._audioContext.createBuffer(this.channelCount, array.length / this.channelCount, this._codecSampleRate); + for (let channel = 0; channel < this.channelCount; channel++) { + for (let offset = 0; offset < audioBuf.length; offset++) { + audioBuf.getChannelData(channel)[offset] = array[channel + offset * this.channelCount]; + } + } + resolve(audioBuf); + } + else { + reject(data.message); + } + } + }); + }); + this.sendWorkerMessage({ + command: "decodeSamples", + token: token, + data: data, + dataLength: data.length + }); + return result; + } + encode(data) { + let token = this.generateToken(); + let result = new Promise((resolve, reject) => { + this._workerListener.push({ + token: token, + resolve: (data) => { + if (data.success) { + let array = new Uint8Array(data.dataLength); + for (let index = 0; index < array.length; index++) + array[index] = data.data[index]; + resolve(array); + } + else { + reject(data.message); + } + } + }); + }); + let buffer = new Float32Array(this.channelCount * data.length); + for (let offset = 0; offset < data.length; offset++) { + for (let channel = 0; channel < this.channelCount; channel++) + buffer[offset * this.channelCount + channel] = data.getChannelData(channel)[offset]; + } + this.sendWorkerMessage({ + command: "encodeSamples", + token: token, + data: buffer, + dataLength: buffer.length + }); + return result; + } + reset() { + this.sendWorkerMessage({ + command: "reset" + }); + return true; + } + generateToken() { + return this._workerTokeIndex++ + "_token"; + } + sendWorkerMessage(message, transfare) { + message["timestamp"] = Date.now(); + this._worker.postMessage(message, transfare); + } + onWorkerMessage(message) { + if (Date.now() - message["timestamp"] > 5) + console.warn(_translations.mVOeydNI || (_translations.mVOeydNI = tr("Worker message stock time: %d")), Date.now() - message["timestamp"]); + if (!message["token"]) { + console.error(_translations.UY6zlrk1 || (_translations.UY6zlrk1 = tr("Invalid worker token!"))); + return; + } + if (message["token"] == this._workerCallbackToken) { + if (message["type"] == "loaded") { + console.log(_translations.yWCPu1Vl || (_translations.yWCPu1Vl = tr("[Codec] Got worker init response: Success: %o Message: %o")), message["success"], message["message"]); + if (message["success"]) { + if (this._workerCallbackResolve) + this._workerCallbackResolve(); + } + else { + if (this._workerCallbackReject) + this._workerCallbackReject(message["message"]); + } + this._workerCallbackReject = undefined; + this._workerCallbackResolve = undefined; + return; + } + else if (message["type"] == "chatmessage_server") { + chat.serverChat().appendMessage(message["message"]); + return; + } + console.log(_translations.k3gMhK6X || (_translations.k3gMhK6X = tr("Costume callback! (%o)")), message); + return; + } + for (let entry of this._workerListener) { + if (entry.token == message["token"]) { + entry.resolve(message); + this._workerListener.remove(entry); + return; + } + } + //TODO tr + console.error("Could not find worker token entry! (" + message["token"] + ")"); + } + spawnWorker() { + return new Promise((resolve, reject) => { + this._workerCallbackReject = reject; + this._workerCallbackResolve = resolve; + this._worker = new Worker(settings.static("worker_directory", "js/workers/") + "WorkerCodec.js"); + this._worker.onmessage = event => this.onWorkerMessage(event.data); + this._worker.onerror = (error) => reject("Failed to load worker (" + error.message + ")"); //TODO tr + }); + } +} +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["6233fb4b35a2d6fc524440f68ed7419bdafb5eae2edbf36a5a9cbdec1e836438"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["6233fb4b35a2d6fc524440f68ed7419bdafb5eae2edbf36a5a9cbdec1e836438"] = "6233fb4b35a2d6fc524440f68ed7419bdafb5eae2edbf36a5a9cbdec1e836438"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "TFD2Zvsi", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (65,29)" }, { name: "o1_kIuJm", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (84,25)" }, { name: "a9gYXNmN", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (107,45)" }, { name: "qiMXyXQE", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (121,39)" }, { name: "KzoM1Aru", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (128,35)" }, { name: "pzcd68lU", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (160,25)" }, { name: "ORQmYQxR", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (181,25)" }, { name: "ZnMmybHj", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (185,35)" }, { name: "H8Ljrp8b", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (195,25)" }, { name: "wNE6Yk8v", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (199,35)" }, { name: "yBTs793E", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (240,57)" }, { name: "ld0SEFgV", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (242,57)" }, { name: "H2m5xkNS", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (248,53)" }, { name: "G8shumQI", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (258,53)" }, { name: "wGPL0vDb", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (266,34)" }, { name: "yddBhUW8", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (297,31)" }, { name: "dQP_9bwx", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (320,53)" }, { name: "wiWY_KPc", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (325,53)" }, { name: "Oru0Sje5", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (333,51)" }, { name: "zwEFh23K", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (341,51)" }, { name: "FKmT074Q", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (355,51)" }, { name: "vTWtjrtn", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (365,35)" }, { name: "mP6ACPD5", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (380,31)" }, { name: "JApmNtuz", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (385,31)" }, { name: "DA87rt4L", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (389,31)" }, { name: "NcqTc0dn", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (405,56)" }, { name: "qeasUFNW", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (405,109)" }, { name: "dtUR49jo", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (418,56)" }, { name: "YFVVq1QK", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (418,101)" }, { name: "icEV8veV", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (429,56)" }, { name: "mui2Bvyn", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (429,127)" }, { name: "v33Oxo4X", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (443,30)" }, { name: "mzojB4K9", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (455,31)" }, { name: "ZF_a7vjl", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (461,31)" }, { name: "JOU61YqT", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (467,31)" }, { name: "c6E0QRE0", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (480,31)" }, { name: "HvOzEfon", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (508,35)" }, { name: "WjJ09uxh", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (512,35)" }, { name: "Wy_4Q6WO", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (538,31)" }, { name: "bVJCAzRK", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts (601,46)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +var connection; +(function (connection_3) { + class ServerConnectionCommandBoss extends connection_3.AbstractCommandHandlerBoss { + constructor(connection) { + super(connection); + } + } + connection_3.ServerConnectionCommandBoss = ServerConnectionCommandBoss; + class ConnectionCommandHandler extends connection_3.AbstractCommandHandler { + constructor(connection) { + super(connection); + this["error"] = this.handleCommandResult; + this["channellist"] = this.handleCommandChannelList; + this["channellistfinished"] = this.handleCommandChannelListFinished; + this["notifychannelcreated"] = this.handleCommandChannelCreate; + this["notifychanneldeleted"] = this.handleCommandChannelDelete; + this["notifychannelhide"] = this.handleCommandChannelHide; + this["notifychannelshow"] = this.handleCommandChannelShow; + this["notifycliententerview"] = this.handleCommandClientEnterView; + this["notifyclientleftview"] = this.handleCommandClientLeftView; + this["notifyclientmoved"] = this.handleNotifyClientMoved; + this["initserver"] = this.handleCommandServerInit; + this["notifychannelmoved"] = this.handleNotifyChannelMoved; + this["notifychanneledited"] = this.handleNotifyChannelEdited; + this["notifytextmessage"] = this.handleNotifyTextMessage; + this["notifyclientupdated"] = this.handleNotifyClientUpdated; + this["notifyserveredited"] = this.handleNotifyServerEdited; + this["notifyserverupdated"] = this.handleNotifyServerUpdated; + this["notifyclientpoke"] = this.handleNotifyClientPoke; + this["notifymusicplayerinfo"] = this.handleNotifyMusicPlayerInfo; + this["notifyservergroupclientadded"] = this.handleNotifyServerGroupClientAdd; + this["notifyservergroupclientdeleted"] = this.handleNotifyServerGroupClientRemove; + this["notifyclientchannelgroupchanged"] = this.handleNotifyClientChannelGroupChanged; + } + handle_command(command) { + if (this[command.command]) { + this[command.command](command.arguments); + return true; + } + return false; + } + set_handler(command, handler) { + this[command] = handler; + } + unset_handler(command, handler) { + if (handler && this[command] != handler) + return; + this[command] = undefined; + } + handleCommandResult(json) { + json = json[0]; //Only one bulk + let code = json["return_code"]; + if (code.length == 0) { + console.log(_translations.TFD2Zvsi || (_translations.TFD2Zvsi = tr("Invalid return code! (%o)")), json); + return; + } + let retListeners = this.connection["_retListener"]; + for (let e of retListeners) { + if (e.code != code) + continue; + retListeners.remove(e); + let result = new CommandResult(json); + if (result.success) + e.resolve(result); + else + e.reject(result); + break; + } + } + handleCommandServerInit(json) { + //We could setup the voice channel + console.log(_translations.o1_kIuJm || (_translations.o1_kIuJm = tr("Setting up voice"))); + this.connection.client.voiceConnection.createSession(); + json = json[0]; //Only one bulk + this.connection.client.clientId = parseInt(json["aclid"]); + this.connection.client.getClient().updateVariables({ key: "client_nickname", value: json["acn"] }); + let updates = []; + for (let key in json) { + if (key === "aclid") + continue; + if (key === "acn") + continue; + updates.push({ key: key, value: json[key] }); + } + this.connection.client.channelTree.server.updateVariables(false, ...updates); + chat.serverChat().name = this.connection.client.channelTree.server.properties["virtualserver_name"]; + chat.serverChat().appendMessage(_translations.a9gYXNmN || (_translations.a9gYXNmN = tr("Connected as {0}")), true, this.connection.client.getClient().createChatTag(true)); + sound.play(Sound.CONNECTION_CONNECTED); + globalClient.onConnected(); + } + createChannelFromJson(json, ignoreOrder = false) { + let tree = this.connection.client.channelTree; + let channel = new ChannelEntry(parseInt(json["cid"]), json["channel_name"], tree.findChannel(json["cpid"])); + tree.insertChannel(channel); + if (json["channel_order"] !== "0") { + let prev = tree.findChannel(json["channel_order"]); + if (!prev && json["channel_order"] != 0) { + if (!ignoreOrder) { + console.error(_translations.qiMXyXQE || (_translations.qiMXyXQE = tr("Invalid channel order id!"))); + return; + } + } + let parent = tree.findChannel(json["cpid"]); + if (!parent && json["cpid"] != 0) { + console.error(_translations.KzoM1Aru || (_translations.KzoM1Aru = tr("Invalid channel parent"))); + return; + } + tree.moveChannel(channel, prev, parent); //TODO test if channel exists! + } + if (ignoreOrder) { + for (let ch of tree.channels) { + if (ch.properties.channel_order == channel.channelId) { + tree.moveChannel(ch, channel, channel.parent); //Corrent the order :) + } + } + } + let updates = []; + for (let key in json) { + if (key === "cid") + continue; + if (key === "cpid") + continue; + if (key === "invokerid") + continue; + if (key === "invokername") + continue; + if (key === "invokeruid") + continue; + if (key === "reasonid") + continue; + updates.push({ key: key, value: json[key] }); + } + channel.updateVariables(...updates); + } + handleCommandChannelList(json) { + this.connection.client.channelTree.hide_channel_tree(); /* dont perform channel inserts on the dom to prevent style recalculations */ + console.log(_translations.pzcd68lU || (_translations.pzcd68lU = tr("Got %d new channels")), json.length); + for (let index = 0; index < json.length; index++) + this.createChannelFromJson(json[index], true); + } + handleCommandChannelListFinished(json) { + this.connection.client.channelTree.show_channel_tree(); + } + handleCommandChannelCreate(json) { + this.createChannelFromJson(json[0]); + } + handleCommandChannelShow(json) { + this.createChannelFromJson(json[0]); //TODO may chat? + } + handleCommandChannelDelete(json) { + let tree = this.connection.client.channelTree; + console.log(_translations.ORQmYQxR || (_translations.ORQmYQxR = tr("Got %d channel deletions")), json.length); + for (let index = 0; index < json.length; index++) { + let channel = tree.findChannel(json[index]["cid"]); + if (!channel) { + console.error(_translations.ZnMmybHj || (_translations.ZnMmybHj = tr("Invalid channel onDelete (Unknown channel)"))); + continue; + } + tree.deleteChannel(channel); + } + } + handleCommandChannelHide(json) { + let tree = this.connection.client.channelTree; + console.log(_translations.H8Ljrp8b || (_translations.H8Ljrp8b = tr("Got %d channel hides")), json.length); + for (let index = 0; index < json.length; index++) { + let channel = tree.findChannel(json[index]["cid"]); + if (!channel) { + console.error(_translations.wNE6Yk8v || (_translations.wNE6Yk8v = tr("Invalid channel on hide (Unknown channel)"))); + continue; + } + tree.deleteChannel(channel); + } + } + handleCommandClientEnterView(json) { + json = json[0]; //Only one bulk + let tree = this.connection.client.channelTree; + let client; + let channel = tree.findChannel(json["ctid"]); + let old_channel = tree.findChannel(json["cfid"]); + client = tree.findClient(json["clid"]); + if (!client) { + if (parseInt(json["client_type_exact"]) == ClientType.CLIENT_MUSIC) { + client = new MusicClientEntry(parseInt(json["clid"]), json["client_nickname"]); + } + else { + client = new ClientEntry(parseInt(json["clid"]), json["client_nickname"]); + } + client.properties.client_type = parseInt(json["client_type"]); + client = tree.insertClient(client, channel); + } + else { + if (client == this.connection.client.getClient()) + chat.channelChat().name = channel.channelName(); + tree.moveClient(client, channel); + } + if (this.connection.client.controlBar.query_visible || client.properties.client_type != ClientType.CLIENT_QUERY) { + const own_channel = this.connection.client.getClient().currentChannel(); + if (json["reasonid"] == ViewReasonId.VREASON_USER_ACTION) { + if (own_channel == channel) + if (old_channel) + sound.play(Sound.USER_ENTERED); + else + sound.play(Sound.USER_ENTERED_CONNECT); + if (old_channel) { + chat.serverChat().appendMessage(_translations.yBTs793E || (_translations.yBTs793E = tr("{0} appeared from {1} to {2}")), true, client.createChatTag(true), old_channel.generate_tag(true), channel.generate_tag(true)); + } + else { + chat.serverChat().appendMessage(_translations.ld0SEFgV || (_translations.ld0SEFgV = tr("{0} connected to channel {1}")), true, client.createChatTag(true), channel.generate_tag(true)); + } + } + else if (json["reasonid"] == ViewReasonId.VREASON_MOVED) { + if (own_channel == channel) + sound.play(Sound.USER_ENTERED_MOVED); + chat.serverChat().appendMessage(_translations.H2m5xkNS || (_translations.H2m5xkNS = tr("{0} appeared from {1} to {2}, moved by {3}")), true, client.createChatTag(true), old_channel ? old_channel.generate_tag(true) : undefined, channel.generate_tag(true), ClientEntry.chatTag(json["invokerid"], json["invokername"], json["invokeruid"])); + } + else if (json["reasonid"] == ViewReasonId.VREASON_CHANNEL_KICK) { + if (own_channel == channel) + sound.play(Sound.USER_ENTERED_KICKED); + chat.serverChat().appendMessage(_translations.G8shumQI || (_translations.G8shumQI = tr("{0} appeared from {1} to {2}, kicked by {3}{4}")), true, client.createChatTag(true), old_channel ? old_channel.generate_tag(true) : undefined, channel.generate_tag(true), ClientEntry.chatTag(json["invokerid"], json["invokername"], json["invokeruid"]), json["reasonmsg"] > 0 ? " (" + json["msg"] + ")" : ""); + } + else { + console.warn(_translations.wGPL0vDb || (_translations.wGPL0vDb = tr("Unknown reasonid for %o")), json["reasonid"]); + } + } + let updates = []; + for (let key in json) { + if (key == "cfid") + continue; + if (key == "ctid") + continue; + if (key === "invokerid") + continue; + if (key === "invokername") + continue; + if (key === "invokeruid") + continue; + if (key === "reasonid") + continue; + updates.push({ key: key, value: json[key] }); + } + client.updateVariables(...updates); + if (client instanceof LocalClientEntry) + this.connection.client.controlBar.updateVoice(); + } + handleCommandClientLeftView(json) { + json = json[0]; //Only one bulk + let tree = this.connection.client.channelTree; + let client = tree.findClient(json["clid"]); + if (!client) { + console.error(_translations.yddBhUW8 || (_translations.yddBhUW8 = tr("Unknown client left!"))); + return 0; + } + if (client == this.connection.client.getClient()) { + if (json["reasonid"] == ViewReasonId.VREASON_BAN) { + this.connection.client.handleDisconnect(DisconnectReason.CLIENT_BANNED, json); + } + else if (json["reasonid"] == ViewReasonId.VREASON_SERVER_KICK) { + this.connection.client.handleDisconnect(DisconnectReason.CLIENT_KICKED, json); + } + else if (json["reasonid"] == ViewReasonId.VREASON_SERVER_SHUTDOWN) { + this.connection.client.handleDisconnect(DisconnectReason.SERVER_CLOSED, json); + } + else if (json["reasonid"] == ViewReasonId.VREASON_SERVER_STOPPED) { + this.connection.client.handleDisconnect(DisconnectReason.SERVER_CLOSED, json); + } + else + this.connection.client.handleDisconnect(DisconnectReason.UNKNOWN, json); + return; + } + if (this.connection.client.controlBar.query_visible || client.properties.client_type != ClientType.CLIENT_QUERY) { + const own_channel = this.connection.client.getClient().currentChannel(); + let channel_from = tree.findChannel(json["cfid"]); + let channel_to = tree.findChannel(json["ctid"]); + if (json["reasonid"] == ViewReasonId.VREASON_USER_ACTION) { + chat.serverChat().appendMessage(_translations.dQP_9bwx || (_translations.dQP_9bwx = tr("{0} disappeared from {1} to {2}")), true, client.createChatTag(true), channel_from.generate_tag(true), channel_to.generate_tag(true)); + if (channel_from == own_channel) + sound.play(Sound.USER_LEFT); + } + else if (json["reasonid"] == ViewReasonId.VREASON_SERVER_LEFT) { + chat.serverChat().appendMessage(_translations.wiWY_KPc || (_translations.wiWY_KPc = tr("{0} left the server{1}")), true, client.createChatTag(true), json["reasonmsg"] ? " (" + json["reasonmsg"] + ")" : ""); + if (channel_from == own_channel) + sound.play(Sound.USER_LEFT_DISCONNECT); + } + else if (json["reasonid"] == ViewReasonId.VREASON_SERVER_KICK) { + chat.serverChat().appendError(_translations.Oru0Sje5 || (_translations.Oru0Sje5 = tr("{0} was kicked from the server by {1}.{2}")), client.createChatTag(true), ClientEntry.chatTag(json["invokerid"], json["invokername"], json["invokeruid"]), json["reasonmsg"] ? " (" + json["reasonmsg"] + ")" : ""); + if (channel_from == own_channel) + sound.play(Sound.USER_LEFT_KICKED_SERVER); + } + else if (json["reasonid"] == ViewReasonId.VREASON_CHANNEL_KICK) { + chat.serverChat().appendError(_translations.zwEFh23K || (_translations.zwEFh23K = tr("{0} was kicked from your channel by {1}.{2}")), client.createChatTag(true), ClientEntry.chatTag(json["invokerid"], json["invokername"], json["invokeruid"]), json["reasonmsg"] ? " (" + json["reasonmsg"] + ")" : ""); + if (channel_from == own_channel) + sound.play(Sound.USER_LEFT_KICKED_CHANNEL); + } + else if (json["reasonid"] == ViewReasonId.VREASON_BAN) { + //"Mulus" was banned for 1 second from the server by "WolverinDEV" (Sry brauchte kurz ein opfer :P <3 (Nohomo)) + let duration = "permanently"; + if (json["bantime"]) + duration = "for " + formatDate(Number.parseInt(json["bantime"])); + chat.serverChat().appendError(_translations.FKmT074Q || (_translations.FKmT074Q = tr("{0} was banned {1} by {2}.{3}")), client.createChatTag(true), duration, ClientEntry.chatTag(json["invokerid"], json["invokername"], json["invokeruid"]), json["reasonmsg"] ? " (" + json["reasonmsg"] + ")" : ""); + if (channel_from == own_channel) + sound.play(Sound.USER_LEFT_BANNED); + } + else { + console.error(_translations.vTWtjrtn || (_translations.vTWtjrtn = tr("Unknown client left reason!"))); + } + } + tree.deleteClient(client); + } + handleNotifyClientMoved(json) { + json = json[0]; //Only one bulk + let tree = this.connection.client.channelTree; + let client = tree.findClient(json["clid"]); + let channel_to = tree.findChannel(json["ctid"]); + let channel_from = tree.findChannel(json["cfid"]); + if (!client) { + console.error(_translations.mP6ACPD5 || (_translations.mP6ACPD5 = tr("Unknown client move (Client)!"))); + return 0; + } + if (!channel_to) { + console.error(_translations.JApmNtuz || (_translations.JApmNtuz = tr("Unknown client move (Channel to)!"))); + return 0; + } + if (!channel_from) //Not critical + console.error(_translations.DA87rt4L || (_translations.DA87rt4L = tr("Unknown client move (Channel from)!"))); + let self = client instanceof LocalClientEntry; + let current_clients; + if (self) { + chat.channelChat().name = channel_to.channelName(); + current_clients = client.channelTree.clientsByChannel(client.currentChannel()); + this.connection.client.controlBar.updateVoice(channel_to); + } + tree.moveClient(client, channel_to); + for (const entry of current_clients || []) + if (entry !== client) + entry.getAudioController().stopAudio(true); + const own_channel = this.connection.client.getClient().currentChannel(); + if (json["reasonid"] == ViewReasonId.VREASON_MOVED) { + chat.serverChat().appendMessage(self ? _translations.NcqTc0dn || (_translations.NcqTc0dn = tr("You was moved by {3} from channel {1} to {2}")) : _translations.qeasUFNW || (_translations.qeasUFNW = tr("{0} was moved from channel {1} to {2} by {3}")), true, client.createChatTag(true), channel_from ? channel_from.generate_tag(true) : undefined, channel_to.generate_tag(true), ClientEntry.chatTag(json["invokerid"], json["invokername"], json["invokeruid"])); + if (self) + sound.play(Sound.USER_MOVED_SELF); + else if (own_channel == channel_to) + sound.play(Sound.USER_ENTERED_MOVED); + else if (own_channel == channel_from) + sound.play(Sound.USER_LEFT_MOVED); + } + else if (json["reasonid"] == ViewReasonId.VREASON_USER_ACTION) { + chat.serverChat().appendMessage(self ? _translations.dtUR49jo || (_translations.dtUR49jo = tr("You switched from channel {1} to {2}")) : _translations.YFVVq1QK || (_translations.YFVVq1QK = tr("{0} switched from channel {1} to {2}")), true, client.createChatTag(true), channel_from ? channel_from.generate_tag(true) : undefined, channel_to.generate_tag(true)); + if (self) { } //If we do an action we wait for the error response + else if (own_channel == channel_to) + sound.play(Sound.USER_ENTERED); + else if (own_channel == channel_from) + sound.play(Sound.USER_LEFT); + } + else if (json["reasonid"] == ViewReasonId.VREASON_CHANNEL_KICK) { + chat.serverChat().appendMessage(self ? _translations.icEV8veV || (_translations.icEV8veV = tr("You got kicked out of the channel {1} to channel {2} by {3}{4}")) : _translations.mui2Bvyn || (_translations.mui2Bvyn = tr("{0} got kicked from channel {1} to {2} by {3}{4}")), true, client.createChatTag(true), channel_from ? channel_from.generate_tag(true) : undefined, channel_to.generate_tag(true), ClientEntry.chatTag(json["invokerid"], json["invokername"], json["invokeruid"]), json["reasonmsg"] ? " (" + json["reasonmsg"] + ")" : ""); + if (self) { + sound.play(Sound.CHANNEL_KICKED); + } + else if (own_channel == channel_to) + sound.play(Sound.USER_ENTERED_KICKED); + else if (own_channel == channel_from) + sound.play(Sound.USER_LEFT_KICKED_CHANNEL); + } + else { + console.warn(_translations.v33Oxo4X || (_translations.v33Oxo4X = tr("Unknown reason id %o")), json["reasonid"]); + } + } + handleNotifyChannelMoved(json) { + json = json[0]; //Only one bulk + for (let key in json) + console.log("Key: " + key + " Value: " + json[key]); + let tree = this.connection.client.channelTree; + let channel = tree.findChannel(json["cid"]); + if (!channel) { + console.error(_translations.mzojB4K9 || (_translations.mzojB4K9 = tr("Unknown channel move (Channel)!"))); + return 0; + } + let prev = tree.findChannel(json["order"]); + if (!prev && json["order"] != 0) { + console.error(_translations.ZF_a7vjl || (_translations.ZF_a7vjl = tr("Unknown channel move (prev)!"))); + return 0; + } + let parent = tree.findChannel(json["cpid"]); + if (!parent && json["cpid"] != 0) { + console.error(_translations.JOU61YqT || (_translations.JOU61YqT = tr("Unknown channel move (parent)!"))); + return 0; + } + tree.moveChannel(channel, prev, parent); + } + handleNotifyChannelEdited(json) { + json = json[0]; //Only one bulk + let tree = this.connection.client.channelTree; + let channel = tree.findChannel(json["cid"]); + if (!channel) { + console.error(_translations.c6E0QRE0 || (_translations.c6E0QRE0 = tr("Unknown channel edit (Channel)!"))); + return 0; + } + let updates = []; + for (let key in json) { + if (key === "cid") + continue; + if (key === "invokerid") + continue; + if (key === "invokername") + continue; + if (key === "invokeruid") + continue; + if (key === "reasonid") + continue; + updates.push({ key: key, value: json[key] }); + } + channel.updateVariables(...updates); + } + handleNotifyTextMessage(json) { + json = json[0]; //Only one bulk + //TODO chat format? + let mode = json["targetmode"]; + if (mode == 1) { + let invoker = this.connection.client.channelTree.findClient(json["invokerid"]); + let target = this.connection.client.channelTree.findClient(json["target"]); + if (!invoker) { //TODO spawn chat (Client is may invisible) + console.error(_translations.HvOzEfon || (_translations.HvOzEfon = tr("Got private message from invalid client!"))); + return; + } + if (!target) { //TODO spawn chat (Client is may invisible) + console.error(_translations.WjJ09uxh || (_translations.WjJ09uxh = tr("Got private message from invalid client!"))); + return; + } + if (invoker == this.connection.client.getClient()) { + sound.play(Sound.MESSAGE_SEND, { default_volume: .5 }); + target.chat(true).appendMessage("{0}: {1}", true, this.connection.client.getClient().createChatTag(true), MessageHelper.bbcode_chat(json["msg"])); + } + else { + sound.play(Sound.MESSAGE_RECEIVED, { default_volume: .5 }); + invoker.chat(true).appendMessage("{0}: {1}", true, ClientEntry.chatTag(json["invokerid"], json["invokername"], json["invokeruid"], true), MessageHelper.bbcode_chat(json["msg"])); + } + } + else if (mode == 2) { + if (json["invokerid"] == this.connection.client.clientId) + sound.play(Sound.MESSAGE_SEND, { default_volume: .5 }); + else + sound.play(Sound.MESSAGE_RECEIVED, { default_volume: .5 }); + chat.channelChat().appendMessage("{0}: {1}", true, ClientEntry.chatTag(json["invokerid"], json["invokername"], json["invokeruid"], true), MessageHelper.bbcode_chat(json["msg"])); + } + else if (mode == 3) { + chat.serverChat().appendMessage("{0}: {1}", true, ClientEntry.chatTag(json["invokerid"], json["invokername"], json["invokeruid"], true), MessageHelper.bbcode_chat(json["msg"])); + } + } + handleNotifyClientUpdated(json) { + json = json[0]; //Only one bulk + let client = this.connection.client.channelTree.findClient(json["clid"]); + if (!client) { + console.error(_translations.Wy_4Q6WO || (_translations.Wy_4Q6WO = tr("Tried to update an non existing client"))); + return; + } + let updates = []; + for (let key in json) { + if (key == "clid") + continue; + updates.push({ key: key, value: json[key] }); + } + client.updateVariables(...updates); + if (this.connection.client.selectInfo.currentSelected == client) + this.connection.client.selectInfo.update(); + } + handleNotifyServerEdited(json) { + json = json[0]; + let updates = []; + for (let key in json) { + if (key === "invokerid") + continue; + if (key === "invokername") + continue; + if (key === "invokeruid") + continue; + if (key === "reasonid") + continue; + updates.push({ key: key, value: json[key] }); + } + this.connection.client.channelTree.server.updateVariables(false, ...updates); + if (this.connection.client.selectInfo.currentSelected == this.connection.client.channelTree.server) + this.connection.client.selectInfo.update(); + } + handleNotifyServerUpdated(json) { + json = json[0]; + let updates = []; + for (let key in json) { + if (key === "invokerid") + continue; + if (key === "invokername") + continue; + if (key === "invokeruid") + continue; + if (key === "reasonid") + continue; + updates.push({ key: key, value: json[key] }); + } + this.connection.client.channelTree.server.updateVariables(true, ...updates); + let info = this.connection.client.selectInfo; + if (info.currentSelected instanceof ServerEntry) + info.update(); + } + handleNotifyMusicPlayerInfo(json) { + json = json[0]; + let bot = this.connection.client.channelTree.find_client_by_dbid(json["bot_id"]); + if (!bot || !(bot instanceof MusicClientEntry)) { + log.warn(LogCategory.CLIENT, _translations.bVJCAzRK || (_translations.bVJCAzRK = tr("Got music player info for unknown or invalid bot! (ID: %i, Entry: %o)")), json["bot_id"], bot); + return; + } + bot.handlePlayerInfo(json); + } + handleNotifyClientPoke(json) { + json = json[0]; + Modals.spawnPoke({ + id: parseInt(json["invokerid"]), + name: json["invokername"], + unique_id: json["invokeruid"] + }, json["msg"]); + sound.play(Sound.USER_POKED_SELF); + } + //TODO server chat message + handleNotifyServerGroupClientAdd(json) { + json = json[0]; + const self = this.connection.client.getClient(); + if (json["clid"] == self.clientId()) + sound.play(Sound.GROUP_SERVER_ASSIGNED_SELF); + } + //TODO server chat message + handleNotifyServerGroupClientRemove(json) { + json = json[0]; + const self = this.connection.client.getClient(); + if (json["clid"] == self.clientId()) { + sound.play(Sound.GROUP_SERVER_REVOKED_SELF); + } + else { + } + } + //TODO server chat message + handleNotifyClientChannelGroupChanged(json) { + json = json[0]; + const self = this.connection.client.getClient(); + if (json["clid"] == self.clientId()) { + sound.play(Sound.GROUP_CHANNEL_CHANGED_SELF); + } + } + } + connection_3.ConnectionCommandHandler = ConnectionCommandHandler; +})(connection || (connection = {})); +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["2d8c483dec3a421dac4e03bac009ca3c2324d36b3e3cfa6e28d50456f043f9df"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["2d8c483dec3a421dac4e03bac009ca3c2324d36b3e3cfa6e28d50456f043f9df"] = "2d8c483dec3a421dac4e03bac009ca3c2324d36b3e3cfa6e28d50456f043f9df"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "kQ6oVqzx", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHelper.ts (141,67)" }, { name: "UD2e8fqR", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHelper.ts (173,63)" }, { name: "GA8yGY40", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHelper.ts (192,67)" }, { name: "YAugHF1M", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHelper.ts (222,63)" }, { name: "VQ3mQXnH", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/CommandHelper.ts (243,63)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +var connection; +(function (connection_4) { + class CommandHelper extends connection_4.AbstractCommandHandler { + constructor(connection) { + super(connection); + this._callbacks_namefromuid = []; + this.volatile_handler_boss = false; + this.ignore_consumed = true; + } + initialize() { + this.connection.command_handler_boss().register_handler(this); + /* notifyquerylist */ + } + handle_command(command) { + if (command.command == "notifyclientnamefromuid") + this.handle_notifyclientnamefromuid(command.arguments); + else + return false; + return true; + } + joinChannel(channel, password) { + return this.connection.send_command("clientmove", { + "clid": this.connection.client.getClientId(), + "cid": channel.getChannelId(), + "cpw": password || "" + }); + } + sendMessage(message, type, target) { + if (type == ChatType.SERVER) + return this.connection.send_command("sendtextmessage", { "targetmode": 3, "target": 0, "msg": message }); + else if (type == ChatType.CHANNEL) + return this.connection.send_command("sendtextmessage", { "targetmode": 2, "target": target.getChannelId(), "msg": message }); + else if (type == ChatType.CLIENT) + return this.connection.send_command("sendtextmessage", { "targetmode": 1, "target": target.clientId(), "msg": message }); + } + updateClient(key, value) { + let data = {}; + data[key] = value; + return this.connection.send_command("clientupdate", data); + } + info_from_uid(...uid) { + let uids = [...uid]; + for (let p of this._callbacks_namefromuid) + if (p.keys == uids) + return p.promise; + let req = {}; + req.keys = uids; + req.response = new Array(uids.length); + req.promise = new LaterPromise(); + for (let uid of uids) { + this.connection.send_command("clientgetnamefromuid", { + cluid: uid + }).catch(req.promise.function_rejected()); + } + this._callbacks_namefromuid.push(req); + return req.promise; + } + request_query_list(server_id = undefined) { + return new Promise((resolve, reject) => { + const single_handler = { + command: "notifyquerylist", + function: command => { + const json = command.arguments; + const result = {}; + result.flag_all = json[0]["flag_all"]; + result.flag_own = json[0]["flag_own"]; + result.queries = []; + for (const entry of json) { + const rentry = {}; + rentry.bounded_server = entry["client_bounded_server"]; + rentry.username = entry["client_login_name"]; + rentry.unique_id = entry["client_unique_identifier"]; + result.queries.push(rentry); + } + resolve(result); + return true; + } + }; + this.handler_boss.register_single_handler(single_handler); + let data = {}; + if (server_id !== undefined) + data["server_id"] = server_id; + this.connection.send_command("querylist", data).catch(error => { + this.handler_boss.remove_single_handler(single_handler); + if (error instanceof CommandResult) { + if (error.id == ErrorID.EMPTY_RESULT) { + resolve(undefined); + return; + } + } + reject(error); + }); + }); + } + request_playlist_list() { + return new Promise((resolve, reject) => { + const single_handler = { + command: "notifyplaylistlist", + function: command => { + const json = command.arguments; + const result = []; + for (const entry of json) { + try { + result.push({ + playlist_id: parseInt(entry["playlist_id"]), + playlist_bot_id: parseInt(entry["playlist_bot_id"]), + playlist_title: entry["playlist_title"], + playlist_type: parseInt(entry["playlist_type"]), + playlist_owner_dbid: parseInt(entry["playlist_owner_dbid"]), + playlist_owner_name: entry["playlist_owner_name"], + needed_power_modify: parseInt(entry["needed_power_modify"]), + needed_power_permission_modify: parseInt(entry["needed_power_permission_modify"]), + needed_power_delete: parseInt(entry["needed_power_delete"]), + needed_power_song_add: parseInt(entry["needed_power_song_add"]), + needed_power_song_move: parseInt(entry["needed_power_song_move"]), + needed_power_song_remove: parseInt(entry["needed_power_song_remove"]) + }); + } + catch (error) { + log.error(LogCategory.NETWORKING, _translations.kQ6oVqzx || (_translations.kQ6oVqzx = tr("Failed to parse playlist entry: %o")), error); + } + } + resolve(result); + return true; + } + }; + this.handler_boss.register_single_handler(single_handler); + this.connection.send_command("playlistlist").catch(error => { + this.handler_boss.remove_single_handler(single_handler); + if (error instanceof CommandResult) { + if (error.id == ErrorID.EMPTY_RESULT) { + resolve([]); + return; + } + } + reject(error); + }); + }); + } + request_playlist_songs(playlist_id) { + return new Promise((resolve, reject) => { + const single_handler = { + command: "notifyplaylistsonglist", + function: command => { + const json = command.arguments; + if (json[0]["playlist_id"] != playlist_id) { + log.error(LogCategory.NETWORKING, _translations.UD2e8fqR || (_translations.UD2e8fqR = tr("Received invalid notification for playlist songs"))); + return false; + } + const result = []; + for (const entry of json) { + try { + result.push({ + song_id: parseInt(entry["song_id"]), + song_invoker: entry["song_invoker"], + song_previous_song_id: parseInt(entry["song_previous_song_id"]), + song_url: entry["song_url"], + song_url_loader: entry["song_url_loader"], + song_loaded: entry["song_loaded"] == true || entry["song_loaded"] == "1", + song_metadata: entry["song_metadata"] + }); + } + catch (error) { + log.error(LogCategory.NETWORKING, _translations.GA8yGY40 || (_translations.GA8yGY40 = tr("Failed to parse playlist song entry: %o")), error); + } + } + resolve(result); + return true; + } + }; + this.handler_boss.register_single_handler(single_handler); + this.connection.send_command("playlistsonglist", { playlist_id: playlist_id }).catch(error => { + this.handler_boss.remove_single_handler(single_handler); + if (error instanceof CommandResult) { + if (error.id == ErrorID.EMPTY_RESULT) { + resolve([]); + return; + } + } + reject(error); + }); + }); + } + request_playlist_info(playlist_id) { + return new Promise((resolve, reject) => { + const single_handler = { + command: "notifyplaylistinfo", + function: command => { + const json = command.arguments[0]; + if (json["playlist_id"] != playlist_id) { + log.error(LogCategory.NETWORKING, _translations.YAugHF1M || (_translations.YAugHF1M = tr("Received invalid notification for playlist info"))); + return; + } + try { + //resolve + resolve({ + playlist_id: parseInt(json["playlist_id"]), + playlist_title: json["playlist_title"], + playlist_description: json["playlist_description"], + playlist_type: parseInt(json["playlist_type"]), + playlist_owner_dbid: parseInt(json["playlist_owner_dbid"]), + playlist_owner_name: json["playlist_owner_name"], + playlist_flag_delete_played: json["playlist_flag_delete_played"] == true || json["playlist_flag_delete_played"] == "1", + playlist_flag_finished: json["playlist_flag_finished"] == true || json["playlist_flag_finished"] == "1", + playlist_replay_mode: parseInt(json["playlist_replay_mode"]), + playlist_current_song_id: parseInt(json["playlist_current_song_id"]), + }); + } + catch (error) { + log.error(LogCategory.NETWORKING, _translations.VQ3mQXnH || (_translations.VQ3mQXnH = tr("Failed to parse playlist info: %o")), error); + reject("failed to parse info"); + } + return true; + } + }; + this.handler_boss.register_single_handler(single_handler); + this.connection.send_command("playlistinfo", { playlist_id: playlist_id }).catch(error => { + this.handler_boss.remove_single_handler(single_handler); + reject(error); + }); + }); + } + /** + * @deprecated + * Its just a workaround for the query management. + * There is no garante that the whoami trick will work forever + */ + current_virtual_server_id() { + if (this._who_am_i) + return Promise.resolve(parseInt(this._who_am_i["virtualserver_id"])); + return new Promise((resolve, reject) => { + const single_handler = { + function: command => { + if (command.command != "") + return false; + this._who_am_i = command.arguments[0]; + resolve(parseInt(this._who_am_i["virtualserver_id"])); + return true; + } + }; + this.handler_boss.register_single_handler(single_handler); + this.connection.send_command("whoami").catch(error => { + this.handler_boss.remove_single_handler(single_handler); + reject(error); + }); + }); + } + handle_notifyclientnamefromuid(json) { + for (let entry of json) { + let info = {}; + info.client_unique_id = entry["cluid"]; + info.client_nickname = entry["clname"]; + info.client_database_id = parseInt(entry["cldbid"]); + for (let elm of this._callbacks_namefromuid.slice(0)) { + let unset = 0; + for (let index = 0; index < elm.keys.length; index++) { + if (elm.keys[index] == info.client_unique_id) { + elm.response[index] = info; + } + if (elm.response[index] == undefined) + unset++; + } + if (unset == 0) { + this._callbacks_namefromuid.remove(elm); + elm.promise.resolved(elm.response); + } + } + } + } + } + connection_4.CommandHelper = CommandHelper; +})(connection || (connection = {})); +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["e2e8defd9f6e149e9be9fc5c1a7241df7e196dd487817e50265229048abf6e85"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["e2e8defd9f6e149e9be9fc5c1a7241df7e196dd487817e50265229048abf6e85"] = "e2e8defd9f6e149e9be9fc5c1a7241df7e196dd487817e50265229048abf6e85"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "CJwFvFn2", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/HandshakeHandler.ts (57,39)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +var connection; +(function (connection) { + class HandshakeHandler { + constructor(profile, name, password) { + this.failed = false; + this.profile = profile; + this.server_password = password; + this.name = name; + } + setConnection(con) { + this.connection = con; + } + startHandshake() { + this.handshake_handler = this.profile.spawn_identity_handshake_handler(this.connection); + if (!this.handshake_handler) { + this.handshake_failed("failed to create identity handler"); + return; + } + this.handshake_handler.register_callback((flag, message) => { + if (flag) + this.handshake_finished(); + else + this.handshake_failed(message); + }); + this.handshake_handler.start_handshake(); + } + handshake_failed(message) { + if (this.failed) + return; + this.failed = true; + this.connection.client.handleDisconnect(DisconnectReason.HANDSHAKE_FAILED, message); + } + handshake_finished(version) { + if (native_client && window["native"] && native.client_version && !version) { + native.client_version() + .then(this.handshake_finished.bind(this)) + .catch(error => { + console.error(_translations.CJwFvFn2 || (_translations.CJwFvFn2 = tr("Failed to get version:"))); + console.error(error); + this.handshake_finished("?.?.?"); + }); + return; + } + const git_version = settings.static_global("version", "unknown"); + const browser_name = (navigator.browserSpecs || {})["name"] || " "; + let data = { + //TODO variables! + client_nickname: this.name, + client_platform: (browser_name ? browser_name + " " : "") + navigator.platform, + client_version: "TeaWeb " + git_version + " (" + navigator.userAgent + ")", + client_server_password: this.server_password, + client_browser_engine: navigator.product + }; + if (version) { + data.client_version = "TeaClient "; + data.client_version += " " + version; + const os = require("os"); + const arch_mapping = { + "x32": "32bit", + "x64": "64bit" + }; + data.client_version += " " + (arch_mapping[os.arch()] || os.arch()); + const os_mapping = { + "win32": "Windows", + "linux": "Linux" + }; + data.client_platform = (os_mapping[os.platform()] || os.platform()); + } + this.connection.send_command("clientinit", data).catch(error => { + this.connection.disconnect(); + if (error instanceof CommandResult) { + if (error.id == 1028) { + this.connection.client.handleDisconnect(DisconnectReason.SERVER_REQUIRES_PASSWORD); + } + else { + this.connection.client.handleDisconnect(DisconnectReason.CLIENT_KICKED, error); + } + } + }); + } + } + connection.HandshakeHandler = HandshakeHandler; +})(connection || (connection = {})); +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["1b9ed7673e14dd8de7643659af5c37ce4645985797c33e3983c5ffa25edd9f06"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["1b9ed7673e14dd8de7643659af5c37ce4645985797c33e3983c5ffa25edd9f06"] = "1b9ed7673e14dd8de7643659af5c37ce4645985797c33e3983c5ffa25edd9f06"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "XIh9afcf", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/ServerConnection.ts (66,25)" }, { name: "fPGOWwqS", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/ServerConnection.ts (67,45)" }, { name: "fiJGXlYF", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/ServerConnection.ts (84,35)" }, { name: "BPotoUYu", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/ServerConnection.ts (93,45)" }, { name: "aUBpWo3n", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/ServerConnection.ts (101,33)" }, { name: "wsab4Jcl", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/ServerConnection.ts (105,58)" }, { name: "JKog4HLT", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/ServerConnection.ts (137,33)" }, { name: "rFu5r2U1", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/ServerConnection.ts (150,54)" }, { name: "I3PKHBHP", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/ServerConnection.ts (172,49)" }, { name: "X9OVEeHc", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/ServerConnection.ts (175,31)" }, { name: "ipPP5zUT", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/ServerConnection.ts (187,35)" }, { name: "fokLKoGU", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/ServerConnection.ts (192,33)" }, { name: "imXS9kEs", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/ServerConnection.ts (196,86)" }, { name: "sPbDX5nM", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/ServerConnection.ts (197,31)" }, { name: "oZM5phD0", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/ServerConnection.ts (198,52)" }, { name: "FcNk8Ozi", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/ServerConnection.ts (207,33)" }, { name: "JnGgKqKA", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/ServerConnection.ts (210,50)" }, { name: "mU5d8pLA", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/ServerConnection.ts (216,50)" }, { name: "Hhxp4jDK", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/ServerConnection.ts (235,30)" }, { name: "pSyJGvv3", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/ServerConnection.ts (275,51)" }, { name: "t9MJiTw7", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/ServerConnection.ts (276,67)" }, { name: "pyddVpEH", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/ServerConnection.ts (283,59)" }, { name: "xQuEHP07", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/connection/ServerConnection.ts (285,43)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +var ErrorID; +(function (ErrorID) { + ErrorID[ErrorID["PERMISSION_ERROR"] = 2568] = "PERMISSION_ERROR"; + ErrorID[ErrorID["EMPTY_RESULT"] = 1281] = "EMPTY_RESULT"; + ErrorID[ErrorID["PLAYLIST_IS_IN_USE"] = 8451] = "PLAYLIST_IS_IN_USE"; +})(ErrorID || (ErrorID = {})); +class CommandResult { + constructor(json) { + this.json = json; + this.id = json["id"]; + this.message = json["msg"]; + this.extra_message = ""; + if (json["extra_msg"]) + this.extra_message = json["extra_msg"]; + this.success = this.id == 0; + } +} +class ReturnListener { +} +var connection; +(function (connection) { + class ServerConnection extends connection.AbstractServerConnection { + constructor(client) { + super(client); + this._connectionState = ConnectionState.UNCONNECTED; + this._connect_timeout_timer = undefined; + this._connected = false; + this.on_connect = () => { + console.log(_translations.XIh9afcf || (_translations.XIh9afcf = tr("Socket connected"))); + chat.serverChat().appendMessage(_translations.fPGOWwqS || (_translations.fPGOWwqS = tr("Logging in..."))); + this._handshakeHandler.startHandshake(); + }; + this._socket = null; + this._retCodeIdx = 0; + this._retListener = []; + this._command_boss = new connection.ServerConnectionCommandBoss(this); + this._command_handler_default = new connection.ConnectionCommandHandler(this); + this._command_boss.register_handler(this._command_handler_default); + this.command_helper.initialize(); + } + generateReturnCode() { + return (this._retCodeIdx++).toString(); + } + connect(address, handshake, timeout) { + return __awaiter(this, void 0, void 0, function* () { + timeout = typeof (timeout) === "number" ? timeout : 0; + if (this._connect_timeout_timer) { + clearTimeout(this._connect_timeout_timer); + this._connect_timeout_timer = null; + try { + yield this.disconnect(); + } + catch (error) { + console.error(_translations.fiJGXlYF || (_translations.fiJGXlYF = tr("Failed to close old connection properly. Error: %o")), error); + throw "failed to cleanup old connection"; + } + } + this.updateConnectionState(ConnectionState.CONNECTING); + this._remote_address = address; + this._handshakeHandler = handshake; + this._handshakeHandler.setConnection(this); + this._connected = false; + chat.serverChat().appendMessage(_translations.BPotoUYu || (_translations.BPotoUYu = tr("Connecting to {0}:{1}")), true, address.host, address.port); + const self = this; + try { + let local_socket; + let local_timeout_timer; + local_timeout_timer = setTimeout(() => __awaiter(this, void 0, void 0, function* () { + console.log(_translations.aUBpWo3n || (_translations.aUBpWo3n = tr("Connect timeout triggered!"))); + try { + yield this.disconnect(); + } + catch (error) { + log.warn(LogCategory.NETWORKING, _translations.wsab4Jcl || (_translations.wsab4Jcl = tr("Failed to close connection after timeout had been triggered! (%o)")), error); + } + this.client.handleDisconnect(DisconnectReason.CONNECT_FAILURE); + }), timeout); + this._connect_timeout_timer = local_timeout_timer; + this._socket = (local_socket = new WebSocket('wss://' + address.host + ":" + address.port)); /* this may hangs */ + clearTimeout(local_timeout_timer); + if (this._connect_timeout_timer == local_timeout_timer) + this._connect_timeout_timer = undefined; + if (this._socket != local_socket) + return; /* something had changed and we dont use this connection anymore! */ + local_socket.onopen = () => { + if (this._socket != local_socket) + return; /* this socket isn't from interest anymore */ + this._connected = true; + this.on_connect(); + }; + local_socket.onclose = event => { + if (this._socket != local_socket) + return; /* this socket isn't from interest anymore */ + this.client.handleDisconnect(this._connected ? DisconnectReason.CONNECTION_CLOSED : DisconnectReason.CONNECT_FAILURE, { + code: event.code, + reason: event.reason, + event: event + }); + }; + local_socket.onerror = e => { + if (this._socket != local_socket) + return; /* this socket isn't from interest anymore */ + console.log(_translations.JKog4HLT || (_translations.JKog4HLT = tr("Received web socket error: (%o)")), e); + }; + local_socket.onmessage = msg => { + if (this._socket != local_socket) + return; /* this socket isn't from interest anymore */ + self.handle_socket_message(msg.data); + }; + this.updateConnectionState(ConnectionState.INITIALISING); + } + catch (e) { + try { + yield this.disconnect(); + } + catch (error) { + log.warn(LogCategory.NETWORKING, _translations.rFu5r2U1 || (_translations.rFu5r2U1 = tr("Failed to close connection after connect attempt failed (%o)")), error); + } + this.client.handleDisconnect(DisconnectReason.CONNECT_FAILURE, e); + } + }); + } + updateConnectionState(state) { + this._connectionState = state; + this.client.controlBar.update_connection_state(); + } + disconnect(reason) { + return __awaiter(this, void 0, void 0, function* () { + if (typeof (reason) === "string") { + //TODO send disconnect reason + } + if (this._connectionState == ConnectionState.UNCONNECTED) + return; + this.updateConnectionState(ConnectionState.UNCONNECTED); + if (this._socket) + this._socket.close(3000 + 0xFF, _translations.I3PKHBHP || (_translations.I3PKHBHP = tr("request disconnect"))); + this._socket = null; + for (let future of this._retListener) + future.reject(_translations.X9OVEeHc || (_translations.X9OVEeHc = tr("Connection closed"))); + this._retListener = []; + this._retCodeIdx = 0; + this._connected = false; + }); + } + handle_socket_message(data) { + if (typeof (data) === "string") { + let json; + try { + json = JSON.parse(data); + } + catch (e) { + console.error(_translations.ipPP5zUT || (_translations.ipPP5zUT = tr("Could not parse message json!"))); + alert(e); // error in the above string (in this case, yes)! + return; + } + if (json["type"] === undefined) { + console.log(_translations.fokLKoGU || (_translations.fokLKoGU = tr("Missing data type!"))); + return; + } + if (json["type"] === "command") { + let group = log.group(log.LogType.DEBUG, LogCategory.NETWORKING, _translations.imXS9kEs || (_translations.imXS9kEs = tr("Handling command '%s'")), json["command"]); + group.log(_translations.sPbDX5nM || (_translations.sPbDX5nM = tr("Handling command '%s'")), json["command"]); + group.group(log.LogType.TRACE, _translations.oZM5phD0 || (_translations.oZM5phD0 = tr("Json:"))).collapsed(true).log("%o", json).end(); + this._command_boss.invoke_handle({ + command: json["command"], + arguments: json["data"] + }); + group.end(); + } + else if (json["type"] === "WebRTC") + this.client.voiceConnection.handleControlPacket(json); + else { + console.log(_translations.FcNk8Ozi || (_translations.FcNk8Ozi = tr("Unknown command type %o")), json["type"]); + } + } + else { + log.warn(LogCategory.NETWORKING, _translations.JnGgKqKA || (_translations.JnGgKqKA = tr("Received unknown message of type %s. Dropping message")), typeof (data)); + } + } + sendData(data) { + if (!this._socket || this._socket.readyState != 1) { + log.warn(LogCategory.NETWORKING, _translations.mU5d8pLA || (_translations.mU5d8pLA = tr("Tried to send on a invalid socket (%s)")), this._socket ? "invalid state (" + this._socket.readyState + ")" : "invalid socket"); + return; + } + this._socket.send(data); + } + commandiefy(input) { + return JSON.stringify(input, (key, value) => { + switch (typeof value) { + case "boolean": return value == true ? "1" : "0"; + case "function": return value(); + default: + return value; + } + }); + } + send_command(command, data, _options) { + if (!this._socket || !this.connected()) { + console.warn(_translations.Hhxp4jDK || (_translations.Hhxp4jDK = tr("Tried to send a command without a valid connection."))); + return; + } + const options = {}; + Object.assign(options, connection.CommandOptionDefaults); + Object.assign(options, _options); + data = $.isArray(data) ? data : [data || {}]; + const _this = this; + let result = new Promise((resolve, failed) => { + let _data = $.isArray(data) ? data : [data]; + let retCode = _data[0]["return_code"] !== undefined ? _data[0].return_code : _this.generateReturnCode(); + _data[0].return_code = retCode; + let listener = new ReturnListener(); + listener.resolve = resolve; + listener.reject = failed; + listener.code = retCode; + listener.timeout = setTimeout(() => { + _this._retListener.remove(listener); + listener.reject("timeout"); + }, 1500); + this._retListener.push(listener); + this._socket.send(this.commandiefy({ + "type": "command", + "command": command, + "data": _data, + "flags": options.flagset.filter(entry => entry.length != 0) + })); + }); + return new Promise((resolve, failed) => { + result.then(resolve).catch(ex => { + if (options.process_result) { + if (ex instanceof CommandResult) { + let res = ex; + if (!res.success) { + if (res.id == 2568) { //Permission error + res.message = (_translations.pSyJGvv3 || (_translations.pSyJGvv3 = tr("Insufficient client permissions. Failed on permission "))) + this.client.permissions.resolveInfo(res.json["failed_permid"]).name; + chat.serverChat().appendError(_translations.t9MJiTw7 || (_translations.t9MJiTw7 = tr("Insufficient client permissions. Failed on permission {}")), this.client.permissions.resolveInfo(res.json["failed_permid"]).name); + sound.play(Sound.ERROR_INSUFFICIENT_PERMISSIONS); + } + else { + chat.serverChat().appendError(res.extra_message.length == 0 ? res.message : res.extra_message); + } + } + } + else if (typeof (ex) === "string") { + chat.serverChat().appendError((_translations.pyddVpEH || (_translations.pyddVpEH = tr("Command execution results in "))) + ex); + } + else { + console.error(_translations.xQuEHP07 || (_translations.xQuEHP07 = tr("Invalid promise result type: %o. Result:")), typeof (ex)); + console.error(ex); + } + } + failed(ex); + }); + }); + } + connected() { + return this._socket && this._socket.readyState == WebSocket.OPEN; + } + support_voice() { + return false; + } + voice_connection() { + return undefined; + } + command_handler_boss() { + return this._command_boss; + } + } + connection.ServerConnection = ServerConnection; +})(connection || (connection = {})); +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["f2cb5cb5e81993856f75ec86d34cbd93c355ed6cf975364a656f0337431d38c1"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["f2cb5cb5e81993856f75ec86d34cbd93c355ed6cf975364a656f0337431d38c1"] = "f2cb5cb5e81993856f75ec86d34cbd93c355ed6cf975364a656f0337431d38c1"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of []) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +// ASN.1 JavaScript decoder +// Copyright (c) 2008-2018 Lapo Luchini +// Copyright (c) 2019-2019 Markus Hadenfeldt +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +var asn1; +(function (asn1) { + const ellipsis = "\u2026"; + function string_cut(str, len) { + if (str.length > len) + str = str.substring(0, len) + ellipsis; + return str; + } + class Stream { + constructor(data, position) { + if (data instanceof Stream) + this.data = data.data; + else + this.data = data; + this.position = position; + } + length() { + if (this.data instanceof ArrayBuffer) + return this.data.byteLength; + return this.data.length; + } + get(position) { + if (position === undefined) + position = this.position++; + if (position >= this.length()) + throw 'Requesting byte offset ' + this.position + ' on a stream of length ' + this.length(); + return (typeof (this.data) === "string") ? this.data.charCodeAt(position) : this.data[position]; + } + hexByte(byte) { + return Stream.HEX_DIGITS.charAt((byte >> 4) & 0xF) + Stream.HEX_DIGITS.charAt(byte & 0xF); + } + parseStringISO(start, end) { + let s = ""; + for (let i = start; i < end; ++i) + s += String.fromCharCode(this.get(i)); + return s; + } + parseStringUTF(start, end) { + let s = ""; + for (let i = start; i < end;) { + let c = this.get(i++); + if (c < 128) + s += String.fromCharCode(c); + else if ((c > 191) && (c < 224)) + s += String.fromCharCode(((c & 0x1F) << 6) | (this.get(i++) & 0x3F)); + else + s += String.fromCharCode(((c & 0x0F) << 12) | ((this.get(i++) & 0x3F) << 6) | (this.get(i++) & 0x3F)); + } + return s; + } + parseStringBMP(start, end) { + let str = "", hi, lo; + for (let i = start; i < end;) { + hi = this.get(i++); + lo = this.get(i++); + str += String.fromCharCode((hi << 8) | lo); + } + return str; + } + parseTime(start, end, shortYear) { + let s = this.parseStringISO(start, end), m = (shortYear ? Stream.reTimeS : Stream.reTimeL).exec(s); + if (!m) + return "Unrecognized time: " + s; + if (shortYear) { + // to avoid querying the timer, use the fixed range [1970, 2069] + // it will conform with ITU X.400 [-10, +40] sliding window until 2030 + //m[1] = +m[1]; + //m[1] += (parseInt(m[1]) < 70) ? 2000 : 1900; + throw "fixme!"; + } + s = m[1] + "-" + m[2] + "-" + m[3] + " " + m[4]; + if (m[5]) { + s += ":" + m[5]; + if (m[6]) { + s += ":" + m[6]; + if (m[7]) + s += "." + m[7]; + } + } + if (m[8]) { + s += " UTC"; + if (m[8] != 'Z') { + s += m[8]; + if (m[9]) + s += ":" + m[9]; + } + } + return s; + } + ; + parseInteger(start, end) { + let current = this.get(start); + let negative = (current > 127); + let padding = negative ? 255 : 0; + let length; + let descriptor; + // skip unuseful bits (not allowed in DER) + while (current == padding && ++start < end) + current = this.get(start); + length = end - start; + if (length === 0) + return negative ? '-1' : '0'; + // show bit length of huge integers + if (length > 4) { + descriptor = current; + length <<= 3; /* calculate bit length */ + while (((descriptor ^ padding) & 0x80) == 0) { + descriptor <<= 1; + --length; + } + descriptor = "(" + length + " bit)\n"; + } + // decode the integer + if (negative) + current = current - 256; + let number = ""; + if (typeof (Int10) !== "undefined") { + let n = new Int10(current); + for (let i = start + 1; i < end; ++i) + n.mulAdd(256, this.get(i)); + number = n.toString(); + } + else { + let n = 0; + for (let i = start + 1; i < end; ++i) { + n <<= 8; + n += this.get(i); + } + number = n.toString(); + } + return descriptor + number; + } + ; + isASCII(start, end) { + for (let i = start; i < end; ++i) { + const c = this.get(i); + if (c < 32 || c > 176) + return false; + } + return true; + } + ; + parseBitString(start, end, maxLength) { + let unusedBit = this.get(start), lenBit = ((end - start - 1) << 3) - unusedBit, intro = "(" + lenBit + " bit)\n", s = ""; + for (let i = start + 1; i < end; ++i) { + let b = this.get(i), skip = (i == end - 1) ? unusedBit : 0; + for (let j = 7; j >= skip; --j) + s += (b >> j) & 1 ? "1" : "0"; + if (s.length > maxLength) + return intro + string_cut(s, maxLength); + } + return intro + s; + } + ; + parseOctetString(start, end, maxLength) { + if (this.isASCII(start, end)) + return string_cut(this.parseStringISO(start, end), maxLength); + let len = end - start, s = "(" + len + " byte)\n"; + maxLength /= 2; // we work in bytes + if (len > maxLength) + end = start + maxLength; + for (let i = start; i < end; ++i) + s += this.hexByte(this.get(i)); + if (len > maxLength) + s += ellipsis; + return s; + } + ; + parseOID(start, end, maxLength) { + let s = '', n = new Int10(), bits = 0; + for (let i = start; i < end; ++i) { + let v = this.get(i); + n.mulAdd(128, v & 0x7F); + bits += 7; + if (!(v & 0x80)) { // finished + if (s === '') { + n = n.simplify(); + if (n instanceof Int10) { + n.sub(80); + s = "2." + n.toString(); + } + else { + let m = n < 80 ? n < 40 ? 0 : 1 : 2; + s = m + "." + (n - m * 40); + } + } + else + s += "." + n.toString(); + if (s.length > maxLength) + return string_cut(s, maxLength); + n = new Int10(); + bits = 0; + } + } + if (bits > 0) + s += ".incomplete"; + /* FIXME + if (typeof oids === 'object') { + let oid = oids[s]; + if (oid) { + if (oid.d) s += "\n" + oid.d; + if (oid.c) s += "\n" + oid.c; + if (oid.w) s += "\n(warning!)"; + } + } + */ + return s; + } + ; + } + Stream.HEX_DIGITS = "0123456789ABCDEF"; + Stream.reTimeS = /^(\d\d)(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])([01]\d|2[0-3])(?:([0-5]\d)(?:([0-5]\d)(?:[.,](\d{1,3}))?)?)?(Z|[-+](?:[0]\d|1[0-2])([0-5]\d)?)?$/; + Stream.reTimeL = /^(\d\d\d\d)(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])([01]\d|2[0-3])(?:([0-5]\d)(?:([0-5]\d)(?:[.,](\d{1,3}))?)?)?(Z|[-+](?:[0]\d|1[0-2])([0-5]\d)?)?$/; + asn1.Stream = Stream; + let TagClass; + (function (TagClass) { + TagClass[TagClass["UNIVERSAL"] = 0] = "UNIVERSAL"; + TagClass[TagClass["APPLICATION"] = 1] = "APPLICATION"; + TagClass[TagClass["CONTEXT"] = 2] = "CONTEXT"; + TagClass[TagClass["PRIVATE"] = 3] = "PRIVATE"; + })(TagClass = asn1.TagClass || (asn1.TagClass = {})); + let TagType; + (function (TagType) { + TagType[TagType["EOC"] = 0] = "EOC"; + TagType[TagType["BOOLEAN"] = 1] = "BOOLEAN"; + TagType[TagType["INTEGER"] = 2] = "INTEGER"; + TagType[TagType["BIT_STRING"] = 3] = "BIT_STRING"; + TagType[TagType["OCTET_STRING"] = 4] = "OCTET_STRING"; + TagType[TagType["NULL"] = 5] = "NULL"; + TagType[TagType["OBJECT_IDENTIFIER"] = 6] = "OBJECT_IDENTIFIER"; + TagType[TagType["ObjectDescriptor"] = 7] = "ObjectDescriptor"; + TagType[TagType["EXTERNAL"] = 8] = "EXTERNAL"; + TagType[TagType["REAL"] = 9] = "REAL"; + TagType[TagType["ENUMERATED"] = 10] = "ENUMERATED"; + TagType[TagType["EMBEDDED_PDV"] = 11] = "EMBEDDED_PDV"; + TagType[TagType["UTF8String"] = 12] = "UTF8String"; + TagType[TagType["SEQUENCE"] = 16] = "SEQUENCE"; + TagType[TagType["SET"] = 17] = "SET"; + TagType[TagType["NumericString"] = 18] = "NumericString"; + TagType[TagType["PrintableString"] = 19] = "PrintableString"; + TagType[TagType["TeletextString"] = 20] = "TeletextString"; + TagType[TagType["VideotexString"] = 21] = "VideotexString"; + TagType[TagType["IA5String"] = 22] = "IA5String"; + TagType[TagType["UTCTime"] = 23] = "UTCTime"; + TagType[TagType["GeneralizedTime"] = 24] = "GeneralizedTime"; + TagType[TagType["GraphicString"] = 25] = "GraphicString"; + TagType[TagType["VisibleString"] = 26] = "VisibleString"; + TagType[TagType["GeneralString"] = 27] = "GeneralString"; + TagType[TagType["UniversalString"] = 28] = "UniversalString"; + TagType[TagType["BMPString"] = 30] = "BMPString"; + })(TagType = asn1.TagType || (asn1.TagType = {})); + class ASN1Tag { + constructor(stream) { + let buf = stream.get(); + this.tagClass = buf >> 6; + this.tagConstructed = ((buf & 0x20) !== 0); + this.tagNumber = buf & 0x1F; + if (this.tagNumber == 0x1F) { // long tag + let n = new Int10(); + do { + buf = stream.get(); + n.mulAdd(128, buf & 0x7F); + } while (buf & 0x80); + this.tagNumber = n.simplify(); + } + } + isUniversal() { + return this.tagClass === 0x00; + } + ; + isEOC() { + return this.tagClass === 0x00 && this.tagNumber === 0x00; + } + ; + } + class ASN1 { + constructor(stream, header, length, tag, children) { + this.stream = stream; + this.header = header; + this.length = length; + this.tag = tag; + this.children = children; + } + content(max_length, type) { + if (this.tag === undefined) + return null; + if (max_length === undefined) + max_length = Infinity; + let content = this.posContent(), len = Math.abs(this.length); + if (!this.tag.isUniversal()) { + if (this.children !== null) + return "(" + this.children.length + " elem)"; + return this.stream.parseOctetString(content, content + len, max_length); + } + switch (type || this.tag.tagNumber) { + case 0x01: // BOOLEAN + return (this.stream.get(content) === 0) ? "false" : "true"; + case 0x02: // INTEGER + return this.stream.parseInteger(content, content + len); + case 0x03: // BIT_STRING + return this.children ? "(" + this.children.length + " elem)" : + this.stream.parseBitString(content, content + len, max_length); + case 0x04: // OCTET_STRING + return this.children ? "(" + this.children.length + " elem)" : + this.stream.parseOctetString(content, content + len, max_length); + //case 0x05: // NULL + case 0x06: // OBJECT_IDENTIFIER + return this.stream.parseOID(content, content + len, max_length); + //case 0x07: // ObjectDescriptor + //case 0x08: // EXTERNAL + //case 0x09: // REAL + //case 0x0A: // ENUMERATED + //case 0x0B: // EMBEDDED_PDV + case 0x10: // SEQUENCE + case 0x11: // SET + if (this.children !== null) + return "(" + this.children.length + " elem)"; + else + return "(no elem)"; + case 0x0C: // UTF8String + return string_cut(this.stream.parseStringUTF(content, content + len), max_length); + case 0x12: // NumericString + case 0x13: // PrintableString + case 0x14: // TeletexString + case 0x15: // VideotexString + case 0x16: // IA5String + //case 0x19: // GraphicString + case 0x1A: // VisibleString + //case 0x1B: // GeneralString + //case 0x1C: // UniversalString + return string_cut(this.stream.parseStringISO(content, content + len), max_length); + case 0x1E: // BMPString + return string_cut(this.stream.parseStringBMP(content, content + len), max_length); + case 0x17: // UTCTime + case 0x18: // GeneralizedTime + return this.stream.parseTime(content, content + len, (this.tag.tagNumber == 0x17)); + } + return null; + } + ; + typeName() { + switch (this.tag.tagClass) { + case 0: // universal + return TagType[this.tag.tagNumber] || ("Universal_" + this.tag.tagNumber.toString()); + case 1: + return "Application_" + this.tag.tagNumber.toString(); + case 2: + return "[" + this.tag.tagNumber.toString() + "]"; // Context + case 3: + return "Private_" + this.tag.tagNumber.toString(); + } + } + ; + toString() { + return this.typeName() + "@" + this.stream.position + "[header:" + this.header + ",length:" + this.length + ",sub:" + ((this.children === null) ? 'null' : this.children.length) + "]"; + } + toPrettyString(indent) { + if (indent === undefined) + indent = ''; + let s = indent + this.typeName() + " @" + this.stream.position; + if (this.length >= 0) + s += "+"; + s += this.length; + if (this.tag.tagConstructed) + s += " (constructed)"; + else if ((this.tag.isUniversal() && ((this.tag.tagNumber == 0x03) || (this.tag.tagNumber == 0x04))) && (this.children !== null)) + s += " (encapsulates)"; + let content = this.content(); + if (content) + s += ": " + content.replace(/\n/g, '|'); + s += "\n"; + if (this.children !== null) { + indent += ' '; + for (let i = 0, max = this.children.length; i < max; ++i) + s += this.children[i].toPrettyString(indent); + } + return s; + } + ; + posStart() { + return this.stream.position; + } + ; + posContent() { + return this.stream.position + this.header; + } + ; + posEnd() { + return this.stream.position + this.header + Math.abs(this.length); + } + ; + static decodeLength(stream) { + let buf = stream.get(); + const len = buf & 0x7F; + if (len == buf) + return len; + if (len > 6) // no reason to use Int10, as it would be a huge buffer anyways + throw "Length over 48 bits not supported at position " + (stream.position - 1); + if (len === 0) + return null; // undefined + buf = 0; + for (let i = 0; i < len; ++i) + buf = (buf << 8) + stream.get(); + return buf; + } + ; + static encodeLength(buffer, offset, length) { + if (length < 0x7F) { + buffer[offset] = length; + } + else { + buffer[offset] = 0x80; + let index = 1; + while (length > 0) { + buffer[offset + index++] = length & 0xFF; + length >>= 8; + buffer[offset] += 1; + } + } + } + } + asn1.ASN1 = ASN1; + function decode0(stream) { + const streamStart = new Stream(stream, 0); /* copy */ + const tag = new ASN1Tag(stream); + let len = ASN1.decodeLength(stream); + const start = stream.position; + const length_header = start - streamStart.position; + let children = null; + const query_children = () => { + children = []; + if (len !== null) { + const end = start + len; + if (end > stream.length()) + throw 'Container at offset ' + start + ' has a length of ' + len + ', which is past the end of the stream'; + while (stream.position < end) + children[children.length] = decode0(stream); + if (stream.position != end) + throw 'Content size is not correct for container at offset ' + start; + } + else { + // undefined length + try { + while (true) { + const s = decode0(stream); + if (s.tag.isEOC()) + break; + children[children.length] = s; + } + len = start - stream.position; // undefined lengths are represented as negative values + } + catch (e) { + throw 'Exception while decoding undefined length content at offset ' + start + ': ' + e; + } + } + }; + if (tag.tagConstructed) { + // must have valid content + query_children(); + } + else if (tag.isUniversal() && ((tag.tagNumber == 0x03) || (tag.tagNumber == 0x04))) { + // sometimes BitString and OctetString are used to encapsulate ASN.1 + try { + if (tag.tagNumber == 0x03) + if (stream.get() != 0) + throw "BIT STRINGs with unused bits cannot encapsulate."; + query_children(); + for (let i = 0; i < children.length; ++i) + if (children[i].tag.isEOC()) + throw 'EOC is not supposed to be actual content.'; + } + catch (e) { + // but silently ignore when they don't + children = null; + //DEBUG console.log('Could not decode structure at ' + start + ':', e); + } + } + if (children === null) { + if (len === null) + throw "We can't skip over an invalid tag with undefined length at offset " + start; + stream.position = start + Math.abs(len); + } + return new ASN1(streamStart, length_header, len, tag, children); + } + function decode(stream) { + return decode0(new Stream(stream, 0)); + } + asn1.decode = decode; +})(asn1 || (asn1 = {})); +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["6bde651a74cdd2d05932f19f8fa848464eeb568c660e1ec7f4831839c5744f96"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["6bde651a74cdd2d05932f19f8fa848464eeb568c660e1ec7f4831839c5744f96"] = "6bde651a74cdd2d05932f19f8fa848464eeb568c660e1ec7f4831839c5744f96"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of []) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +var hex; +(function (hex) { + function encode(buffer) { + let hexCodes = []; + let view = new DataView(buffer); + for (let i = 0; i < view.byteLength % 4; i++) { + let value = view.getUint32(i * 4); + let stringValue = value.toString(16); + let padding = '00000000'; + let paddedValue = (padding + stringValue).slice(-padding.length); + hexCodes.push(paddedValue); + } + for (let i = (view.byteLength % 4) * 4; i < view.byteLength; i++) { + let value = view.getUint8(i).toString(16); + let padding = '00'; + hexCodes.push((padding + value).slice(-padding.length)); + } + return hexCodes.join(""); + } + hex.encode = encode; +})(hex || (hex = {})); +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["b288268cc16167231d1a5363ccc537a63bd4a36290992fde1b42a45e12e530d4"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["b288268cc16167231d1a5363ccc537a63bd4a36290992fde1b42a45e12e530d4"] = "b288268cc16167231d1a5363ccc537a63bd4a36290992fde1b42a45e12e530d4"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "XlrqGY18", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/profiles/ConnectionProfile.ts (122,35)" }, { name: "w5lXn91e", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/profiles/ConnectionProfile.ts (142,38)" }, { name: "OUsmYl99", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/profiles/ConnectionProfile.ts (142,81)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +var profiles; +(function (profiles_1) { + class ConnectionProfile { + constructor(id) { + this.selected_identity_type = "unset"; + this.identities = {}; + this.id = id; + } + selected_identity(current_type) { + if (!current_type) + current_type = this.selected_type(); + if (current_type === undefined) + return undefined; + if (current_type == profiles_1.identities.IdentitifyType.TEAFORO) { + return profiles_1.identities.static_forum_identity(); + } + else if (current_type == profiles_1.identities.IdentitifyType.TEAMSPEAK || current_type == profiles_1.identities.IdentitifyType.NICKNAME) { + return this.identities[this.selected_identity_type.toLowerCase()]; + } + return undefined; + } + selected_type() { + return profiles_1.identities.IdentitifyType[this.selected_identity_type.toUpperCase()]; + } + set_identity(type, identity) { + this.identities[profiles_1.identities.IdentitifyType[type].toLowerCase()] = identity; + } + spawn_identity_handshake_handler(connection) { + const identity = this.selected_identity(); + if (!identity) + return undefined; + return identity.spawn_identity_handshake_handler(connection); + } + encode() { + const identity_data = {}; + for (const key in this.identities) + if (this.identities[key]) + identity_data[key] = this.identities[key].encode(); + return JSON.stringify({ + version: 1, + username: this.default_username, + password: this.default_password, + profile_name: this.profile_name, + identity_type: this.selected_identity_type, + identity_data: identity_data, + id: this.id + }); + } + valid() { + const identity = this.selected_identity(); + if (!identity || !identity.valid()) + return false; + return this.default_username !== undefined; + } + } + profiles_1.ConnectionProfile = ConnectionProfile; + function decode_profile(data) { + return __awaiter(this, void 0, void 0, function* () { + data = JSON.parse(data); + if (data.version !== 1) + return "invalid version"; + const result = new ConnectionProfile(data.id); + result.default_username = data.username; + result.default_password = data.password; + result.profile_name = data.profile_name; + result.selected_identity_type = (data.identity_type || "").toLowerCase(); + if (data.identity_data) { + for (const key in data.identity_data) { + const type = profiles_1.identities.IdentitifyType[key.toUpperCase()]; + const _data = data.identity_data[key]; + if (type == undefined) + continue; + const identity = yield profiles_1.identities.decode_identity(type, _data); + if (identity == undefined) + continue; + result.identities[key.toLowerCase()] = identity; + } + } + return result; + }); + } + let available_profiles = []; + function load() { + return __awaiter(this, void 0, void 0, function* () { + available_profiles = []; + const profiles_json = localStorage.getItem("profiles"); + let profiles_data = profiles_json ? JSON.parse(profiles_json) : { version: 0 }; + if (profiles_data.version === 0) { + profiles_data = { + version: 1, + profiles: [] + }; + } + if (profiles_data.version == 1) { + for (const profile_data of profiles_data.profiles) { + const profile = yield decode_profile(profile_data); + if (typeof (profile) === 'string') { + console.error(_translations.XlrqGY18 || (_translations.XlrqGY18 = tr("Failed to load profile. Reason: %s, Profile data: %s")), profile, profiles_data); + continue; + } + available_profiles.push(profile); + } + } + if (!find_profile("default")) { //Create a default profile and teaforo profile + { + const profile = create_new_profile("default", "default"); + profile.default_password = ""; + profile.default_username = "Another TeaSpeak user"; + profile.profile_name = "Default Profile"; + /* generate default identity */ + try { + const identity = yield profiles_1.identities.TeaSpeakIdentity.generate_new(); + profile.set_identity(profiles_1.identities.IdentitifyType.TEAMSPEAK, identity); + profile.selected_identity_type = profiles_1.identities.IdentitifyType[profiles_1.identities.IdentitifyType.TEAMSPEAK]; + } + catch (error) { + createErrorModal(_translations.w5lXn91e || (_translations.w5lXn91e = tr("Failed to generate default identity")), _translations.OUsmYl99 || (_translations.OUsmYl99 = tr("Failed to generate default identity!
    Please manually generate the identity within your settings => profiles"))).open(); + } + } + { /* forum identity (works only when connected to the forum) */ + const profile = create_new_profile("TeaSpeak Forum", "teaforo"); + profile.default_password = ""; + profile.default_username = "Another TeaSpeak user"; + profile.profile_name = "TeaSpeak Forum profile"; + } + save(); + } + }); + } + profiles_1.load = load; + function create_new_profile(name, id) { + const profile = new ConnectionProfile(id || guid()); + profile.profile_name = name; + profile.default_username = "Another TeaSpeak user"; + available_profiles.push(profile); + return profile; + } + profiles_1.create_new_profile = create_new_profile; + let _requires_save = false; + function save() { + const profiles = []; + for (const profile of available_profiles) + profiles.push(profile.encode()); + const data = JSON.stringify({ + version: 1, + profiles: profiles + }); + localStorage.setItem("profiles", data); + } + profiles_1.save = save; + function mark_need_save() { + _requires_save = true; + } + profiles_1.mark_need_save = mark_need_save; + function requires_save() { + return _requires_save; + } + profiles_1.requires_save = requires_save; + function profiles() { + return available_profiles; + } + profiles_1.profiles = profiles; + function find_profile(id) { + for (const profile of profiles()) + if (profile.id == id) + return profile; + return undefined; + } + profiles_1.find_profile = find_profile; + function find_profile_by_name(name) { + name = name.toLowerCase(); + for (const profile of profiles()) + if ((profile.profile_name || "").toLowerCase() == name) + return profile; + return undefined; + } + profiles_1.find_profile_by_name = find_profile_by_name; + function default_profile() { + return find_profile("default"); + } + profiles_1.default_profile = default_profile; + function set_default_profile(profile) { + const old_default = default_profile(); + if (old_default && old_default != profile) { + old_default.id = guid(); + } + profile.id = "default"; + } + profiles_1.set_default_profile = set_default_profile; + function delete_profile(profile) { + available_profiles.remove(profile); + } + profiles_1.delete_profile = delete_profile; +})(profiles || (profiles = {})); +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["97f4f425246fb5a09df76962d3b4e6ded55a744c1a4572c69cacb84b09947703"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["97f4f425246fb5a09df76962d3b4e6ded55a744c1a4572c69cacb84b09947703"] = "97f4f425246fb5a09df76962d3b4e6ded55a744c1a4572c69cacb84b09947703"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "LU4TMdIh", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/profiles/identities/NameIdentity.ts (23,31)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +/// +var profiles; +(function (profiles) { + var identities; + (function (identities) { + class NameHandshakeHandler extends identities.AbstractHandshakeIdentityHandler { + constructor(connection, identity) { + super(connection); + this.identity = identity; + this.handler = new identities.HandshakeCommandHandler(connection, this); + this.handler["handshakeidentityproof"] = () => this.trigger_fail("server requested unexpected proof"); + } + start_handshake() { + this.connection.command_handler_boss().register_handler(this.handler); + this.connection.send_command("handshakebegin", { + intention: 0, + authentication_method: this.identity.type(), + client_nickname: this.identity.name() + }).catch(error => { + console.error(_translations.LU4TMdIh || (_translations.LU4TMdIh = tr("Failed to initialize name based handshake. Error: %o")), error); + if (error instanceof CommandResult) + error = error.extra_message || error.message; + this.trigger_fail("failed to execute begin (" + error + ")"); + }).then(() => this.trigger_success()); + } + trigger_fail(message) { + this.connection.command_handler_boss().unregister_handler(this.handler); + super.trigger_fail(message); + } + trigger_success() { + this.connection.command_handler_boss().unregister_handler(this.handler); + super.trigger_success(); + } + } + class NameIdentity { + constructor(name) { + this._name = name; + } + set_name(name) { this._name = name; } + name() { + return this._name; + } + uid() { + return btoa(this._name); //FIXME hash! + } + type() { + return identities.IdentitifyType.NICKNAME; + } + valid() { + return this._name != undefined && this._name.length >= 3; + } + decode(data) { + data = JSON.parse(data); + if (data.version !== 1) + throw "invalid version"; + this._name = data["name"]; + return; + } + encode() { + return JSON.stringify({ + version: 1, + name: this._name + }); + } + spawn_identity_handshake_handler(connection) { + return new NameHandshakeHandler(connection, this); + } + } + identities.NameIdentity = NameIdentity; + })(identities = profiles.identities || (profiles.identities = {})); +})(profiles || (profiles = {})); +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["b13c710ce5812e8eebe16c3f00ec0e6fc0c6afb86dde4b0672d57682d4d1615b"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["b13c710ce5812e8eebe16c3f00ec0e6fc0c6afb86dde4b0672d57682d4d1615b"] = "b13c710ce5812e8eebe16c3f00ec0e6fc0c6afb86dde4b0672d57682d4d1615b"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "gTP_s5rf", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/profiles/identities/TeaForumIdentity.ts (22,31)" }, { name: "rtlNOQM4", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/profiles/identities/TeaForumIdentity.ts (35,31)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +/// +var profiles; +(function (profiles) { + var identities; + (function (identities) { + class TeaForumHandshakeHandler extends identities.AbstractHandshakeIdentityHandler { + constructor(connection, identity) { + super(connection); + this.identity = identity; + this.handler = new identities.HandshakeCommandHandler(connection, this); + this.handler["handshakeidentityproof"] = this.handle_proof.bind(this); + } + start_handshake() { + this.connection.command_handler_boss().register_handler(this.handler); + this.connection.send_command("handshakebegin", { + intention: 0, + authentication_method: this.identity.type(), + data: this.identity.data_json() + }).catch(error => { + console.error(_translations.gTP_s5rf || (_translations.gTP_s5rf = tr("Failed to initialize TeaForum based handshake. Error: %o")), error); + if (error instanceof CommandResult) + error = error.extra_message || error.message; + this.trigger_fail("failed to execute begin (" + error + ")"); + }); + } + handle_proof(json) { + this.connection.send_command("handshakeindentityproof", { + proof: this.identity.data_sign() + }).catch(error => { + console.error(_translations.rtlNOQM4 || (_translations.rtlNOQM4 = tr("Failed to proof the identity. Error: %o")), error); + if (error instanceof CommandResult) + error = error.extra_message || error.message; + this.trigger_fail("failed to execute proof (" + error + ")"); + }).then(() => this.trigger_success()); + } + trigger_fail(message) { + this.connection.command_handler_boss().unregister_handler(this.handler); + super.trigger_fail(message); + } + trigger_success() { + this.connection.command_handler_boss().unregister_handler(this.handler); + super.trigger_success(); + } + } + class TeaForumIdentity { + constructor(data, sign) { + this.identity_data_raw = data; + this.identity_data_sign = sign; + try { + this.identity_data = data ? JSON.parse(this.identity_data_raw) : undefined; + } + catch (error) { } + } + valid() { + return this.identity_data_raw.length > 0 && this.identity_data_raw.length > 0 && this.identity_data_sign.length > 0; + } + data_json() { return this.identity_data_raw; } + data_sign() { return this.identity_data_sign; } + name() { return this.identity_data["user_name"]; } + uid() { return "TeaForo#" + this.identity_data["user_id"]; } + type() { return identities.IdentitifyType.TEAFORO; } + forum_user_id() { return this.identity_data["user_id"]; } + forum_user_group() { return this.identity_data["user_group_id"]; } + is_stuff() { return this.identity_data["is_staff"]; } + is_premium() { return this.identity_data["user_groups"].indexOf(5) != -1; } + data_age() { return new Date(this.identity_data["data_age"]); } + /* + $user_data["user_id"] = $user->user_id; + $user_data["user_name"] = $user->username; + $user_data["user_group"] = $user->user_group_id; + $user_data["user_groups"] = $user->secondary_group_ids; + + $user_data["trophy_points"] = $user->trophy_points; + $user_data["register_date"] = $user->register_date; + $user_data["is_staff"] = $user->is_staff; + $user_data["is_admin"] = $user->is_admin; + $user_data["is_super_admin"] = $user->is_super_admin; + $user_data["is_banned"] = $user->is_banned; + + $user_data["data_age"] = milliseconds(); + */ + decode(data) { + data = JSON.parse(data); + if (data.version !== 1) + throw "invalid version"; + this.identity_data_raw = data["identity_data"]; + this.identity_data_sign = data["identity_sign"]; + this.identity_data = JSON.parse(this.identity_data); + return; + } + encode() { + return JSON.stringify({ + version: 1, + identity_data: this.identity_data_raw, + identity_sign: this.identity_data_sign + }); + } + spawn_identity_handshake_handler(connection) { + return new TeaForumHandshakeHandler(connection, this); + } + } + identities.TeaForumIdentity = TeaForumIdentity; + let static_identity; + function set_static_identity(identity) { + static_identity = identity; + } + identities.set_static_identity = set_static_identity; + function setup_forum() { + const user_data = settings.static("forum_user_data"); + const user_sign = settings.static("forum_user_sign"); + if (user_data && user_sign) + static_identity = new TeaForumIdentity(user_data, user_sign); + } + identities.setup_forum = setup_forum; + function valid_static_forum_identity() { + return static_identity && static_identity.valid(); + } + identities.valid_static_forum_identity = valid_static_forum_identity; + function static_forum_identity() { + return static_identity; + } + identities.static_forum_identity = static_forum_identity; + })(identities = profiles.identities || (profiles.identities = {})); +})(profiles || (profiles = {})); +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["2ebc31136bb5cb9c9590586fa5a6c05556711699d9fb197a19f3a560ce22cbca"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["2ebc31136bb5cb9c9590586fa5a6c05556711699d9fb197a19f3a560ce22cbca"] = "2ebc31136bb5cb9c9590586fa5a6c05556711699d9fb197a19f3a560ce22cbca"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "UShtyyBP", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/profiles/identities/TeamSpeakIdentity.ts (217,31)" }, { name: "MexYNNj3", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/profiles/identities/TeamSpeakIdentity.ts (233,35)" }, { name: "dzrFDiun", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/profiles/identities/TeamSpeakIdentity.ts (415,31)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +/// +var profiles; +(function (profiles) { + var identities; + (function (identities) { + let CryptoHelper; + (function (CryptoHelper) { + function export_ecc_key(crypto_key, public_key) { + return __awaiter(this, void 0, void 0, function* () { + /* + Tomcrypt public key export: + if (type == PK_PRIVATE) { + flags[0] = 1; + err = der_encode_sequence_multi(out, outlen, + LTC_ASN1_BIT_STRING, 1UL, flags, + LTC_ASN1_SHORT_INTEGER, 1UL, &key_size, + LTC_ASN1_INTEGER, 1UL, key->pubkey.x, + LTC_ASN1_INTEGER, 1UL, key->pubkey.y, + LTC_ASN1_INTEGER, 1UL, key->k, + LTC_ASN1_EOL, 0UL, NULL); + } else { + flags[0] = 0; + err = der_encode_sequence_multi(out, outlen, + LTC_ASN1_BIT_STRING, 1UL, flags, + LTC_ASN1_SHORT_INTEGER, 1UL, &key_size, + LTC_ASN1_INTEGER, 1UL, key->pubkey.x, + LTC_ASN1_INTEGER, 1UL, key->pubkey.y, + LTC_ASN1_EOL, 0UL, NULL); + } + + */ + const key_data = yield crypto.subtle.exportKey("jwk", crypto_key); + let index = 0; + const length = public_key ? 79 : 114; /* max lengths! Depends on the padding could be less */ + const buffer = new Uint8Array(length); /* fixed ASN1 length */ + { /* the initial sequence */ + buffer[index++] = 0x30; /* type */ + buffer[index++] = 0x00; /* we will set the sequence length later */ + } + { /* the flags bit string */ + buffer[index++] = 0x03; /* type */ + buffer[index++] = 0x02; /* length */ + buffer[index++] = 0x07; /* data */ + buffer[index++] = public_key ? 0x00 : 0x80; /* flag 1 or 0 (1 = private key)*/ + } + { /* key size (const 32 for P-256) */ + buffer[index++] = 0x02; /* type */ + buffer[index++] = 0x01; /* length */ + buffer[index++] = 0x20; + } + try { /* Public kex X */ + buffer[index++] = 0x02; /* type */ + buffer[index++] = 0x20; /* length */ + const raw = atob(Base64DecodeUrl(key_data.x, false)); + if (raw.charCodeAt(0) > 0x7F) { + buffer[index - 1] += 1; + buffer[index++] = 0; + } + for (let i = 0; i < 32; i++) + buffer[index++] = raw.charCodeAt(i); + } + catch (error) { + if (error instanceof DOMException) + throw "failed to parse x coordinate (invalid base64)"; + throw error; + } + try { /* Public kex Y */ + buffer[index++] = 0x02; /* type */ + buffer[index++] = 0x20; /* length */ + const raw = atob(Base64DecodeUrl(key_data.y, false)); + if (raw.charCodeAt(0) > 0x7F) { + buffer[index - 1] += 1; + buffer[index++] = 0; + } + for (let i = 0; i < 32; i++) + buffer[index++] = raw.charCodeAt(i); + } + catch (error) { + if (error instanceof DOMException) + throw "failed to parse y coordinate (invalid base64)"; + throw error; + } + if (!public_key) { + try { /* Public kex K */ + buffer[index++] = 0x02; /* type */ + buffer[index++] = 0x20; /* length */ + const raw = atob(Base64DecodeUrl(key_data.d, false)); + if (raw.charCodeAt(0) > 0x7F) { + buffer[index - 1] += 1; + buffer[index++] = 0; + } + for (let i = 0; i < 32; i++) + buffer[index++] = raw.charCodeAt(i); + } + catch (error) { + if (error instanceof DOMException) + throw "failed to parse y coordinate (invalid base64)"; + throw error; + } + } + buffer[1] = index - 2; /* set the final sequence length */ + return base64ArrayBuffer(buffer.buffer.slice(0, index)); + }); + } + CryptoHelper.export_ecc_key = export_ecc_key; + const crypt_key = "b9dfaa7bee6ac57ac7b65f1094a1c155e747327bc2fe5d51c512023fe54a280201004e90ad1daaae1075d53b7d571c30e063b5a62a4a017bb394833aa0983e6e"; + function c_strlen(buffer, offset) { + let index = 0; + while (index + offset < buffer.length && buffer[index + offset] != 0) + index++; + return index; + } + function decrypt_ts_identity(buffer) { + return __awaiter(this, void 0, void 0, function* () { + /* buffer could contains a zero! */ + const hash = new Uint8Array(yield sha.sha1(buffer.buffer.slice(20, 20 + c_strlen(buffer, 20)))); + for (let i = 0; i < 20; i++) + buffer[i] ^= hash[i]; + const length = Math.min(buffer.length, 100); + for (let i = 0; i < length; i++) + buffer[i] ^= crypt_key.charCodeAt(i); + return ab2str(buffer); + }); + } + CryptoHelper.decrypt_ts_identity = decrypt_ts_identity; + function encrypt_ts_identity(buffer) { + return __awaiter(this, void 0, void 0, function* () { + const length = Math.min(buffer.length, 100); + for (let i = 0; i < length; i++) + buffer[i] ^= crypt_key.charCodeAt(i); + const hash = new Uint8Array(yield sha.sha1(buffer.buffer.slice(20, 20 + c_strlen(buffer, 20)))); + for (let i = 0; i < 20; i++) + buffer[i] ^= hash[i]; + return base64ArrayBuffer(buffer); + }); + } + CryptoHelper.encrypt_ts_identity = encrypt_ts_identity; + /** + * @param buffer base64 encoded ASN.1 string + */ + function decode_tomcrypt_key(buffer) { + let decoded; + try { + decoded = asn1.decode(atob(buffer)); + } + catch (error) { + if (error instanceof DOMException) + throw "failed to parse key buffer (invalid base64)"; + throw error; + } + let { x, y, k } = { + x: decoded.children[2].content(Infinity, asn1.TagType.VisibleString), + y: decoded.children[3].content(Infinity, asn1.TagType.VisibleString), + k: decoded.children[4].content(Infinity, asn1.TagType.VisibleString) + }; + if (x.length > 32) { + if (x.charCodeAt(0) != 0) + throw "Invalid X coordinate! (Too long)"; + x = x.substr(1); + } + if (y.length > 32) { + if (y.charCodeAt(0) != 0) + throw "Invalid Y coordinate! (Too long)"; + y = y.substr(1); + } + if (k.length > 32) { + if (k.charCodeAt(0) != 0) + throw "Invalid private coordinate! (Too long)"; + k = k.substr(1); + } + /* + console.log("Key x: %s (%d)", btoa(x), x.length); + console.log("Key y: %s (%d)", btoa(y), y.length); + console.log("Key k: %s (%d)", btoa(k), k.length); + */ + return { + crv: "P-256", + d: Base64EncodeUrl(btoa(k)), + x: Base64EncodeUrl(btoa(x)), + y: Base64EncodeUrl(btoa(y)), + ext: true, + key_ops: ["deriveKey", "sign"], + kty: "EC", + }; + } + CryptoHelper.decode_tomcrypt_key = decode_tomcrypt_key; + })(CryptoHelper = identities.CryptoHelper || (identities.CryptoHelper = {})); + class TeaSpeakHandshakeHandler extends identities.AbstractHandshakeIdentityHandler { + constructor(connection, identity) { + super(connection); + this.identity = identity; + this.handler = new identities.HandshakeCommandHandler(connection, this); + this.handler["handshakeidentityproof"] = this.handle_proof.bind(this); + } + start_handshake() { + this.connection.command_handler_boss().register_handler(this.handler); + this.connection.send_command("handshakebegin", { + intention: 0, + authentication_method: this.identity.type(), + publicKey: this.identity.public_key + }).catch(error => { + console.error(_translations.UShtyyBP || (_translations.UShtyyBP = tr("Failed to initialize TeamSpeak based handshake. Error: %o")), error); + if (error instanceof CommandResult) + error = error.extra_message || error.message; + this.trigger_fail("failed to execute begin (" + error + ")"); + }); + } + handle_proof(json) { + if (!json[0]["digest"]) { + this.trigger_fail("server too old"); + return; + } + this.identity.sign_message(json[0]["message"], json[0]["digest"]).then(proof => { + this.connection.send_command("handshakeindentityproof", { proof: proof }).catch(error => { + console.error(_translations.MexYNNj3 || (_translations.MexYNNj3 = tr("Failed to proof the identity. Error: %o")), error); + if (error instanceof CommandResult) + error = error.extra_message || error.message; + this.trigger_fail("failed to execute proof (" + error + ")"); + }).then(() => this.trigger_success()); + }).catch(error => { + this.trigger_fail("failed to sign message"); + }); + } + trigger_fail(message) { + this.connection.command_handler_boss().unregister_handler(this.handler); + super.trigger_fail(message); + } + trigger_success() { + this.connection.command_handler_boss().unregister_handler(this.handler); + super.trigger_success(); + } + } + class IdentityPOWWorker { + initialize(key) { + return __awaiter(this, void 0, void 0, function* () { + this._worker = new Worker(settings.static("worker_directory", "js/workers/") + "WorkerPOW.js"); + /* initialize */ + yield new Promise((resolve, reject) => { + const timeout_id = setTimeout(() => reject("timeout"), 1000); + this._worker.onmessage = event => { + clearTimeout(timeout_id); + if (!event.data) { + reject("invalid data"); + return; + } + if (!event.data.success) { + reject("initialize failed (" + event.data.success + " | " + (event.data.message || "unknown eroror") + ")"); + return; + } + this._worker.onmessage = event => this.handle_message(event.data); + resolve(); + }; + this._worker.onerror = event => { + console.error("POW Worker error %o", event); + clearTimeout(timeout_id); + reject("Failed to load worker (" + event.message + ")"); + }; + }); + /* set data */ + yield new Promise((resolve, reject) => { + this._worker.postMessage({ + type: "set_data", + private_key: key, + code: "set_data" + }); + const timeout_id = setTimeout(() => reject("timeout (data)"), 1000); + this._worker.onmessage = event => { + clearTimeout(timeout_id); + if (!event.data) { + reject("invalid data"); + return; + } + if (!event.data.success) { + reject("initialize of data failed (" + event.data.success + " | " + (event.data.message || "unknown eroror") + ")"); + return; + } + this._worker.onmessage = event => this.handle_message(event.data); + resolve(); + }; + }); + }); + } + mine(hash, iterations, target, timeout) { + return __awaiter(this, void 0, void 0, function* () { + this._current_hash = hash; + if (target < this._best_level) + return true; + return yield new Promise((resolve, reject) => { + this._worker.postMessage({ + type: "mine", + hash: this._current_hash, + iterations: iterations, + target: target, + code: "mine" + }); + const timeout_id = setTimeout(() => reject("timeout (mine)"), timeout || 5000); + this._worker.onmessage = event => { + this._worker.onmessage = event => this.handle_message(event.data); + clearTimeout(timeout_id); + if (!event.data) { + reject("invalid data"); + return; + } + if (!event.data.success) { + reject("mining failed (" + event.data.success + " | " + (event.data.message || "unknown eroror") + ")"); + return; + } + if (event.data.result) { + this._best_level = event.data.level; + this._current_hash = event.data.hash; + resolve(true); + } + else { + resolve(false); /* no result */ + } + }; + }); + }); + } + current_hash() { + return this._current_hash; + } + current_level() { + return this._best_level; + } + finalize(timeout) { + return __awaiter(this, void 0, void 0, function* () { + try { + yield new Promise((resolve, reject) => { + this._worker.postMessage({ + type: "finalize", + code: "finalize" + }); + const timeout_id = setTimeout(() => reject("timeout"), timeout || 250); + this._worker.onmessage = event => { + this._worker.onmessage = event => this.handle_message(event.data); + clearTimeout(timeout_id); + if (!event.data) { + reject("invalid data"); + return; + } + if (!event.data.success) { + reject("failed to finalize (" + event.data.success + " | " + (event.data.message || "unknown eroror") + ")"); + return; + } + resolve(); + }; + }); + } + catch (error) { + console.warn("Failed to finalize POW worker! (%o)", error); + } + this._worker.terminate(); + this._worker = undefined; + }); + } + handle_message(message) { + console.log("Received message: %o", message); + } + } + class TeaSpeakIdentity { + constructor(private_key, hash, name, initialize) { + this.private_key = private_key; + this.hash_number = hash || "0"; + this._name = name; + if (this.private_key && (typeof (initialize) === "undefined" || initialize)) { + this.initialize().catch(error => { + console.error("Failed to initialize TeaSpeakIdentity (%s)", error); + this._initialized = false; + }); + } + } + static generate_new() { + return __awaiter(this, void 0, void 0, function* () { + let key; + try { + key = yield crypto.subtle.generateKey({ name: 'ECDH', namedCurve: 'P-256' }, true, ["deriveKey"]); + } + catch (e) { + console.error(_translations.dzrFDiun || (_translations.dzrFDiun = tr("Could not generate a new key: %o")), e); + throw "Failed to generate keypair"; + } + const private_key = yield CryptoHelper.export_ecc_key(key.privateKey, false); + const identity = new TeaSpeakIdentity(private_key, "0", undefined, false); + yield identity.initialize(); + return identity; + }); + } + static import_ts(ts_string, ini) { + return __awaiter(this, void 0, void 0, function* () { + const parse_string = string => { + /* parsing without INI structure */ + const V_index = string.indexOf('V'); + if (V_index == -1) + throw "invalid input (missing V)"; + return { + hash: string.substr(0, V_index), + data: string.substr(V_index + 1), + name: "TeaSpeak user" + }; + }; + const { hash, data, name } = (!ini ? () => parse_string(ts_string) : () => { + /* parsing with INI structure */ + let identity, name; + for (const line of ts_string.split("\n")) { + if (line.startsWith("identity=")) + identity = line.substr(9); + else if (line.startsWith("nickname=")) + name = line.substr(9); + } + if (!identity) + throw "missing identity keyword"; + if (identity[0] == "\"" && identity[identity.length - 1] == "\"") + identity = identity.substr(1, identity.length - 2); + const result = parse_string(identity); + result.name = name || result.name; + return result; + })(); + if (!ts_string.match(/[0-9]+/g)) + throw "invalid hash!"; + const key64 = yield CryptoHelper.decrypt_ts_identity(new Uint8Array(arrayBufferBase64(data))); + const identity = new TeaSpeakIdentity(key64, hash, name, false); + yield identity.initialize(); + return identity; + }); + } + name() { + return this._name; + } + uid() { + return this._unique_id; + } + type() { + return identities.IdentitifyType.TEAMSPEAK; + } + valid() { + return this._initialized && !!this._crypto_key && !!this._crypto_key_sign; + } + decode(data) { + return __awaiter(this, void 0, void 0, function* () { + const json = JSON.parse(data); + if (!json) + throw "invalid json"; + if (json.version == 2) { + this.private_key = json.key; + this.hash_number = json.hash; + this._name = json.name; + } + else if (json.version == 1) { + const key = json.key; + this._name = json.name; + const clone = yield TeaSpeakIdentity.import_ts(key, false); + this.private_key = clone.private_key; + this.hash_number = clone.hash_number; + } + else + throw "invalid version"; + yield this.initialize(); + }); + } + encode() { + return JSON.stringify({ + key: this.private_key, + hash: this.hash_number, + name: this._name, + version: 2 + }); + } + level() { + return __awaiter(this, void 0, void 0, function* () { + if (!this._initialized || !this.public_key) + throw "not initialized"; + const hash = new Uint8Array(yield sha.sha1(this.public_key + this.hash_number)); + let level = 0; + while (level < hash.byteLength && hash[level] == 0) + level++; + if (level >= hash.byteLength) { + level = 256; + } + else { + let byte = hash[level]; + level <<= 3; + while ((byte & 0x1) == 0) { + level++; + byte >>= 1; + } + } + return level; + }); + } + /** + * @param {string} a + * @param {string} b + * @description b must be smaller (in bytes) then a + */ + string_add(a, b) { + const char_result = []; + const char_a = [...a].reverse().map(e => e.charCodeAt(0)); + const char_b = [...b].reverse().map(e => e.charCodeAt(0)); + let carry = false; + while (char_b.length > 0) { + let result = char_b.pop_front() + char_a.pop_front() + (carry ? 1 : 0) - 48; + if ((carry = result > 57)) + result -= 10; + char_result.push(result); + } + while (char_a.length > 0) { + let result = char_a.pop_front() + (carry ? 1 : 0); + if ((carry = result > 57)) + result -= 10; + char_result.push(result); + } + if (carry) + char_result.push(49); + return String.fromCharCode.apply(null, char_result.reverse()); + } + improve_level_for(time, threads) { + return __awaiter(this, void 0, void 0, function* () { + let active = true; + setTimeout(() => active = false, time); + return yield this.improve_level(-1, threads, () => active); + }); + } + improve_level(target, threads, active_callback, callback_level, callback_status) { + return __awaiter(this, void 0, void 0, function* () { + if (!this._initialized || !this.public_key) + throw "not initialized"; + if (target == -1) /* get the highest level possible */ + target = 0; + else if (target <= (yield this.level())) + return true; + const workers = []; + const iterations = 100000; + let current_hash; + const next_hash = () => { + if (!current_hash) + return (current_hash = this.hash_number); + if (current_hash.length < iterations.toString().length) { + current_hash = this.string_add(iterations.toString(), current_hash); + } + else { + current_hash = this.string_add(current_hash, iterations.toString()); + } + return current_hash; + }; + { /* init */ + const initialize_promise = []; + for (let index = 0; index < threads; index++) { + const worker = new IdentityPOWWorker(); + workers.push(worker); + initialize_promise.push(worker.initialize(this.public_key)); + } + try { + yield Promise.all(initialize_promise); + } + catch (error) { + console.error(error); + throw "failed to initialize"; + } + } + let result = false; + let best_level = 0; + let target_level = target > 0 ? target : (yield this.level()) + 1; + const worker_promise = []; + const hash_timestamps = []; + let last_hashrate_update = 0; + const update_hashrate = () => { + if (!callback_status) + return; + const now = Date.now(); + hash_timestamps.push(now); + if (last_hashrate_update + 1000 < now) { + last_hashrate_update = now; + const timeout = now - 10 * 1000; /* 10s */ + const rounds = hash_timestamps.filter(e => e > timeout); + callback_status(Math.ceil((rounds.length * iterations) / Math.ceil((now - rounds[0]) / 1000))); + } + }; + try { + result = yield new Promise((resolve, reject) => { + let active = true; + const exit = () => { + const timeout = setTimeout(() => resolve(true), 1000); + Promise.all(worker_promise).then(result => { + clearTimeout(timeout); + resolve(true); + }).catch(error => resolve(true)); + active = false; + }; + for (const worker of workers) { + const worker_mine = () => { + if (!active) + return; + const promise = worker.mine(next_hash(), iterations, target_level); + const p = promise.then(result => { + update_hashrate(); + worker_promise.remove(p); + if (result.valueOf()) { + if (worker.current_level() > best_level) { + this.hash_number = worker.current_hash(); + console.log("Found new best at %s (%d). Old was %d", this.hash_number, worker.current_level(), best_level); + best_level = worker.current_level(); + if (callback_level) + callback_level(best_level); + } + if (active) { + if (target > 0) + exit(); + else + target_level = best_level + 1; + } + } + if (active && (active = active_callback())) + setTimeout(() => worker_mine(), 0); + else { + exit(); + } + return Promise.resolve(); + }).catch(error => { + worker_promise.remove(p); + console.warn("POW worker error %o", error); + reject(error); + return Promise.resolve(); + }); + worker_promise.push(p); + }; + worker_mine(); + } + }); + } + catch (error) { + //error already printed before reject had been called + } + { /* shutdown */ + const finalize_promise = []; + for (const worker of workers) + finalize_promise.push(worker.finalize(250)); + try { + yield Promise.all(finalize_promise); + } + catch (error) { + console.error(error); + throw "failed to finalize"; + } + } + return result; + }); + } + initialize() { + return __awaiter(this, void 0, void 0, function* () { + if (!this.private_key) + throw "Invalid private key"; + let jwk; + try { + jwk = yield CryptoHelper.decode_tomcrypt_key(this.private_key); + if (!jwk) + throw "result undefined"; + } + catch (error) { + throw "failed to parse key (" + error + ")"; + } + try { + this._crypto_key_sign = yield crypto.subtle.importKey("jwk", jwk, { name: 'ECDSA', namedCurve: 'P-256' }, false, ["sign"]); + } + catch (error) { + console.error(error); + throw "failed to create crypto sign key"; + } + try { + this._crypto_key = yield crypto.subtle.importKey("jwk", jwk, { name: 'ECDH', namedCurve: 'P-256' }, true, ["deriveKey"]); + } + catch (error) { + console.error(error); + throw "failed to create crypto key"; + } + try { + this.public_key = yield CryptoHelper.export_ecc_key(this._crypto_key, true); + this._unique_id = base64ArrayBuffer(yield sha.sha1(this.public_key)); + } + catch (error) { + console.error(error); + throw "failed to calculate unique id"; + } + this._initialized = true; + //const public_key = await profiles.identities.CryptoHelper.export_ecc_key(key, true); + }); + } + export_ts(ini) { + return __awaiter(this, void 0, void 0, function* () { + if (!this.private_key) + throw "Invalid private key"; + const identity = this.hash_number + "V" + (yield CryptoHelper.encrypt_ts_identity(new Uint8Array(str2ab8(this.private_key)))); + if (!ini) + return identity; + return "[Identity]\n" + + "id=TeaWeb-Exported\n" + + "identity=\"" + identity + "\"\n" + + "nickname=\"" + this.name() + "\"\n" + + "phonetic_nickname="; + }); + } + sign_message(message, hash = "SHA-256") { + return __awaiter(this, void 0, void 0, function* () { + /* bring this to libtomcrypt format */ + const sign_buffer = yield crypto.subtle.sign({ + name: "ECDSA", + hash: hash + }, this._crypto_key_sign, str2ab8(message)); + const sign = new Uint8Array(sign_buffer); + /* first 32 r bits | last 32 s bits */ + const buffer = new Uint8Array(72); + let index = 0; + { /* the initial sequence */ + buffer[index++] = 0x30; /* type */ + buffer[index++] = 0x00; /* we will set the sequence length later */ + } + { /* integer r */ + buffer[index++] = 0x02; /* type */ + buffer[index++] = 0x20; /* length */ + if (sign[0] > 0x7F) { + buffer[index - 1] += 1; + buffer[index++] = 0; + } + for (let i = 0; i < 32; i++) + buffer[index++] = sign[i]; + } + { /* integer s */ + buffer[index++] = 0x02; /* type */ + buffer[index++] = 0x20; /* length */ + if (sign[32] > 0x7F) { + buffer[index - 1] += 1; + buffer[index++] = 0; + } + for (let i = 0; i < 32; i++) + buffer[index++] = sign[32 + i]; + } + buffer[1] = index - 2; + return base64ArrayBuffer(buffer.subarray(0, index)); + }); + } + spawn_identity_handshake_handler(connection) { + return new TeaSpeakHandshakeHandler(connection, this); + } + } + identities.TeaSpeakIdentity = TeaSpeakIdentity; + })(identities = profiles.identities || (profiles.identities = {})); +})(profiles || (profiles = {})); +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["446c209ef81f7b7224d75fc18d74014a5fa733e34fd263d33518be90ac3515b7"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["446c209ef81f7b7224d75fc18d74014a5fa733e34fd263d33518be90ac3515b7"] = "446c209ef81f7b7224d75fc18d74014a5fa733e34fd263d33518be90ac3515b7"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "SHOob1ET", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/sound/Sounds.ts (231,26)" }, { name: "qc1lS3zj", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/sound/Sounds.ts (244,26)" }, { name: "NYKnfWD9", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/sound/Sounds.ts (249,21)" }, { name: "TedPjWue", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/sound/Sounds.ts (257,33)" }, { name: "MLBuwnWd", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/sound/Sounds.ts (261,29)" }, { name: "nZCjUk0f", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/sound/Sounds.ts (287,37)" }, { name: "gELGE4Pb", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/sound/Sounds.ts (289,41)" }, { name: "PgjiBh_8", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/sound/Sounds.ts (293,43)" }, { name: "qC2EsMD0", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/sound/Sounds.ts (313,39)" }, { name: "PejUdLLE", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/sound/Sounds.ts (320,35)" }, { name: "m7VfH0cA", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/sound/Sounds.ts (329,25)" }, { name: "_RK0Gxtx", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/sound/Sounds.ts (336,34)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +var Sound; +(function (Sound) { + Sound["SOUND_TEST"] = "sound.test"; + Sound["SOUND_EGG"] = "sound.egg"; + Sound["AWAY_ACTIVATED"] = "away_activated"; + Sound["AWAY_DEACTIVATED"] = "away_deactivated"; + Sound["CONNECTION_CONNECTED"] = "connection.connected"; + Sound["CONNECTION_DISCONNECTED"] = "connection.disconnected"; + Sound["CONNECTION_BANNED"] = "connection.banned"; + Sound["CONNECTION_DISCONNECTED_TIMEOUT"] = "connection.disconnected.timeout"; + Sound["CONNECTION_REFUSED"] = "connection.refused"; + Sound["SERVER_EDITED"] = "server.edited"; + Sound["SERVER_EDITED_SELF"] = "server.edited.self"; + Sound["SERVER_KICKED"] = "server.kicked"; + Sound["CHANNEL_CREATED"] = "channel.created"; + Sound["CHANNEL_MOVED"] = "channel.moved"; + Sound["CHANNEL_EDITED"] = "channel.edited"; + Sound["CHANNEL_EDITED_SELF"] = "channel.edited.self"; + Sound["CHANNEL_DELETED"] = "channel.deleted"; + Sound["CHANNEL_JOINED"] = "channel.joined"; + Sound["CHANNEL_KICKED"] = "channel.kicked"; + Sound["USER_MOVED"] = "user.moved"; + Sound["USER_MOVED_SELF"] = "user.moved.self"; + Sound["USER_POKED_SELF"] = "user.poked.self"; + Sound["USER_BANNED"] = "user.banned"; + Sound["USER_ENTERED"] = "user.joined"; + Sound["USER_ENTERED_MOVED"] = "user.joined.moved"; + Sound["USER_ENTERED_KICKED"] = "user.joined.kicked"; + Sound["USER_ENTERED_CONNECT"] = "user.joined.connect"; + Sound["USER_LEFT"] = "user.left"; + Sound["USER_LEFT_MOVED"] = "user.left.moved"; + Sound["USER_LEFT_KICKED_CHANNEL"] = "user.left.kicked.server"; + Sound["USER_LEFT_KICKED_SERVER"] = "user.left.kicked.channel"; + Sound["USER_LEFT_DISCONNECT"] = "user.left.disconnect"; + Sound["USER_LEFT_BANNED"] = "user.left.banned"; + Sound["ERROR_INSUFFICIENT_PERMISSIONS"] = "error.insufficient_permissions"; + Sound["MESSAGE_SEND"] = "message.send"; + Sound["MESSAGE_RECEIVED"] = "message.received"; + Sound["GROUP_SERVER_ASSIGNED"] = "group.server.assigned"; + Sound["GROUP_SERVER_REVOKED"] = "group.server.revoked"; + Sound["GROUP_CHANNEL_CHANGED"] = "group.channel.changed"; + Sound["GROUP_SERVER_ASSIGNED_SELF"] = "group.server.assigned.self"; + Sound["GROUP_SERVER_REVOKED_SELF"] = "group.server.revoked.self"; + Sound["GROUP_CHANNEL_CHANGED_SELF"] = "group.channel.changed.self"; +})(Sound || (Sound = {})); +var sound; +(function (sound_1) { + let warned = false; + let speech_mapping = {}; + let volume_require_save = false; + let speech_volume = {}; + let master_volume; + let overlap_sounds; + let ignore_muted; + let master_mixed; + function register_sound(key, file) { + speech_mapping[key] = { key: key, filename: file }; + } + function get_sound_volume(sound, default_volume) { + let result = speech_volume[sound]; + if (typeof (result) === "undefined") { + if (typeof (default_volume) !== "undefined") + result = default_volume; + else + result = 1; + } + return result; + } + sound_1.get_sound_volume = get_sound_volume; + function set_sound_volume(sound, volume) { + volume_require_save = volume_require_save || speech_volume[sound] != volume; + speech_volume[sound] = volume == 1 ? undefined : volume; + } + sound_1.set_sound_volume = set_sound_volume; + function get_master_volume() { + return master_volume; + } + sound_1.get_master_volume = get_master_volume; + function set_master_volume(volume) { + volume_require_save = volume_require_save || master_volume != volume; + master_volume = volume; + if (master_mixed.gain.setValueAtTime) + master_mixed.gain.setValueAtTime(volume, 0); + else + master_mixed.gain.value = volume; + } + sound_1.set_master_volume = set_master_volume; + function overlap_activated() { + return overlap_sounds; + } + sound_1.overlap_activated = overlap_activated; + function set_overlap_activated(flag) { + volume_require_save = volume_require_save || overlap_sounds != flag; + overlap_sounds = flag; + } + sound_1.set_overlap_activated = set_overlap_activated; + function ignore_output_muted() { + return ignore_muted; + } + sound_1.ignore_output_muted = ignore_output_muted; + function set_ignore_output_muted(flag) { + volume_require_save = volume_require_save || ignore_muted != flag; + ignore_muted = flag; + } + sound_1.set_ignore_output_muted = set_ignore_output_muted; + function reinitialisize_audio() { + const context = audio.player.context(); + const destination = audio.player.destination(); + if (master_mixed) + master_mixed.disconnect(); + master_mixed = context.createGain(); + if (master_mixed.gain.setValueAtTime) + master_mixed.gain.setValueAtTime(master_volume, 0); + else + master_mixed.gain.value = master_volume; + master_mixed.connect(destination); + } + sound_1.reinitialisize_audio = reinitialisize_audio; + function save() { + if (volume_require_save) { + volume_require_save = false; + const data = {}; + data.version = 1; + for (const sound in Sound) { + if (typeof (speech_volume[sound]) !== "undefined") + data[sound] = speech_volume[sound]; + } + data.master = master_volume; + data.overlap = overlap_sounds; + data.ignore_muted = ignore_muted; + settings.changeGlobal("sound_volume", JSON.stringify(data)); + console.error(data); + } + } + sound_1.save = save; + function initialize() { + $.ajaxSetup({ + beforeSend: function (jqXHR, settings) { + if (settings.dataType === 'binary') { + settings.xhr().responseType = 'arraybuffer'; + settings.processData = false; + } + } + }); + /* volumes */ + { + const data = JSON.parse(settings.static_global("sound_volume", "{}")); + for (const sound in Sound) { + if (typeof (data[sound]) !== "undefined") + speech_volume[sound] = data[sound]; + } + console.error(data); + master_volume = data.master || 1; + overlap_sounds = data.overlap || true; + ignore_muted = data.ignore_muted || true; + } + register_sound("message.received", "effects/message_received.wav"); + register_sound("message.send", "effects/message_send.wav"); + audio.player.on_ready(reinitialisize_audio); + return new Promise(resolve => { + $.ajax({ + url: "audio/speech/mapping.json", + success: response => { + if (typeof (response) === "string") + response = JSON.parse(response); + for (const entry of response) + register_sound(entry.key, "speech/" + entry.file); + resolve(); + }, + error: () => { + console.log("error!"); + console.dir(...arguments); + }, + timeout: 5000, + async: true, + type: 'GET' + }); + }); + } + sound_1.initialize = initialize; + function play(sound, options) { + if (!options) { + options = {}; + } + const file = speech_mapping[sound]; + if (!file) { + console.warn(_translations.SHOob1ET || (_translations.SHOob1ET = tr("Missing sound %o")), sound); + return; + } + if (file.not_supported) { + if (!file.not_supported_timeout || Date.now() < file.not_supported_timeout) //Test if the not supported isn't may timeouted + return; + file.not_supported = false; + file.not_supported_timeout = undefined; + } + const path = "audio/" + file.filename; + const context = audio.player.context(); + if (!context) { + console.warn(_translations.qc1lS3zj || (_translations.qc1lS3zj = tr("Tried to replay a sound without an audio context (Sound: %o). Dropping playback")), sound); + return; + } + const volume = get_sound_volume(sound, options.default_volume); + console.log(_translations.NYKnfWD9 || (_translations.NYKnfWD9 = tr("Replaying sound %s (Sound volume: %o | Master volume %o)")), sound, volume, master_volume); + if (volume == 0) + return; + if (master_volume == 0) + return; + if (!options.ignore_muted && !ignore_muted && globalClient.controlBar.muteOutput) + return; + if (context.decodeAudioData) { + if (file.cached) { + if (!options.ignore_overlap && file.replaying && !overlap_sounds) { + console.log(_translations.TedPjWue || (_translations.TedPjWue = tr("Dropping requested playback for sound %s because it would overlap.")), sound); + return; + } + console.log(_translations.MLBuwnWd || (_translations.MLBuwnWd = tr("Using cached buffer: %o")), file.cached); + const player = context.createBufferSource(); + player.buffer = file.cached; + player.start(0); + file.replaying = true; + player.onended = event => { + file.replaying = false; + }; + if (volume != 1 && context.createGain) { + const gain = context.createGain(); + if (gain.gain.setValueAtTime) + gain.gain.setValueAtTime(volume, 0); + else + gain.gain.value = volume; + player.connect(gain); + gain.connect(master_mixed); + } + else { + player.connect(master_mixed); + } + } + else { + const decode_data = buffer => { + console.log(buffer); + try { + console.log(_translations.nZCjUk0f || (_translations.nZCjUk0f = tr("Decoding data"))); + context.decodeAudioData(buffer, result => { + console.log(_translations.gELGE4Pb || (_translations.gELGE4Pb = tr("Got decoded data"))); + file.cached = result; + play(sound, options); + }, error => { + console.error(_translations.PgjiBh_8 || (_translations.PgjiBh_8 = tr("Failed to decode audio data for %o")), sound); + console.error(error); + file.not_supported = true; + file.not_supported_timeout = Date.now() + 1000 * 60 * 60; //Try in 2min again! + }); + } + catch (error) { + console.error(error); + file.not_supported = true; + file.not_supported_timeout = Date.now() + 1000 * 60 * 60; //Try in 2min again! + } + }; + const xhr = new XMLHttpRequest(); + xhr.open('GET', path, true); + xhr.responseType = 'arraybuffer'; + xhr.onload = function (e) { + if (this.status == 200) { + decode_data(this.response); + } + else { + console.error(_translations.qC2EsMD0 || (_translations.qC2EsMD0 = tr("Failed to load audio file. (Response code %o)")), this.status); + file.not_supported = true; + file.not_supported_timeout = Date.now() + 1000 * 60 * 60; //Try in 2min again! + } + }; + xhr.onerror = error => { + console.error(_translations.PejUdLLE || (_translations.PejUdLLE = tr("Failed to load audio file ")), sound); + console.error(error); + file.not_supported = true; + file.not_supported_timeout = Date.now() + 1000 * 60 * 60; //Try in 2min again! + }; + xhr.send(); + } + } + else { + console.log(_translations.m7VfH0cA || (_translations.m7VfH0cA = tr("Replaying %s")), path); + if (file.node) { + file.node.currentTime = 0; + file.node.play(); + } + else { + if (!warned) { + warned = true; + console.warn(_translations._RK0Gxtx || (_translations._RK0Gxtx = tr("Your browser does not support decodeAudioData! Using a node to playback! This bypasses the audio output and volume regulation!"))); + } + const container = $("#sounds"); + const node = $.spawn("audio").attr("src", path); + node.appendTo(container); + file.node = node[0]; + file.node.play(); + } + } + } + sound_1.play = play; +})(sound || (sound = {})); +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["3faa3b45f66fbf63bdd5516c889adf8619e6831641d9f1f7994437998b6910d7"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["3faa3b45f66fbf63bdd5516c889adf8619e6831641d9f1f7994437998b6910d7"] = "3faa3b45f66fbf63bdd5516c889adf8619e6831641d9f1f7994437998b6910d7"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of []) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +if (!$.fn.dividerfy) { + $.fn.dividerfy = function () { + this.find(".container-seperator").each(function () { + if (!this.previousElementSibling) + return; + if (!this.nextElementSibling) + return; + const element = $(this); + const parent_element = $(this.parentElement); + const previous_element = $(this.previousElementSibling); + const next_element = $(this.nextElementSibling); + const seperator_id = element.attr("seperator-id"); + const vertical = element.hasClass("vertical"); + const apply_view = (property, previous, next) => { + previous_element.css(property, "calc(" + previous + "% - " + (vertical ? element.width() : element.height()) + "px)"); + next_element.css(property, "calc(" + next + "% - " + (vertical ? element.width() : element.height()) + "px)"); + }; + const listener_move = (event) => { + const parent_offset = parent_element.offset(); + const min = vertical ? parent_offset.left : parent_offset.top; + const max = vertical ? parent_offset.left + parent_element.width() : parent_offset.top + parent_element.height(); + const current = event instanceof MouseEvent ? + (vertical ? event.pageX : event.pageY) : + (vertical ? event.touches[event.touches.length - 1].clientX : event.touches[event.touches.length - 1].clientY); + /* + const previous_offset = previous_element.offset(); + const next_offset = next_element.offset(); + + const min = vertical ? Math.min(previous_offset.left, next_offset.left) : Math.min(previous_offset.top, next_offset.top); + const max = vertical ? + Math.max(previous_offset.left + previous_element.width(), next_offset.left + next_element.width()) : + Math.max(previous_offset.top + previous_element.height(), next_offset.top + next_element.height()); + */ + let previous = 0; + let next = 0; + if (current < min) { + previous = 0; + next = 1; + } + else if (current < max) { + const x_offset = current - min; + const x_offset_max = max - min; + previous = x_offset / x_offset_max; + next = 1 - previous; + } + else { + previous = 1; + next = 0; + } + const property = vertical ? "width" : "height"; + const previous_p = Math.ceil(previous * 100); + const next_p = Math.ceil(next * 100); + apply_view(property, previous_p, next_p); + if (seperator_id) + settings.changeGlobal("seperator-settings-" + seperator_id, JSON.stringify({ + previous: previous_p, + next: next_p, + property: property + })); + }; + const listener_up = (event) => { + document.removeEventListener('mousemove', listener_move); + document.removeEventListener('touchmove', listener_move); + document.removeEventListener('mouseup', listener_up); + document.removeEventListener('touchend', listener_up); + document.removeEventListener('touchcancel', listener_up); + $(document.documentElement).css("user-select", ""); + element.removeClass("seperator-selected"); + }; + element.on('mousedown', () => { + document.addEventListener('mousemove', listener_move); + document.addEventListener('touchmove', listener_move); + document.addEventListener('mouseup', listener_up); + document.addEventListener('touchend', listener_up); + document.addEventListener('touchcancel', listener_up); + $(document.documentElement).css("user-select", "none"); + element.addClass("seperator-selected"); + }); + element.on('touchstart', () => { + element.trigger('mousedown'); + }); + if (seperator_id) { + try { + const config = JSON.parse(settings.global("seperator-settings-" + seperator_id)); + if (config) { + console.log("Apply previous changed: %o", config); + apply_view(config.property, config.previous, config.next); + } + } + catch (e) { + if (!(e instanceof SyntaxError)) + console.error(e); + } + } + }); + return this; + }; +} +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["975d14defd03581dc3938c23723a34d79728dafafa0e7060c8e6a3266031b34c"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["975d14defd03581dc3938c23723a34d79728dafafa0e7060c8e6a3266031b34c"] = "975d14defd03581dc3938c23723a34d79728dafafa0e7060c8e6a3266031b34c"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of []) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +var htmltags; +(function (htmltags) { + let mouse_coordinates = { x: 0, y: 0 }; + function initialize() { + document.addEventListener('mousemove', event => { + mouse_coordinates.x = event.pageX; + mouse_coordinates.y = event.pageY; + }); + } + initialize(); + /* required for the bbcodes */ + function generate_client_open(properties) { + let result = ""; + /* build the opening tag:
    */ + result = result + "
    "; + return result; + } + function generate_client(properties) { + let result = generate_client_open(properties); + /* content */ + { + if (properties.add_braces) + result = result + "\""; + result = result + MessageHelper.htmlEscape(properties.client_name || "undefined").join(" "); + if (properties.add_braces) + result = result + "\""; + } + /* close tag */ + { + result += "
    "; + } + return result; + } + htmltags.generate_client = generate_client; + /* required for the bbcodes */ + function generate_channel_open(properties) { + let result = ""; + /* build the opening tag:
    */ + result = result + "
    "; + return result; + } + function generate_channel(properties) { + let result = generate_channel_open(properties); + /* content */ + { + if (properties.add_braces) + result = result + "\""; + result = result + MessageHelper.htmlEscape(properties.channel_display_name || properties.channel_name || "undefined").join(" "); + if (properties.add_braces) + result = result + "\""; + } + /* close tag */ + { + result += "
    "; + } + return result; + } + htmltags.generate_channel = generate_channel; + let callbacks; + (function (callbacks) { + function callback_context_client(element) { + const client_id = parseInt(element.attr("client-id") || "0"); + const client_unique_id = decodeURIComponent(element.attr("client-unique-id") || ""); + /* we ignore the name, we cant find clients by name because the name is too volatile*/ + let client; + if (globalClient && globalClient.channelTree) { + if (!client && client_id) { + client = globalClient.channelTree.findClient(client_id); + if (client && (client_unique_id && client.properties.client_unique_identifier != client_unique_id)) { + client = undefined; /* client id dosn't match anymore, lets search for the unique id */ + } + } + if (!client && client_unique_id) + client = globalClient.channelTree.find_client_by_unique_id(client_unique_id); + } + if (!client) { + /* we may should open a "offline" menu? */ + log.debug(LogCategory.GENERAL, "Failed to resolve client from html tag. Client id: %o, Client unique id: %o, Client name: %o", client_id, client_unique_id, decodeURIComponent(element.attr("client-name"))); + return false; + } + client.showContextMenu(mouse_coordinates.x, mouse_coordinates.y); + return false; + } + callbacks.callback_context_client = callback_context_client; + function callback_context_channel(element) { + const channel_id = parseInt(element.attr("channel-id") || "0"); + let channel; + if (globalClient && globalClient.channelTree) { + channel = globalClient.channelTree.findChannel(channel_id); + } + if (!channel) + return false; + channel.showContextMenu(mouse_coordinates.x, mouse_coordinates.y); + return false; + } + callbacks.callback_context_channel = callback_context_channel; + })(callbacks = htmltags.callbacks || (htmltags.callbacks = {})); + let bbcodes; + (function (bbcodes) { + /* the = because we sometimes get that */ + //const url_client_regex = /(?:=)?client:\/\/(?[0-9]+)\/(?[a-zA-Z0-9+=#]+)~(?(?:[^%]|%[0-9A-Fa-f]{2})+)$/g; + const url_client_regex = /(?:=)?client:\/\/([0-9]+)\/([a-zA-Z0-9+=/#]+)~((?:[^%]|%[0-9A-Fa-f]{2})+)$/g; /* IDK which browsers already support group naming */ + const url_channel_regex = /(?:=)?channel:\/\/([0-9]+)~((?:[^%]|%[0-9A-Fa-f]{2})+)$/g; + function initialize() { + const origin_url = XBBCODE.tags()["url"]; + XBBCODE.addTags({ + function: { + openTag: (params, content) => { + if (params) { + if (params.match(url_channel_regex)) { + const groups = url_channel_regex.exec(params); + return generate_channel_open({ + add_braces: false, + channel_id: parseInt(groups[1]), + channel_name: decodeURIComponent(groups[2]) + }); + } + else if (params.match(url_client_regex)) { + const groups = url_client_regex.exec(params); + return generate_client_open({ + add_braces: false, + client_id: parseInt(groups[1]), + client_unique_id: groups[2], + client_name: decodeURIComponent(groups[3]) + }); + } + } + return origin_url.openTag(params, content); + }, + closeTag: (params, content) => { + if (params) { + if (params.match(url_client_regex)) + return "
    "; + if (params.match(url_channel_regex)) + return "
    "; + } + return origin_url.closeTag(params, content); + } + }, + tag: "url" + }); + /* + "img": { + openTag: function(params,content) { + let myUrl; + + if (!params) { + myUrl = content.replace(/<.*?>/g,""); + } else { + myUrl = params.substr(1); + } + + urlPattern.lastIndex = 0; + if ( !urlPattern.test( myUrl ) ) { + myUrl = "#"; + } + + return ''; + }, + closeTag: function(params,content) { + return ''; + } + }, + */ + } + initialize(); + })(bbcodes || (bbcodes = {})); +})(htmltags || (htmltags = {})); +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["181f59474ad585434f2f8cd33a37ee29d4292be2ee59cc5b1bde6d8417448949"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["181f59474ad585434f2f8cd33a37ee29d4292be2ee59cc5b1bde6d8417448949"] = "181f59474ad585434f2f8cd33a37ee29d4292be2ee59cc5b1bde6d8417448949"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of []) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +/// +var Modals; +(function (Modals) { + function createServerModal(server, callback) { + let properties = {}; //The changes properties + const modal_template = $("#tmpl_server_edit").renderTag(server.properties); + const modal = modal_template.modalize((header, body, footer) => { + return { + body: body.tabify() + }; + }); + server_applyGeneralListener(properties, modal.htmlTag.find(".properties_general"), modal.htmlTag.find(".button_ok")); + server_applyTransferListener(properties, server, modal.htmlTag.find('.properties_transfer')); + server_applyHostListener(server, properties, server.properties, modal.htmlTag.find(".properties_host"), modal.htmlTag.find(".button_ok")); + server_applyMessages(properties, server, modal.htmlTag.find(".properties_messages")); + server_applyFlood(properties, server, modal.htmlTag.find(".properties_flood")); + server_applySecurity(properties, server, modal.htmlTag.find(".properties_security")); + server_applyMisc(properties, server, modal.htmlTag.find(".properties_misc")); + modal.htmlTag.find(".button_ok").click(() => { + modal.close(); + callback(properties); //First may create the channel + }); + modal.htmlTag.find(".button_cancel").click(() => { + modal.close(); + callback(); + }); + modal.open(); + } + Modals.createServerModal = createServerModal; + function server_applyGeneralListener(properties, tag, button) { + let updateButton = () => { + if (tag.find(".input_error").length == 0) + button.removeAttr("disabled"); + else + button.attr("disabled", "true"); + }; + tag.find(".virtualserver_name").change(function () { + properties.virtualserver_name = this.value; + $(this).removeClass("input_error"); + if (this.value.length < 1 || this.value.length > 70) + $(this).addClass("input_error"); + updateButton(); + }).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_MODIFY_NAME).granted(1)); + tag.find(".virtualserver_name_phonetic").change(function () { + properties.virtualserver_name_phonetic = this.value; + }).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_MODIFY_NAME).granted(1)); + tag.find(".virtualserver_password").change(function () { + properties.virtualserver_flag_password = this.value.length != 0; + if (properties.virtualserver_flag_password) + helpers.hashPassword(this.value).then(pass => properties.virtualserver_password = pass); + $(this).removeClass("input_error"); + if (!properties.virtualserver_flag_password) + if (globalClient.permissions.neededPermission(PermissionType.B_CHANNEL_CREATE_MODIFY_WITH_FORCE_PASSWORD).granted(1)) + $(this).addClass("input_error"); + updateButton(); + }).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_MODIFY_PASSWORD).granted(1)); + tag.find(".virtualserver_maxclients").change(function () { + properties.virtualserver_maxclients = this.valueAsNumber; + }).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_MODIFY_MAXCLIENTS).granted(1)); + tag.find(".virtualserver_reserved_slots").change(function () { + properties.virtualserver_reserved_slots = this.valueAsNumber; + $(this).removeClass("input_error"); + if (this.valueAsNumber > properties.virtualserver_maxclients) + $(this).addClass("input_error"); + updateButton(); + }).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_MODIFY_RESERVED_SLOTS).granted(1)); + tag.find(".virtualserver_welcomemessage").change(function () { + properties.virtualserver_welcomemessage = this.value; + }).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_MODIFY_WELCOMEMESSAGE).granted(1)); + } + function server_applyHostListener(server, properties, original_properties, tag, button) { + tag.find(".virtualserver_host").change(function () { + properties.virtualserver_host = this.value; + }).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_MODIFY_HOST).granted(1)); + tag.find(".virtualserver_port").change(function () { + properties.virtualserver_port = this.valueAsNumber; + }).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_MODIFY_PORT).granted(1)); + tag.find(".virtualserver_hostmessage").change(function () { + properties.virtualserver_hostmessage = this.value; + }).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_MODIFY_HOSTMESSAGE).granted(1)); + tag.find(".virtualserver_hostmessage_mode").change(function () { + properties.virtualserver_hostmessage_mode = this.selectedIndex; + }).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_MODIFY_HOSTMESSAGE).granted(1)) + .find("option").eq(original_properties.virtualserver_hostmessage_mode).prop('selected', true); + tag.find(".virtualserver_hostbanner_url").change(function () { + properties.virtualserver_hostbanner_url = this.value; + }).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_MODIFY_HOSTBANNER).granted(1)); + tag.find(".virtualserver_hostbanner_gfx_url").change(function () { + properties.virtualserver_hostbanner_gfx_url = this.value; + }).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_MODIFY_HOSTBANNER).granted(1)); + tag.find(".virtualserver_hostbanner_gfx_interval").change(function () { + properties.virtualserver_hostbanner_gfx_interval = this.valueAsNumber; + }).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_MODIFY_HOSTBANNER).granted(1)); + tag.find(".virtualserver_hostbanner_mode").change(function () { + properties.virtualserver_hostbanner_mode = this.selectedIndex; + }).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_MODIFY_HOSTMESSAGE).granted(1)) + .find("option").eq(original_properties.virtualserver_hostbanner_mode).prop('selected', true); + tag.find(".virtualserver_hostbutton_tooltip").change(function () { + properties.virtualserver_hostbutton_tooltip = this.value; + }).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_MODIFY_HOSTBUTTON).granted(1)); + tag.find(".virtualserver_hostbutton_url").change(function () { + properties.virtualserver_hostbutton_url = this.value; + }).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_MODIFY_HOSTBUTTON).granted(1)); + tag.find(".virtualserver_hostbutton_gfx_url").change(function () { + properties.virtualserver_hostbutton_gfx_url = this.value; + }).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_MODIFY_HOSTBUTTON).granted(1)); + server.updateProperties().then(() => { + tag.find(".virtualserver_host").val(server.properties.virtualserver_host); + tag.find(".virtualserver_port").val(server.properties.virtualserver_port); + }); + } + function server_applyMessages(properties, server, tag) { + server.updateProperties().then(() => { + tag.find(".virtualserver_default_client_description").val(server.properties.virtualserver_default_client_description); + tag.find(".virtualserver_default_channel_description").val(server.properties.virtualserver_default_channel_description); + tag.find(".virtualserver_default_channel_topic").val(server.properties.virtualserver_default_channel_topic); + }); + tag.find(".virtualserver_default_client_description").change(function () { + properties.virtualserver_default_client_description = this.value; + }).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_MODIFY_DEFAULT_MESSAGES).granted(1)); + tag.find(".virtualserver_default_channel_description").change(function () { + properties.virtualserver_default_channel_description = this.value; + }).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_MODIFY_DEFAULT_MESSAGES).granted(1)); + tag.find(".virtualserver_default_channel_topic").change(function () { + properties.virtualserver_default_channel_topic = this.value; + }).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_MODIFY_DEFAULT_MESSAGES).granted(1)); + } + function server_applyFlood(properties, server, tag) { + server.updateProperties().then(() => { + tag.find(".virtualserver_antiflood_points_tick_reduce").val(server.properties.virtualserver_antiflood_points_tick_reduce); + tag.find(".virtualserver_antiflood_points_needed_command_block").val(server.properties.virtualserver_antiflood_points_needed_command_block); + tag.find(".virtualserver_antiflood_points_needed_ip_block").val(server.properties.virtualserver_antiflood_points_needed_ip_block); + }); + tag.find(".virtualserver_antiflood_points_tick_reduce").change(function () { + properties.virtualserver_antiflood_points_tick_reduce = this.valueAsNumber; + }).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_MODIFY_ANTIFLOOD).granted(1)); + tag.find(".virtualserver_antiflood_points_needed_command_block").change(function () { + properties.virtualserver_antiflood_points_needed_command_block = this.valueAsNumber; + }).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_MODIFY_ANTIFLOOD).granted(1)); + tag.find(".virtualserver_antiflood_points_needed_ip_block").change(function () { + properties.virtualserver_antiflood_points_needed_ip_block = this.valueAsNumber; + }).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_MODIFY_ANTIFLOOD).granted(1)); + } + function server_applySecurity(properties, server, tag) { + server.updateProperties().then(() => { + tag.find(".virtualserver_needed_identity_security_level").val(server.properties.virtualserver_needed_identity_security_level); + }); + tag.find(".virtualserver_needed_identity_security_level").change(function () { + properties.virtualserver_needed_identity_security_level = this.valueAsNumber; + }).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_MODIFY_NEEDED_IDENTITY_SECURITY_LEVEL).granted(1)); + tag.find(".virtualserver_codec_encryption_mode").change(function () { + properties.virtualserver_codec_encryption_mode = this.selectedIndex; + }).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_MODIFY_ANTIFLOOD).granted(1)) + .find("option").eq(server.properties.virtualserver_codec_encryption_mode).prop('selected', true); + } + function server_applyMisc(properties, server, tag) { + { //TODO notify on tmp channeladmin group and vice versa + { + let groups_tag = tag.find(".default_server_group"); + groups_tag.change(function () { + properties.virtualserver_default_server_group = parseInt($(this.item(this.selectedIndex)).attr("group-id")); + }); + for (let group of server.channelTree.client.groups.serverGroups.sort(GroupManager.sorter())) { + if (group.type != 2) + continue; + let group_tag = $.spawn("option").text(group.name + " [" + (group.properties.savedb ? "perm" : "tmp") + "]").attr("group-id", group.id); + if (group.id == server.properties.virtualserver_default_server_group) + group_tag.prop("selected", true); + group_tag.appendTo(groups_tag); + } + } + { + let groups_tag = tag.find(".default_music_group"); + groups_tag.change(function () { + properties.virtualserver_default_music_group = parseInt($(this.item(this.selectedIndex)).attr("group-id")); + }); + for (let group of server.channelTree.client.groups.serverGroups.sort(GroupManager.sorter())) { + if (group.type != 2) + continue; + let group_tag = $.spawn("option").text(group.name + " [" + (group.properties.savedb ? "perm" : "tmp") + "]").attr("group-id", group.id); + if (group.id == server.properties.virtualserver_default_music_group) + group_tag.prop("selected", true); + group_tag.appendTo(groups_tag); + } + } + { + let groups_tag = tag.find(".default_channel_group"); + groups_tag.change(function () { + properties.virtualserver_default_channel_group = parseInt($(this.item(this.selectedIndex)).attr("group-id")); + }); + for (let group of server.channelTree.client.groups.channelGroups.sort(GroupManager.sorter())) { + if (group.type != 2) + continue; + let group_tag = $.spawn("option").text(group.name + " [" + (group.properties.savedb ? "perm" : "tmp") + "]").attr("group-id", group.id); + if (group.id == server.properties.virtualserver_default_channel_group) + group_tag.prop("selected", true); + group_tag.appendTo(groups_tag); + } + } + { + let groups_tag = tag.find(".default_channel_admin_group"); + groups_tag.change(function () { + properties.virtualserver_default_channel_admin_group = parseInt($(this.item(this.selectedIndex)).attr("group-id")); + }); + for (let group of server.channelTree.client.groups.channelGroups.sort(GroupManager.sorter())) { + if (group.type != 2) + continue; + let group_tag = $.spawn("option").text(group.name + " [" + (group.properties.savedb ? "perm" : "tmp") + "]").attr("group-id", group.id); + if (group.id == server.properties.virtualserver_default_channel_admin_group) + group_tag.prop("selected", true); + group_tag.appendTo(groups_tag); + } + } + } + server.updateProperties().then(() => { + //virtualserver_antiflood_points_needed_ip_block + //virtualserver_antiflood_points_needed_command_block + //virtualserver_antiflood_points_tick_reduce + //virtualserver_complain_autoban_count + //virtualserver_complain_autoban_time + //virtualserver_complain_remove_time + tag.find(".virtualserver_antiflood_points_needed_ip_block").val(server.properties.virtualserver_antiflood_points_needed_ip_block); + tag.find(".virtualserver_antiflood_points_needed_command_block").val(server.properties.virtualserver_antiflood_points_needed_command_block); + tag.find(".virtualserver_antiflood_points_tick_reduce").val(server.properties.virtualserver_antiflood_points_tick_reduce); + tag.find(".virtualserver_complain_autoban_count").val(server.properties.virtualserver_complain_autoban_count); + tag.find(".virtualserver_complain_autoban_time").val(server.properties.virtualserver_complain_autoban_time); + tag.find(".virtualserver_complain_remove_time").val(server.properties.virtualserver_complain_remove_time); + tag.find(".virtualserver_weblist_enabled").prop("checked", server.properties.virtualserver_weblist_enabled); + }); + tag.find(".virtualserver_antiflood_points_needed_ip_block").change(function () { + properties.virtualserver_antiflood_points_needed_ip_block = this.valueAsNumber; + }).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_MODIFY_ANTIFLOOD).granted(1)); + tag.find(".virtualserver_antiflood_points_needed_command_block").change(function () { + properties.virtualserver_antiflood_points_needed_command_block = this.valueAsNumber; + }).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_MODIFY_ANTIFLOOD).granted(1)); + tag.find(".virtualserver_antiflood_points_tick_reduce").change(function () { + properties.virtualserver_antiflood_points_tick_reduce = this.valueAsNumber; + }).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_MODIFY_ANTIFLOOD).granted(1)); + tag.find(".virtualserver_complain_autoban_count").change(function () { + properties.virtualserver_complain_autoban_count = this.valueAsNumber; + }).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_MODIFY_COMPLAIN).granted(1)); + tag.find(".virtualserver_complain_autoban_time").change(function () { + properties.virtualserver_complain_autoban_time = this.valueAsNumber; + }).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_MODIFY_COMPLAIN).granted(1)); + tag.find(".virtualserver_complain_remove_time").change(function () { + properties.virtualserver_complain_remove_time = this.valueAsNumber; + }).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_MODIFY_COMPLAIN).granted(1)); + tag.find(".virtualserver_weblist_enabled").change(function () { + properties.virtualserver_weblist_enabled = $(this).prop("checked"); + }).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_MODIFY_WEBLIST).granted(1)); + } + function server_applyTransferListener(properties, server, tag) { + server.updateProperties().then(() => { + //virtualserver_max_upload_total_bandwidth + //virtualserver_upload_quota + //virtualserver_max_download_total_bandwidth + //virtualserver_download_quota + tag.find(".virtualserver_max_upload_total_bandwidth").val(server.properties.virtualserver_max_upload_total_bandwidth); + tag.find(".virtualserver_upload_quota").val(server.properties.virtualserver_upload_quota); + tag.find(".virtualserver_max_download_total_bandwidth").val(server.properties.virtualserver_max_download_total_bandwidth); + tag.find(".virtualserver_download_quota").val(server.properties.virtualserver_download_quota); + }); + tag.find(".virtualserver_max_upload_total_bandwidth").change(function () { + properties.virtualserver_max_upload_total_bandwidth = this.valueAsNumber; + }).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_MODIFY_FT_SETTINGS).granted(1)); + tag.find(".virtualserver_max_download_total_bandwidth").change(function () { + properties.virtualserver_max_download_total_bandwidth = this.valueAsNumber; + }).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_MODIFY_FT_SETTINGS).granted(1)); + tag.find(".virtualserver_upload_quota").change(function () { + properties.virtualserver_upload_quota = this.valueAsNumber; + }).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_MODIFY_FT_QUOTAS).granted(1)); + tag.find(".virtualserver_download_quota").change(function () { + properties.virtualserver_download_quota = this.valueAsNumber; + }).prop("disabled", !globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_MODIFY_FT_QUOTAS).granted(1)); + } +})(Modals || (Modals = {})); +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["bd101f06474d59265da4974b252292ddfa87f6897614905cd9c1a1ab78ae064b"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["bd101f06474d59265da4974b252292ddfa87f6897614905cd9c1a1ab78ae064b"] = "bd101f06474d59265da4974b252292ddfa87f6897614905cd9c1a1ab78ae064b"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "TyOggpDv", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/server.ts (141,23)" }, { name: "Yo2SjrmS", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/server.ts (144,54)" }, { name: "yOT7HTle", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/server.ts (145,37)" }, { name: "Nuoj6H9J", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/server.ts (155,23)" }, { name: "tgZqV628", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/server.ts (162,37)" }, { name: "CVdq81pa", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/server.ts (162,61)" }, { name: "RygJF9MZ", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/server.ts (162,102)" }, { name: "Zt0rvG9D", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/server.ts (170,70)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +/// +/// +class ServerProperties { + constructor() { + this.virtualserver_host = ""; + this.virtualserver_port = 0; + this.virtualserver_name = ""; + this.virtualserver_name_phonetic = ""; + this.virtualserver_icon_id = 0; + this.virtualserver_version = "unknown"; + this.virtualserver_platform = "unknown"; + this.virtualserver_unique_identifier = ""; + this.virtualserver_clientsonline = 0; + this.virtualserver_queryclientsonline = 0; + this.virtualserver_channelsonline = 0; + this.virtualserver_uptime = 0; + this.virtualserver_maxclients = 0; + this.virtualserver_reserved_slots = 0; + this.virtualserver_password = ""; + this.virtualserver_flag_password = false; + this.virtualserver_welcomemessage = ""; + this.virtualserver_hostmessage = ""; + this.virtualserver_hostmessage_mode = 0; + this.virtualserver_hostbanner_url = ""; + this.virtualserver_hostbanner_gfx_url = ""; + this.virtualserver_hostbanner_gfx_interval = 0; + this.virtualserver_hostbanner_mode = 0; + this.virtualserver_hostbutton_tooltip = ""; + this.virtualserver_hostbutton_url = ""; + this.virtualserver_hostbutton_gfx_url = ""; + this.virtualserver_codec_encryption_mode = 0; + this.virtualserver_default_music_group = 0; + this.virtualserver_default_server_group = 0; + this.virtualserver_default_channel_group = 0; + this.virtualserver_default_channel_admin_group = 0; + //Special requested properties + this.virtualserver_default_client_description = ""; + this.virtualserver_default_channel_description = ""; + this.virtualserver_default_channel_topic = ""; + this.virtualserver_antiflood_points_tick_reduce = 0; + this.virtualserver_antiflood_points_needed_command_block = 0; + this.virtualserver_antiflood_points_needed_ip_block = 0; + this.virtualserver_complain_autoban_count = 0; + this.virtualserver_complain_autoban_time = 0; + this.virtualserver_complain_remove_time = 0; + this.virtualserver_needed_identity_security_level = 8; + this.virtualserver_weblist_enabled = false; + this.virtualserver_min_clients_in_channel_before_forced_silence = 0; + this.virtualserver_max_upload_total_bandwidth = 0; + this.virtualserver_upload_quota = 0; + this.virtualserver_max_download_total_bandwidth = 0; + this.virtualserver_download_quota = 0; + } +} +class ServerEntry { + constructor(tree, name, address) { + this.info_request_promise = undefined; + this.info_request_promise_resolve = undefined; + this.info_request_promise_reject = undefined; + this.lastInfoRequest = 0; + this.nextInfoRequest = 0; + this.properties = new ServerProperties(); + this.channelTree = tree; + this.remote_address = address; + this.properties.virtualserver_name = name; + } + get htmlTag() { + if (this._htmlTag) + return this._htmlTag; + let tag = $.spawn("div").addClass("tree-entry server"); + tag.append($.spawn("div") + .addClass("server_type icon client-server_green")); + tag.append($.spawn("div") + .addClass("name") + .text(this.properties.virtualserver_name)); + tag.append($.spawn("div") + .addClass("icon_property icon_empty")); + return this._htmlTag = tag; + } + initializeListener() { + this._htmlTag.click(() => { + this.channelTree.onSelect(this); + }); + if (!settings.static(Settings.KEY_DISABLE_CONTEXT_MENU, false)) { + this.htmlTag.on("contextmenu", (event) => { + event.preventDefault(); + if ($.isArray(this.channelTree.currently_selected)) { //Multiselect + (this.channelTree.currently_selected_context_callback || ((_) => null))(event); + return; + } + this.channelTree.onSelect(this, true); + this.spawnContextMenu(event.pageX, event.pageY, () => { this.channelTree.onSelect(undefined, true); }); + }); + } + } + spawnContextMenu(x, y, on_close = () => { }) { + spawn_context_menu(x, y, { + type: MenuEntryType.ENTRY, + icon: "client-virtualserver_edit", + name: _translations.TyOggpDv || (_translations.TyOggpDv = tr("Edit")), + callback: () => { + Modals.createServerModal(this, properties => { + log.info(LogCategory.SERVER, _translations.Yo2SjrmS || (_translations.Yo2SjrmS = tr("Changing server properties %o")), properties); + console.log(_translations.yOT7HTle || (_translations.yOT7HTle = tr("Changed properties: %o")), properties); + if (properties) + this.channelTree.client.serverConnection.send_command("serveredit", properties).then(() => { + sound.play(Sound.SERVER_EDITED_SELF); + }); + }); + } + }, { + type: MenuEntryType.ENTRY, + icon: "client-invite_buddy", + name: _translations.Nuoj6H9J || (_translations.Nuoj6H9J = tr("Invite buddy")), + callback: () => { + const address = this.channelTree.client.serverConnection._remote_address.host + ":" + this.channelTree.client.serverConnection._remote_address.port; + const parameter = "connect_default=1&connect_address=" + encodeURIComponent(address); + const url = document.location.origin + document.location.pathname + "?" + parameter; + copy_to_clipboard(url); + createInfoModal(_translations.tgZqV628 || (_translations.tgZqV628 = tr("Buddy invite URL")), (_translations.CVdq81pa || (_translations.CVdq81pa = tr("Your buddy invite URL:
    "))) + url + (_translations.RygJF9MZ || (_translations.RygJF9MZ = tr("This has been copied to your clipboard.")))).open(); + } + }, MenuEntry.CLOSE(on_close)); + } + updateVariables(is_self_notify, ...variables) { + let group = log.group(log.LogType.DEBUG, LogCategory.SERVER, _translations.Zt0rvG9D || (_translations.Zt0rvG9D = tr("Update properties (%i)")), variables.length); + let update_bannner = false; + for (let variable of variables) { + JSON.map_field_to(this.properties, variable.value, variable.key); + //TODO tr + group.log("Updating server " + this.properties.virtualserver_name + ". Key " + variable.key + " Value: '" + variable.value + "' (" + typeof (this.properties[variable.key]) + ")"); + if (variable.key == "virtualserver_name") { + this.htmlTag.find(".name").text(variable.value); + } + else if (variable.key == "virtualserver_icon_id") { + if (this.channelTree.client.fileManager && this.channelTree.client.fileManager.icons) + this.htmlTag.find(".icon_property").replaceWith(this.channelTree.client.fileManager.icons.generateTag(this.properties.virtualserver_icon_id).addClass("icon_property")); + } + else if (variable.key.indexOf('hostbanner') != -1) { + update_bannner = true; + } + } + if (update_bannner) + this.channelTree.client.selectInfo.update_banner(); + group.end(); + if (is_self_notify && this.info_request_promise_resolve) { + this.info_request_promise_resolve(); + this.info_request_promise = undefined; + this.info_request_promise_reject = undefined; + this.info_request_promise_resolve = undefined; + } + } + updateProperties() { + if (this.info_request_promise && Date.now() - this.lastInfoRequest < 1000) + return this.info_request_promise; + this.lastInfoRequest = Date.now(); + this.nextInfoRequest = this.lastInfoRequest + 10 * 1000; + this.channelTree.client.serverConnection.send_command("servergetvariables").catch(error => { + this.info_request_promise_reject(error); + this.info_request_promise = undefined; + this.info_request_promise_reject = undefined; + this.info_request_promise_resolve = undefined; + }); + return this.info_request_promise = new Promise((resolve, reject) => { + this.info_request_promise_reject = reject; + this.info_request_promise_resolve = resolve; + }); + } + shouldUpdateProperties() { + return this.nextInfoRequest < Date.now(); + } + calculateUptime() { + if (this.properties.virtualserver_uptime == 0 || this.lastInfoRequest == 0) + return this.properties.virtualserver_uptime; + return this.properties.virtualserver_uptime + (new Date().getTime() - this.lastInfoRequest) / 1000; + } +} +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["1742a73c5bf1b2d3a9d4798e06f4425c2e0934554d549e8bfb1e7e451a1c9718"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["1742a73c5bf1b2d3a9d4798e06f4425c2e0934554d549e8bfb1e7e451a1c9718"] = "1742a73c5bf1b2d3a9d4798e06f4425c2e0934554d549e8bfb1e7e451a1c9718"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "EGKSrXTJ", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalBookmarks.ts (42,21)" }, { name: "w0cXvTxP", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalBookmarks.ts (92,37)" }, { name: "oZh862t4", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalBookmarks.ts (143,36)" }, { name: "Fo8Cfk6b", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalBookmarks.ts (143,57)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +/// +/// +var Modals; +(function (Modals) { + function bookmark_tag(callback_select, bookmark) { + const tag = $("#tmpl_manage_bookmarks-list_entry").renderTag({ + name: bookmark.display_name, + type: bookmark.type == bookmarks.BookmarkType.DIRECTORY ? "directory" : "bookmark" + }); + tag.find(".name").on('click', () => { + callback_select(bookmark, tag); + tag.addClass("selected"); + }); + if (bookmark.type == bookmarks.BookmarkType.DIRECTORY) { + const casted = bookmark; + for (const member of casted.content) + tag.find("> .members").append(bookmark_tag(callback_select, member)); + } + return tag; + } + function parent_tag(select_tag, prefix, bookmark) { + if (bookmark.type == bookmarks.BookmarkType.DIRECTORY) { + const casted = bookmark; + select_tag.append($.spawn("option") + .val(casted.unique_id) + .text(prefix + casted.display_name)); + for (const member of casted.content) + parent_tag(select_tag, prefix + " ", member); + } + } + function spawnBookmarkModal() { + let modal; + modal = createModal({ + header: _translations.EGKSrXTJ || (_translations.EGKSrXTJ = tr("Manage bookmarks")), + body: () => { + let template = $("#tmpl_manage_bookmarks").renderTag({}); + template = $.spawn("div").append(template); + let selected_bookmark; + let update_name; + const update_bookmarks = () => { + template.find(".list").empty(); + const callback_selected = (entry, tag) => { + template.find(".selected").removeClass("selected"); + if (selected_bookmark == entry) + return; + selected_bookmark = entry; + update_name = () => tag.find("> .name").text(entry.display_name); + template.find(".bookmark-setting").hide(); + template.find(".setting-bookmark-name").val(selected_bookmark.display_name); + if (selected_bookmark.type == bookmarks.BookmarkType.ENTRY) { + template.find(".bookmark-setting-bookmark").show(); + const casted = selected_bookmark; + const profile = profiles.find_profile(casted.connect_profile) || profiles.default_profile(); + template.find(".setting-bookmark-profile").val(profile.id); + template.find(".setting-server-host").val(casted.server_properties.server_address); + template.find(".setting-server-port").val(casted.server_properties.server_port); + template.find(".setting-server-password").val(casted.server_properties.server_password_hash || casted.server_properties.server_password); + template.find(".setting-username").val(casted.nickname); + template.find(".setting-channel").val(casted.default_channel); + template.find(".setting-channel-password").val(casted.default_channel_password_hash || casted.default_channel_password); + } + else { + template.find(".bookmark-setting-directory").show(); + } + }; + for (const bookmark of bookmarks.bookmarks().content) { + template.find(".list").append(bookmark_tag(callback_selected, bookmark)); + } + console.log(template.find(".list").find(".bookmark, .directory")); + template.find(".list").find(".bookmark, .directory").eq(0).find("> .name").trigger('click'); + }; + { //General buttons + template.find(".button-create").on('click', event => { + let create_modal; + create_modal = createModal({ + header: _translations.w0cXvTxP || (_translations.w0cXvTxP = tr("Create a new entry")), + body: () => { + let template = $("#tmpl_manage_bookmarks-create").renderTag({}); + template = $.spawn("div").append(template); + for (const bookmark of bookmarks.bookmarks().content) + parent_tag(template.find(".bookmark-parent"), "", bookmark); + if (selected_bookmark) { + const parent = selected_bookmark.type == bookmarks.BookmarkType.ENTRY ? + bookmarks.parent_bookmark(selected_bookmark) : + selected_bookmark; + if (parent) + template.find(".bookmark-parent").val(parent.unique_id); + } + template.find(".bookmark-name").on('change, keyup', event => { + template.find(".button-create").prop("disabled", event.target.value.length < 3); + }); + template.find(".button-create").prop("disabled", true).on('click', event => { + const name = template.find(".bookmark-name").val(); + const parent_uuid = template.find(".bookmark-parent").val(); + const parent = bookmarks.find_bookmark(parent_uuid); + let bookmark; + if (template.find(".bookmark-type").val() == "directory") { + bookmark = bookmarks.create_bookmark_directory(parent || bookmarks.bookmarks(), name); + } + else { + bookmark = bookmarks.create_bookmark(name, parent || bookmarks.bookmarks(), { + server_port: 9987, + server_address: "ts.teaspeak.de" + }, "Another TeaSpeak user"); + } + bookmarks.save_bookmark(bookmark); + create_modal.close(); + update_bookmarks(); + }); + return template; + }, + footer: 400 + }); + create_modal.open(); + }); + template.find(".button-delete").on('click', event => { + if (!selected_bookmark) + return; + Modals.spawnYesNo(_translations.oZh862t4 || (_translations.oZh862t4 = tr("Are you sure?")), _translations.Fo8Cfk6b || (_translations.Fo8Cfk6b = tr("Do you really want to delete this entry?")), result => { + if (result) { + bookmarks.delete_bookmark(selected_bookmark); + bookmarks.save_bookmark(selected_bookmark); /* save the deleted state */ + update_bookmarks(); + } + }); + }); + /* bookmark listener */ + { + template.find(".setting-bookmark-profile").on('change', event => { + if (!selected_bookmark || selected_bookmark.type != bookmarks.BookmarkType.ENTRY) + return; + const casted = selected_bookmark; + const element = event.target; + casted.connect_profile = element.value; + bookmarks.save_bookmark(selected_bookmark); + }); + template.find(".setting-server-host").on('change', event => { + if (!selected_bookmark || selected_bookmark.type != bookmarks.BookmarkType.ENTRY) + return; + const casted = selected_bookmark; + const element = event.target; + casted.server_properties.server_address = element.value; + bookmarks.save_bookmark(selected_bookmark); + }); + template.find(".setting-server-port").on('change', event => { + if (!selected_bookmark || selected_bookmark.type != bookmarks.BookmarkType.ENTRY) + return; + const casted = selected_bookmark; + const element = event.target; + casted.server_properties.server_port = parseInt(element.value); + bookmarks.save_bookmark(selected_bookmark); + }); + template.find(".setting-server-password").on('change', event => { + if (!selected_bookmark || selected_bookmark.type != bookmarks.BookmarkType.ENTRY) + return; + const casted = selected_bookmark; + const element = event.target; + casted.server_properties.server_password = element.value; + bookmarks.save_bookmark(selected_bookmark); + }); + template.find(".setting-username").on('change', event => { + if (!selected_bookmark || selected_bookmark.type != bookmarks.BookmarkType.ENTRY) + return; + const casted = selected_bookmark; + const element = event.target; + casted.nickname = element.value; + bookmarks.save_bookmark(selected_bookmark); + }); + template.find(".setting-channel").on('change', event => { + if (!selected_bookmark || selected_bookmark.type != bookmarks.BookmarkType.ENTRY) + return; + const casted = selected_bookmark; + const element = event.target; + casted.default_channel = element.value; + bookmarks.save_bookmark(selected_bookmark); + }); + template.find(".setting-channel-password").on('change', event => { + if (!selected_bookmark || selected_bookmark.type != bookmarks.BookmarkType.ENTRY) + return; + const casted = selected_bookmark; + const element = event.target; + casted.default_channel_password = element.value; + bookmarks.save_bookmark(selected_bookmark); + }); + } + /* listener for both */ + { + template.find(".setting-bookmark-name").on('change', event => { + if (!selected_bookmark) + return; + const element = event.target; + if (element.value.length >= 3) { + selected_bookmark.display_name = element.value; + bookmarks.save_bookmark(selected_bookmark); + if (update_name) + update_name(); + } + }); + } + } + /* connect profile initialisation */ + { + const list = template.find(".setting-bookmark-profile"); + for (const profile of profiles.profiles()) { + const tag = $.spawn("option").val(profile.id).text(profile.profile_name); + if (profile.id == "default") + tag.css("font-weight", "bold"); + list.append(tag); + } + } + update_bookmarks(); + template.find(".button-close").on('click', event => modal.close()); + return template; + }, + footer: undefined, + width: 750 + }); + modal.close_listener.push(() => globalClient.controlBar.update_bookmarks()); + modal.open(); + } + Modals.spawnBookmarkModal = spawnBookmarkModal; +})(Modals || (Modals = {})); +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["9c4e0679ae90546e1212cf0fa94a8dc93cf5f5d6dd58dec3bdc2ea0354f64bc2"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["9c4e0679ae90546e1212cf0fa94a8dc93cf5f5d6dd58dec3bdc2ea0354f64bc2"] = "9c4e0679ae90546e1212cf0fa94a8dc93cf5f5d6dd58dec3bdc2ea0354f64bc2"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of []) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["5defa2b0b7870d87fbee02ddfa78bcf56652e21a055d43f1914c3ed58a071ce6"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["5defa2b0b7870d87fbee02ddfa78bcf56652e21a055d43f1914c3ed58a071ce6"] = "5defa2b0b7870d87fbee02ddfa78bcf56652e21a055d43f1914c3ed58a071ce6"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "Oww_8MhG", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPermissionEdit.ts (201,39)" }, { name: "pWwEnXuH", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPermissionEdit.ts (206,39)" }, { name: "d782WRD7", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPermissionEdit.ts (211,39)" }, { name: "jLPEqD7a", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPermissionEdit.ts (216,39)" }, { name: "u4Wrveax", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPermissionEdit.ts (379,51)" }, { name: "H8E3MA_M", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPermissionEdit.ts (386,51)" }, { name: "I3wO3RnF", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPermissionEdit.ts (417,51)" }, { name: "sVPIokB6", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPermissionEdit.ts (424,51)" }, { name: "YhHVnenK", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPermissionEdit.ts (433,47)" }, { name: "oz_lVTbr", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPermissionEdit.ts (439,47)" }, { name: "uhJ9MiVe", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPermissionEdit.ts (446,47)" }, { name: "NkqCLmwG", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPermissionEdit.ts (449,49)" }, { name: "MtZz4yIH", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPermissionEdit.ts (450,49)" }, { name: "srnRm9_W", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPermissionEdit.ts (457,47)" }, { name: "ZU4wsk2d", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPermissionEdit.ts (548,24)" }, { name: "n9Z50GLJ", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPermissionEdit.ts (663,63)" }, { name: "mBkRBZS3", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPermissionEdit.ts (674,63)" }, { name: "UsIyoX72", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPermissionEdit.ts (689,63)" }, { name: "QlK0TuLh", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPermissionEdit.ts (706,63)" }, { name: "J_ce8JgI", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPermissionEdit.ts (819,63)" }, { name: "nCBesWoG", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPermissionEdit.ts (829,63)" }, { name: "nv19nyrb", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPermissionEdit.ts (843,63)" }, { name: "pzndfIuy", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPermissionEdit.ts (859,63)" }, { name: "ihkHEieL", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPermissionEdit.ts (954,63)" }, { name: "nhiCrQH9", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPermissionEdit.ts (965,63)" }, { name: "ImjQM5Jj", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPermissionEdit.ts (979,63)" }, { name: "smhZ_Q0H", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPermissionEdit.ts (996,63)" }, { name: "pdeF_A33", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPermissionEdit.ts (1056,63)" }, { name: "FnCGmVHb", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPermissionEdit.ts (1066,63)" }, { name: "b2qjExpf", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPermissionEdit.ts (1080,63)" }, { name: "Dr0kHgdQ", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPermissionEdit.ts (1096,63)" }, { name: "buddzElO", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPermissionEdit.ts (1216,63)" }, { name: "EAsiW60n", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPermissionEdit.ts (1226,63)" }, { name: "FimEJKlf", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPermissionEdit.ts (1240,63)" }, { name: "m6BgWvPe", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPermissionEdit.ts (1256,63)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +/// +/// +/// +var Modals; +(function (Modals) { + let PermissionEditorMode; + (function (PermissionEditorMode) { + PermissionEditorMode[PermissionEditorMode["VISIBLE"] = 0] = "VISIBLE"; + PermissionEditorMode[PermissionEditorMode["NO_PERMISSION"] = 1] = "NO_PERMISSION"; + PermissionEditorMode[PermissionEditorMode["UNSET"] = 2] = "UNSET"; + })(PermissionEditorMode || (PermissionEditorMode = {})); + class PermissionEditor { + constructor(permissions) { + /* references within the container tag */ + this.permission_value_map = {}; + this.listener_change = () => Promise.resolve(); + this.permissions = permissions; + } + build_tag() { + this.permission_map = {}; + this.container = $("#tmpl_permission_editor").renderTag(); + /* search for that as long we've not that much nodes */ + this.mode_container_permissions = this.container.find(".container-mode-permissions"); + this.mode_container_error_permission = this.container.find(".container-mode-no-permissions"); + this.mode_container_unset = this.container.find(".container-mode-unset"); + this.set_mode(PermissionEditorMode.UNSET); + /* the filter */ + { + const tag_filter_input = this.container.find(".filter-input"); + const tag_filter_granted = this.container.find(".filter-granted"); + tag_filter_granted.on('change', event => tag_filter_input.trigger('change')); + tag_filter_input.on('keyup change', event => { + let filter_mask = tag_filter_input.val(); + let req_granted = tag_filter_granted.prop("checked"); + /* we've to disable this function because its sometimes laggy */ + const org_fn = $.fn.dropdown && $.fn.dropdown.Constructor ? $.fn.dropdown.Constructor._clearMenus : undefined; + if (org_fn) + $.fn.dropdown.Constructor._clearMenus = () => { }; + /* update each permission */ + { + const start = Date.now(); + for (const permission_id of Object.keys(this.permission_map)) { + const permission = this.permission_map[permission_id]; + let shown = filter_mask.length == 0 || permission.filter.indexOf(filter_mask) != -1; + if (shown && req_granted) { + const value = this.permission_value_map[permission_id]; + shown = value && (value.hasValue() || value.hasGrant()); + } + permission.tag.attr("match", shown ? 1 : 0); + /* this is faster then .hide() or .show() */ + if (shown) + permission.tag.css('display', 'flex'); + else + permission.tag.css('display', 'none'); + } + const end = Date.now(); + console.error("Filter update required %oms", end - start); + } + /* update group visibility (hide empty groups) */ + { + const start = Date.now(); + this.container.find(".group").each((idx, _entry) => { + let entry = $(_entry); + let target = entry.find(".entry:not(.group)[match=\"1\"]").length > 0; + /* this is faster then .hide() or .show() */ + if (target) + entry.css('display', 'flex'); + else + entry.css('display', 'none'); + }); + const end = Date.now(); + console.error("Group update required %oms", end - start); + } + if (org_fn) + $.fn.dropdown.Constructor._clearMenus = org_fn; + }); + } + /* update button */ + { + this.container.find(".button-update").on('click', this.trigger_update.bind(this)); + } + /* global context menu listener */ + { + this.container.on('contextmenu', event => { + if (event.isDefaultPrevented()) + return; + event.preventDefault(); + /* TODO allow collapse and expend all */ + }); + } + /* actual permissions */ + { + const tag_entries = this.container.find(".entries"); + const template_entry = $("#tmpl_permission_entry"); + const build_group = (group) => { + const tag_group = template_entry.renderTag({ + type: "group", + name: group.group.name + }); + const tag_group_entries = tag_group.find(".group-entries"); + const update_collapse_status = (status, recursive) => { + const tag = recursive ? this.container.find(".entry.group") : tag_group; + /* this is faster then .hide() or .show() */ + if (status) { + tag.find("> .group-entries").css('display', 'block'); + } + else { + tag.find("> .group-entries").css('display', 'none'); + } + tag.find("> .title .arrow").toggleClass("down", status).toggleClass("right", !status); + }; + /* register collapse and context listener */ + { + const tag_arrow = tag_group.find(".arrow"); + tag_arrow.on('click', event => { + if (event.isDefaultPrevented()) + return; + event.preventDefault(); + update_collapse_status(tag_arrow.hasClass("right"), false); + }); + const tag_title = tag_group.find(".title"); + tag_title.on('contextmenu', event => { + if (event.isDefaultPrevented()) + return; + event.preventDefault(); + spawn_context_menu(event.pageX, event.pageY, { + type: MenuEntryType.ENTRY, + icon: "", + name: _translations.Oww_8MhG || (_translations.Oww_8MhG = tr("Expend group")), + callback: () => update_collapse_status(true, false) + }, { + type: MenuEntryType.ENTRY, + icon: "", + name: _translations.pWwEnXuH || (_translations.pWwEnXuH = tr("Expend all")), + callback: () => update_collapse_status(true, true) + }, { + type: MenuEntryType.ENTRY, + icon: "", + name: _translations.d782WRD7 || (_translations.d782WRD7 = tr("Collapse group")), + callback: () => update_collapse_status(false, false) + }, { + type: MenuEntryType.ENTRY, + icon: "", + name: _translations.jLPEqD7a || (_translations.jLPEqD7a = tr("Collapse all")), + callback: () => update_collapse_status(false, true) + }); + }); + } + /* build the permissions */ + { + for (const permission of group.permissions) { + const tag_permission = template_entry.renderTag({ + type: "permission", + permission_name: permission.name, + permission_id: permission.id, + permission_description: permission.description, + }); + const tag_value = tag_permission.find(".column-value input"); + const tag_granted = tag_permission.find(".column-granted input"); + const tag_flag_skip = tag_permission.find(".column-skip input"); + const tag_flag_negate = tag_permission.find(".column-negate input"); + /* double click listener */ + { + tag_permission.on('dblclick', event => { + if (event.isDefaultPrevented()) + return; + event.preventDefault(); + if (tag_permission.hasClass("value-unset")) { + tag_flag_skip.prop("checked", false); + tag_flag_negate.prop("checked", false); + tag_permission.removeClass("value-unset"); + if (permission.name.startsWith("b_")) { + tag_permission.find(".column-value input") + .prop("checked", true) + .trigger('change'); + } + else { + /* TODO auto value */ + tag_value.val('').focus(); + } + } + else if (!permission.name.startsWith("b_")) { + tag_value.focus(); + } + }); + tag_permission.find(".column-granted").on('dblclick', event => { + if (event.isDefaultPrevented()) + return; + event.preventDefault(); + if (tag_permission.hasClass("grant-unset")) { + tag_permission.removeClass("grant-unset"); + tag_granted.focus(); + } + }); + } + /* focus out listener */ + { + tag_granted.on('focusout', event => { + try { + const value = tag_granted.val(); + if (isNaN(parseInt(value))) + throw ""; + } + catch (_) { + tag_granted.val(""); + tag_permission.addClass("grant-unset"); + const element = this.permission_value_map[permission.id]; + if (element && element.hasGrant()) { + this.listener_change(permission, { + remove: true, + granted: -2 + }).then(() => { + element.granted_value = undefined; + }).catch(() => { + tag_granted.val(element.granted_value); + }); + } + } + }); + tag_value.on('focusout', event => { + try { + if (isNaN(parseInt(tag_value.val()))) + throw ""; + } + catch (_) { + const element = this.permission_value_map[permission.id]; + if (element && element.hasValue()) { + tag_value.val(element.value); + } + else { + tag_value.val(""); + tag_permission.addClass("value-unset"); + } + } + }); + } + /* change listener */ + { + tag_flag_negate.on('change', () => tag_value.trigger('change')); + tag_flag_skip.on('change', () => tag_value.trigger('change')); + tag_granted.on('change', event => { + const value = parseInt(tag_granted.val()); + if (isNaN(value)) + return; + this.listener_change(permission, { + remove: false, + granted: value, + }).then(() => { + const element = this.permission_value_map[permission.id] || (this.permission_value_map[permission.id] = new PermissionValue(permission)); + element.granted_value = value; + }).catch(() => { + const element = this.permission_value_map[permission.id]; + tag_granted.val(element && element.hasGrant() ? element.granted_value : ""); + tag_permission.toggleClass("grant-unset", !element || !element.hasGrant()); + }); + }); + tag_value.on('change', event => { + const value = permission.is_boolean() ? tag_value.prop("checked") ? 1 : 0 : parseInt(tag_value.val()); + if (isNaN(value)) + return; + const flag_negate = tag_flag_negate.prop("checked"); + const flag_skip = tag_flag_skip.prop("checked"); + this.listener_change(permission, { + remove: false, + value: value, + flag_negate: flag_negate, + flag_skip: flag_skip + }).then(() => { + const element = this.permission_value_map[permission.id] || (this.permission_value_map[permission.id] = new PermissionValue(permission)); + element.value = value; + element.flag_skip = flag_skip; + element.flag_negate = flag_negate; + }).catch(error => { + const element = this.permission_value_map[permission.id]; + /* reset or set the fields */ + if (permission.is_boolean()) + tag_value.prop('checked', element && element.hasValue() && element.value > 0); + else + tag_value.val(element && element.hasValue() ? element.value : ""); + tag_flag_negate.prop("checked", element && element.flag_negate); + tag_flag_skip.prop("checked", element && element.flag_skip); + tag_permission.toggleClass("value-unset", !element || !element.hasValue()); + }); + }); + } + /* context menu */ + { + tag_permission.on('contextmenu', event => { + if (event.isDefaultPrevented()) + return; + event.preventDefault(); + let entries = []; + if (tag_permission.hasClass("value-unset")) { + entries.push({ + type: MenuEntryType.ENTRY, + icon: "", + name: _translations.u4Wrveax || (_translations.u4Wrveax = tr("Add permission")), + callback: () => tag_permission.trigger('dblclick') + }); + } + else { + entries.push({ + type: MenuEntryType.ENTRY, + icon: "", + name: _translations.H8E3MA_M || (_translations.H8E3MA_M = tr("Remove permission")), + callback: () => { + this.listener_change(permission, { + remove: true, + value: -2 + }).then(() => { + const element = this.permission_value_map[permission.id]; + if (!element) + return; /* This should never happen, if so how are we displaying this permission?! */ + element.value = undefined; + element.flag_negate = false; + element.flag_skip = false; + tag_permission.toggleClass("value-unset", true); + }).catch(() => { + const element = this.permission_value_map[permission.id]; + /* reset or set the fields */ + tag_value.val(element && element.hasValue() ? element.value : ""); + tag_flag_negate.prop("checked", element && element.flag_negate); + tag_flag_skip.prop("checked", element && element.flag_skip); + tag_permission.toggleClass("value-unset", !element || !element.hasValue()); + }); + } + }); + } + if (tag_permission.hasClass("grant-unset")) { + entries.push({ + type: MenuEntryType.ENTRY, + icon: "", + name: _translations.I3wO3RnF || (_translations.I3wO3RnF = tr("Add grant permission")), + callback: () => tag_permission.find(".column-granted").trigger('dblclick') + }); + } + else { + entries.push({ + type: MenuEntryType.ENTRY, + icon: "", + name: _translations.sVPIokB6 || (_translations.sVPIokB6 = tr("Remove grant permission")), + callback: () => tag_granted.val('').trigger('focusout') /* empty values are handled within focus out */ + }); + } + entries.push(MenuEntry.HR()); + entries.push({ + type: MenuEntryType.ENTRY, + icon: "", + name: _translations.YhHVnenK || (_translations.YhHVnenK = tr("Expend all")), + callback: () => update_collapse_status(true, true) + }); + entries.push({ + type: MenuEntryType.ENTRY, + icon: "", + name: _translations.oz_lVTbr || (_translations.oz_lVTbr = tr("Collapse all")), + callback: () => update_collapse_status(false, true) + }); + entries.push(MenuEntry.HR()); + entries.push({ + type: MenuEntryType.ENTRY, + icon: "", + name: _translations.uhJ9MiVe || (_translations.uhJ9MiVe = tr("Show permission description")), + callback: () => { + createInfoModal(_translations.NkqCLmwG || (_translations.NkqCLmwG = tr("Permission description")), (_translations.MtZz4yIH || (_translations.MtZz4yIH = tr("Permission description for permission "))) + permission.name + ":
    " + permission.description).open(); + } + }); + entries.push({ + type: MenuEntryType.ENTRY, + icon: "", + name: _translations.srnRm9_W || (_translations.srnRm9_W = tr("Copy permission name")), + callback: () => { + copy_to_clipboard(permission.name); + } + }); + spawn_context_menu(event.pageX, event.pageY, ...entries); + }); + } + this.permission_map[permission.id] = { + tag: tag_permission, + id: permission.id, + filter: permission.name, + tag_flag_negate: tag_flag_negate, + tag_flag_skip: tag_flag_skip, + tag_grant: tag_granted, + tag_value: tag_value, + is_bool: permission.is_boolean() + }; + tag_group_entries.append(tag_permission); + } + } + /* append the subgroups */ + for (const child of group.children) { + tag_group_entries.append(build_group(child)); + } + return tag_group; + }; + /* build the groups */ + for (const group of this.permissions) + tag_entries.append(build_group(group)); + } + } + set_permissions(permissions) { + permissions = permissions || []; + this.permission_value_map = {}; + for (const permission of permissions) + this.permission_value_map[permission.type.id] = permission; + for (const permission_id of Object.keys(this.permission_map)) { + const permission = this.permission_map[permission_id]; + const value = this.permission_value_map[permission_id]; + permission.tag + .toggleClass("value-unset", !value || !value.hasValue()) + .toggleClass("grant-unset", !value || !value.hasGrant()); + if (value && value.hasValue()) { + if (value.type.is_boolean()) + permission.tag_value.prop("checked", value.value); + else + permission.tag_value.val(value.value); + permission.tag_flag_skip.prop("checked", value.flag_skip); + permission.tag_flag_negate.prop("checked", value.flag_negate); + } + if (value && value.hasGrant()) { + permission.tag_grant.val(value.granted_value); + } + } + } + set_listener(listener) { + this.listener_change = listener || (() => Promise.resolve()); + } + set_listener_update(listener) { + this.listener_update = listener; + } + trigger_update() { + if (this.listener_update) + this.listener_update(); + } + set_mode(mode) { + this.mode_container_permissions.css('display', mode == PermissionEditorMode.VISIBLE ? 'flex' : 'none'); + this.mode_container_error_permission.css('display', mode == PermissionEditorMode.NO_PERMISSION ? 'flex' : 'none'); + this.mode_container_unset.css('display', mode == PermissionEditorMode.UNSET ? 'block' : 'none'); + } + } + function spawnPermissionEdit() { + const connectModal = createModal({ + header: function () { + return _translations.ZU4wsk2d || (_translations.ZU4wsk2d = tr("Server Permissions")); + }, + body: function () { + let properties = {}; + let tag = $("#tmpl_server_permissions").renderTag(properties); + const pe = new PermissionEditor(globalClient.permissions.groupedPermissions()); + pe.build_tag(); + /* initialisation */ + { + const pe_server = tag.find("permission-editor.group-server"); + pe_server.append(pe.container); /* fuck off workaround to initialize form listener */ + } + apply_server_groups(pe, tag.find(".tab-group-server")); + apply_channel_groups(pe, tag.find(".tab-group-channel")); + apply_channel_permission(pe, tag.find(".tab-channel")); + apply_client_permission(pe, tag.find(".tab-client")); + apply_client_channel_permission(pe, tag.find(".tab-client-channel")); + return tag.tabify(false); + }, + footer: undefined, + width: "90%", + height: "80%", + trigger_tab: false, + full_size: true + }); + const tag = connectModal.htmlTag; + tag.find(".btn_close").on('click', () => { + connectModal.close(); + }); + return connectModal; + } + Modals.spawnPermissionEdit = spawnPermissionEdit; + function build_channel_tree(channel_list, select_callback) { + const root = globalClient.channelTree.get_first_channel(); + if (!root) + return; + const build_channel = (channel) => { + let tag = $.spawn("div").addClass("channel").attr("channel-id", channel.channelId); + globalClient.fileManager.icons.generateTag(channel.properties.channel_icon_id).appendTo(tag); + { + let name = $.spawn("a").text(channel.channelName() + " (" + channel.channelId + ")").addClass("name"); + //if(globalClient.channelTree.server.properties. == group.id) + // name.addClass("default"); + name.appendTo(tag); + } + tag.on('click', event => { + channel_list.find(".selected").removeClass("selected"); + tag.addClass("selected"); + select_callback(channel); + }); + return tag; + }; + const build_channels = (root) => { + build_channel(root).appendTo(channel_list); + for (const child of root.children()) + build_channels(child); + while (root.channel_next) { + root = root.channel_next; + build_channel(root).appendTo(channel_list); + } + }; + build_channels(root); + setTimeout(() => channel_list.find('.channel').first().trigger('click'), 0); + } + function apply_client_channel_permission(editor, tab_tag) { + let current_cldbid = 0; + let current_channel; + /* the editor */ + { + const pe_client = tab_tag.find("permission-editor.client-channel"); + tab_tag.on('show', event => { + console.error("Channel tab show"); + pe_client.append(editor.container); + if (globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_CLIENT_PERMISSION_LIST).granted(1)) { + if (current_cldbid && current_channel) + editor.set_mode(PermissionEditorMode.VISIBLE); + else + editor.set_mode(PermissionEditorMode.UNSET); + } + else { + editor.set_mode(PermissionEditorMode.NO_PERMISSION); + return; + } + editor.set_listener_update(() => { + if (!current_cldbid || !current_channel) + return; + globalClient.permissions.requestClientChannelPermissions(current_cldbid, current_channel.channelId).then(result => { + editor.set_permissions(result); + editor.set_mode(PermissionEditorMode.VISIBLE); + }).catch(error => { + console.log(error); //TODO handling? + }); + }); + editor.set_listener((permission, value) => { + if (!current_cldbid) + return Promise.reject("unset client"); + if (!current_channel) + return Promise.reject("unset channel"); + if (value.remove) { + /* remove the permission */ + if (typeof (value.value) !== "undefined") { + log.info(LogCategory.PERMISSIONS, _translations.n9Z50GLJ || (_translations.n9Z50GLJ = tr("Removing client channel permission %s. permission.id: %o")), permission.name, permission.id); + return globalClient.serverConnection.send_command("channelclientdelperm", { + cldbid: current_cldbid, + cid: current_channel.channelId, + permid: permission.id, + }); + } + else { + log.info(LogCategory.PERMISSIONS, _translations.mBkRBZS3 || (_translations.mBkRBZS3 = tr("Removing client channel grant permission %s. permission.id: %o")), permission.name, permission.id_grant(), value.granted); + return globalClient.serverConnection.send_command("channelclientdelperm", { + cldbid: current_cldbid, + cid: current_channel.channelId, + permid: permission.id_grant(), + }); + } + } + else { + /* add the permission */ + if (typeof (value.value) !== "undefined") { + log.info(LogCategory.PERMISSIONS, _translations.UsIyoX72 || (_translations.UsIyoX72 = tr("Adding or updating client channel permission %s. permission.{id: %o, value: %o, flag_skip: %o, flag_negate: %o}")), permission.name, permission.id, value.value, value.flag_skip, value.flag_negate); + return globalClient.serverConnection.send_command("channelclientaddperm", { + cldbid: current_cldbid, + cid: current_channel.channelId, + permid: permission.id, + permvalue: value.value, + permskip: value.flag_skip, + permnegate: value.flag_negate + }); + } + else { + log.info(LogCategory.PERMISSIONS, _translations.QlK0TuLh || (_translations.QlK0TuLh = tr("Adding or updating client channel grant permission %s. permission.{id: %o, value: %o}")), permission.name, permission.id_grant(), value.granted); + return globalClient.serverConnection.send_command("channelclientaddperm", { + cldbid: current_cldbid, + cid: current_channel.channelId, + permid: permission.id_grant(), + permvalue: value.granted, + permskip: false, + permnegate: false + }); + } + } + }); + /* FIXME: Use cached permissions */ + editor.trigger_update(); + }); + } + build_channel_tree(tab_tag.find(".list-channel .entries"), channel => { + if (current_channel == channel) + return; + current_channel = channel; + /* TODO: Test for visibility */ + editor.trigger_update(); + }); + { + const tag_select_uid = tab_tag.find(".client-select input"); + const tag_select_error = tab_tag.find(".client-select .invalid-feedback"); + const tag_client_name = tab_tag.find(".client-name"); + const tag_client_uid = tab_tag.find(".client-uid"); + const tag_client_dbid = tab_tag.find(".client-dbid"); + const resolve_client = () => { + let client_uid = tag_select_uid.val(); + globalClient.serverConnection.command_helper.info_from_uid(client_uid).then(result => { + if (!result || result.length == 0) + return Promise.reject("invalid data"); + tag_select_uid.attr('pattern', null).removeClass('is-invalid'); + tag_client_name.val(result[0].client_nickname); + tag_client_uid.val(result[0].client_unique_id); + tag_client_dbid.val(result[0].client_database_id); + current_cldbid = result[0].client_database_id; + editor.trigger_update(); + }).catch(error => { + console.log(error); + if (error instanceof CommandResult) { + if (error.id == ErrorID.EMPTY_RESULT) + error = "unknown client"; + else + error = error.extra_message || error.message; + } + tag_client_name.val(""); + tag_client_uid.val(""); + tag_client_dbid.val(""); + tag_select_error.text(error); + tag_select_uid.attr('pattern', '^[a]{1000}$').addClass('is-invalid'); + editor.set_mode(PermissionEditorMode.UNSET); + }); + }; + tab_tag.find(".client-select-uid").on('change', event => resolve_client()); + } + } + function apply_client_permission(editor, tab_tag) { + let current_cldbid = 0; + /* the editor */ + { + const pe_client = tab_tag.find("permission-editor.client"); + tab_tag.on('show', event => { + console.error("Channel tab show"); + pe_client.append(editor.container); + if (globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_CLIENT_PERMISSION_LIST).granted(1)) { + if (current_cldbid) + editor.set_mode(PermissionEditorMode.VISIBLE); + else + editor.set_mode(PermissionEditorMode.UNSET); + } + else { + editor.set_mode(PermissionEditorMode.NO_PERMISSION); + return; + } + editor.set_listener_update(() => { + if (!current_cldbid) + return; + globalClient.permissions.requestClientPermissions(current_cldbid).then(result => { + editor.set_permissions(result); + editor.set_mode(PermissionEditorMode.VISIBLE); + }).catch(error => { + console.log(error); //TODO handling? + }); + }); + editor.set_listener((permission, value) => { + if (!current_cldbid) + return Promise.reject("unset client"); + if (value.remove) { + /* remove the permission */ + if (typeof (value.value) !== "undefined") { + log.info(LogCategory.PERMISSIONS, _translations.J_ce8JgI || (_translations.J_ce8JgI = tr("Removing client permission %s. permission.id: %o")), permission.name, permission.id); + return globalClient.serverConnection.send_command("clientaddperm", { + cldbid: current_cldbid, + permid: permission.id, + }); + } + else { + log.info(LogCategory.PERMISSIONS, _translations.nCBesWoG || (_translations.nCBesWoG = tr("Removing client grant permission %s. permission.id: %o")), permission.name, permission.id_grant(), value.granted); + return globalClient.serverConnection.send_command("clientaddperm", { + cldbid: current_cldbid, + permid: permission.id_grant(), + }); + } + } + else { + /* add the permission */ + if (typeof (value.value) !== "undefined") { + log.info(LogCategory.PERMISSIONS, _translations.nv19nyrb || (_translations.nv19nyrb = tr("Adding or updating client permission %s. permission.{id: %o, value: %o, flag_skip: %o, flag_negate: %o}")), permission.name, permission.id, value.value, value.flag_skip, value.flag_negate); + return globalClient.serverConnection.send_command("clientaddperm", { + cldbid: current_cldbid, + permid: permission.id, + permvalue: value.value, + permskip: value.flag_skip, + permnegate: value.flag_negate + }); + } + else { + log.info(LogCategory.PERMISSIONS, _translations.pzndfIuy || (_translations.pzndfIuy = tr("Adding or updating client grant permission %s. permission.{id: %o, value: %o}")), permission.name, permission.id_grant(), value.granted); + return globalClient.serverConnection.send_command("clientaddperm", { + cldbid: current_cldbid, + permid: permission.id_grant(), + permvalue: value.granted, + permskip: false, + permnegate: false + }); + } + } + }); + /* FIXME: Use cached permissions */ + editor.trigger_update(); + }); + } + const tag_select_uid = tab_tag.find(".client-select input"); + const tag_select_error = tab_tag.find(".client-select .invalid-feedback"); + const tag_client_name = tab_tag.find(".client-name"); + const tag_client_uid = tab_tag.find(".client-uid"); + const tag_client_dbid = tab_tag.find(".client-dbid"); + const resolve_client = () => { + let client_uid = tag_select_uid.val(); + globalClient.serverConnection.command_helper.info_from_uid(client_uid).then(result => { + if (!result || result.length == 0) + return Promise.reject("invalid data"); + tag_select_uid.attr('pattern', null).removeClass('is-invalid'); + tag_client_name.val(result[0].client_nickname); + tag_client_uid.val(result[0].client_unique_id); + tag_client_dbid.val(result[0].client_database_id); + current_cldbid = result[0].client_database_id; + editor.trigger_update(); + }).catch(error => { + console.log(error); + if (error instanceof CommandResult) { + if (error.id == ErrorID.EMPTY_RESULT) + error = "unknown client"; + else + error = error.extra_message || error.message; + } + tag_client_name.val(""); + tag_client_uid.val(""); + tag_client_dbid.val(""); + tag_select_error.text(error); + tag_select_uid.attr('pattern', '^[a]{1000}$').addClass('is-invalid'); + editor.set_mode(PermissionEditorMode.UNSET); + }); + }; + tab_tag.find(".client-select-uid").on('change', event => resolve_client()); + } + function apply_channel_permission(editor, tab_tag) { + let current_channel; + /* the editor */ + { + const pe_channel = tab_tag.find("permission-editor.channel"); + tab_tag.on('show', event => { + console.error("Channel tab show"); + pe_channel.append(editor.container); + if (globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_CHANNEL_PERMISSION_LIST).granted(1)) + editor.set_mode(PermissionEditorMode.VISIBLE); + else { + editor.set_mode(PermissionEditorMode.NO_PERMISSION); + return; + } + editor.set_listener_update(() => { + if (!current_channel) + return; + globalClient.permissions.requestChannelPermissions(current_channel.channelId).then(result => editor.set_permissions(result)).catch(error => { + console.log(error); //TODO handling? + }); + }); + editor.set_listener((permission, value) => { + if (!current_channel) + return Promise.reject("unset channel"); + if (value.remove) { + /* remove the permission */ + if (typeof (value.value) !== "undefined") { + log.info(LogCategory.PERMISSIONS, _translations.ihkHEieL || (_translations.ihkHEieL = tr("Removing channel permission %s. permission.id: %o")), permission.name, permission.id); + return globalClient.serverConnection.send_command("channeldelperm", { + cid: current_channel.channelId, + permid: permission.id, + }); + } + else { + /* TODO Remove this because its totally useless. Remove this from the UI as well */ + log.info(LogCategory.PERMISSIONS, _translations.nhiCrQH9 || (_translations.nhiCrQH9 = tr("Removing channel grant permission %s. permission.id: %o")), permission.name, permission.id_grant(), value.granted); + return globalClient.serverConnection.send_command("channeldelperm", { + cid: current_channel.channelId, + permid: permission.id_grant(), + }); + } + } + else { + /* add the permission */ + if (typeof (value.value) !== "undefined") { + log.info(LogCategory.PERMISSIONS, _translations.ImjQM5Jj || (_translations.ImjQM5Jj = tr("Adding or updating channel permission %s. permission.{id: %o, value: %o, flag_skip: %o, flag_negate: %o}")), permission.name, permission.id, value.value, value.flag_skip, value.flag_negate); + return globalClient.serverConnection.send_command("channeladdperm", { + cid: current_channel.channelId, + permid: permission.id, + permvalue: value.value, + permskip: value.flag_skip, + permnegate: value.flag_negate + }); + } + else { + /* TODO Remove this because its totally useless. Remove this from the UI as well */ + log.info(LogCategory.PERMISSIONS, _translations.smhZ_Q0H || (_translations.smhZ_Q0H = tr("Adding or updating channel grant permission %s. permission.{id: %o, value: %o}")), permission.name, permission.id_grant(), value.granted); + return globalClient.serverConnection.send_command("channeladdperm", { + cid: current_channel.channelId, + permid: permission.id_grant(), + permvalue: value.granted, + permskip: false, + permnegate: false + }); + } + } + }); + /* FIXME: Use cached permissions */ + editor.trigger_update(); + }); + } + let channel_list = tab_tag.find(".list-channel .entries"); + build_channel_tree(channel_list, channel => { + current_channel = channel; + editor.trigger_update(); + }); + } + function apply_channel_groups(editor, tab_tag) { + let current_group; + /* the editor */ + { + const pe_server = tab_tag.find("permission-editor.group-channel"); + tab_tag.on('show', event => { + console.error("Channel group tab show"); + pe_server.append(editor.container); + if (globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_CHANNELGROUP_PERMISSION_LIST).granted(1)) + editor.set_mode(PermissionEditorMode.VISIBLE); + else { + editor.set_mode(PermissionEditorMode.NO_PERMISSION); + return; + } + editor.set_listener_update(() => { + if (!current_group) + return; + globalClient.groups.request_permissions(current_group).then(result => editor.set_permissions(result)).catch(error => { + console.log(error); //TODO handling? + }); + }); + editor.set_listener((permission, value) => { + if (!current_group) + return Promise.reject("unset channel group"); + if (value.remove) { + /* remove the permission */ + if (typeof (value.value) !== "undefined") { + log.info(LogCategory.PERMISSIONS, _translations.pdeF_A33 || (_translations.pdeF_A33 = tr("Removing channel group permission %s. permission.id: %o")), permission.name, permission.id); + return globalClient.serverConnection.send_command("channelgroupdelperm", { + cgid: current_group.id, + permid: permission.id, + }); + } + else { + log.info(LogCategory.PERMISSIONS, _translations.FnCGmVHb || (_translations.FnCGmVHb = tr("Removing channel group grant permission %s. permission.id: %o")), permission.name, permission.id_grant(), value.granted); + return globalClient.serverConnection.send_command("channelgroupdelperm", { + cgid: current_group.id, + permid: permission.id_grant(), + }); + } + } + else { + /* add the permission */ + if (typeof (value.value) !== "undefined") { + log.info(LogCategory.PERMISSIONS, _translations.b2qjExpf || (_translations.b2qjExpf = tr("Adding or updating channel group permission %s. permission.{id: %o, value: %o, flag_skip: %o, flag_negate: %o}")), permission.name, permission.id, value.value, value.flag_skip, value.flag_negate); + return globalClient.serverConnection.send_command("channelgroupaddperm", { + cgid: current_group.id, + permid: permission.id, + permvalue: value.value, + permskip: value.flag_skip, + permnegate: value.flag_negate + }); + } + else { + log.info(LogCategory.PERMISSIONS, _translations.Dr0kHgdQ || (_translations.Dr0kHgdQ = tr("Adding or updating channel group grant permission %s. permission.{id: %o, value: %o}")), permission.name, permission.id_grant(), value.granted); + return globalClient.serverConnection.send_command("channelgroupaddperm", { + cgid: current_group.id, + permid: permission.id_grant(), + permvalue: value.granted, + permskip: false, + permnegate: false + }); + } + } + }); + /* FIXME: Use cached permissions */ + editor.trigger_update(); + }); + } + /* list all channel groups */ + { + let group_list = tab_tag.find(".list-group-channel .entries"); + for (let group of globalClient.groups.channelGroups.sort(GroupManager.sorter())) { + let tag = $.spawn("div").addClass("group").attr("group-id", group.id); + globalClient.fileManager.icons.generateTag(group.properties.iconid).appendTo(tag); + { + let name = $.spawn("a").text(group.name + " (" + group.id + ")").addClass("name"); + if (group.properties.savedb) + name.addClass("savedb"); + if (globalClient.channelTree.server.properties.virtualserver_default_channel_group == group.id) + name.addClass("default"); + name.appendTo(tag); + } + tag.appendTo(group_list); + tag.on('click', event => { + current_group = group; + group_list.find(".selected").removeClass("selected"); + tag.addClass("selected"); + //TODO trigger only if the editor is in channel group mode! + editor.trigger_update(); + }); + } + /* because the server menu is the first which will be shown */ + setTimeout(() => group_list.find('.group').first().trigger('click'), 0); + } + } + /* + b_virtualserver_servergroup_permission_list + b_virtualserver_channel_permission_list + b_virtualserver_client_permission_list + b_virtualserver_channelgroup_permission_list + b_virtualserver_channelclient_permission_list + b_virtualserver_playlist_permission_list + */ + function apply_server_groups(editor, tab_tag) { + let current_group; + /* list all groups */ + { + let group_list = tab_tag.find(".list-group-server .entries"); + for (let group of globalClient.groups.serverGroups.sort(GroupManager.sorter())) { + let tag = $.spawn("div").addClass("group").attr("group-id", group.id); + globalClient.fileManager.icons.generateTag(group.properties.iconid).appendTo(tag); + { + let name = $.spawn("a").text(group.name + " (" + group.id + ")").addClass("name"); + if (group.properties.savedb) + name.addClass("savedb"); + if (globalClient.channelTree.server.properties.virtualserver_default_server_group == group.id) + name.addClass("default"); + name.appendTo(tag); + } + tag.appendTo(group_list); + tag.on('click', event => { + current_group = group; + group_list.find(".selected").removeClass("selected"); + tag.addClass("selected"); + editor.trigger_update(); + }); + } + /* because the server menu is the first which will be shown */ + setTimeout(() => group_list.find('.group').first().trigger('click'), 0); + } + /* the editor */ + { + const pe_server = tab_tag.find("permission-editor.group-server"); + tab_tag.on('show', event => { + console.error("Server tab show"); + pe_server.append(editor.container); + if (globalClient.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_SERVERGROUP_PERMISSION_LIST).granted(1)) + editor.set_mode(PermissionEditorMode.VISIBLE); + else { + editor.set_mode(PermissionEditorMode.NO_PERMISSION); + return; + } + editor.set_listener_update(() => { + globalClient.groups.request_permissions(current_group).then(result => editor.set_permissions(result)).catch(error => { + console.log(error); //TODO handling? + }); + }); + editor.set_listener((permission, value) => { + if (!current_group) + return Promise.reject("unset server group"); + if (value.remove) { + /* remove the permission */ + if (typeof (value.value) !== "undefined") { + log.info(LogCategory.PERMISSIONS, _translations.buddzElO || (_translations.buddzElO = tr("Removing server group permission %s. permission.id: %o")), permission.name, permission.id); + return globalClient.serverConnection.send_command("servergroupdelperm", { + sgid: current_group.id, + permid: permission.id, + }); + } + else { + log.info(LogCategory.PERMISSIONS, _translations.EAsiW60n || (_translations.EAsiW60n = tr("Removing server group grant permission %s. permission.id: %o")), permission.name, permission.id_grant(), value.granted); + return globalClient.serverConnection.send_command("servergroupdelperm", { + sgid: current_group.id, + permid: permission.id_grant(), + }); + } + } + else { + /* add the permission */ + if (typeof (value.value) !== "undefined") { + log.info(LogCategory.PERMISSIONS, _translations.FimEJKlf || (_translations.FimEJKlf = tr("Adding or updating server group permission %s. permission.{id: %o, value: %o, flag_skip: %o, flag_negate: %o}")), permission.name, permission.id, value.value, value.flag_skip, value.flag_negate); + return globalClient.serverConnection.send_command("servergroupaddperm", { + sgid: current_group.id, + permid: permission.id, + permvalue: value.value, + permskip: value.flag_skip, + permnegate: value.flag_negate + }); + } + else { + log.info(LogCategory.PERMISSIONS, _translations.m6BgWvPe || (_translations.m6BgWvPe = tr("Adding or updating server group grant permission %s. permission.{id: %o, value: %o}")), permission.name, permission.id_grant(), value.granted); + return globalClient.serverConnection.send_command("servergroupaddperm", { + sgid: current_group.id, + permid: permission.id_grant(), + permvalue: value.granted, + permskip: false, + permnegate: false + }); + } + } + }); + editor.trigger_update(); + }); + } + } +})(Modals || (Modals = {})); +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["e9fc308fbc7dd673ccc12df343a8fbe32f2790467fa2716feacf070b441aa9dd"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["e9fc308fbc7dd673ccc12df343a8fbe32f2790467fa2716feacf070b441aa9dd"] = "e9fc308fbc7dd673ccc12df343a8fbe32f2790467fa2716feacf070b441aa9dd"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "Vzv70U1I", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPlaylistEdit.ts (10,21)" }, { name: "NQh5eGr5", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPlaylistEdit.ts (43,21)" }, { name: "tmSzNTzy", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPlaylistEdit.ts (83,21)" }, { name: "n7VcWm07", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPlaylistEdit.ts (108,46)" }, { name: "a_TZcP0H", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPlaylistEdit.ts (108,82)" }, { name: "NB7sciFG", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPlaylistEdit.ts (130,46)" }, { name: "mnek9ENK", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPlaylistEdit.ts (130,82)" }, { name: "m6AIHquf", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPlaylistEdit.ts (137,36)" }, { name: "jEelVGXf", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPlaylistEdit.ts (137,57)" }, { name: "eWqk1aTM", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPlaylistEdit.ts (178,27)" }, { name: "zynyuRv_", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPlaylistEdit.ts (207,50)" }, { name: "EaOaEwhp", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPlaylistEdit.ts (207,80)" }, { name: "v6RuZ030", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPlaylistEdit.ts (230,31)" }, { name: "I43FEeaW", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPlaylistEdit.ts (248,38)" }, { name: "KwvQCSiF", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPlaylistEdit.ts (248,65)" }, { name: "YI9EW4YZ", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPlaylistEdit.ts (352,30)" }, { name: "LuuiZhoN", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPlaylistEdit.ts (352,67)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +/// +/// +/// +var Modals; +(function (Modals) { + function spawnPlaylistSongInfo(song) { + let modal; + modal = createModal({ + header: _translations.Vzv70U1I || (_translations.Vzv70U1I = tr("Song info")), + body: () => { + try { + song.metadata = JSON.parse(song.song_metadata); + } + catch (e) { } + let template = $("#tmpl_playlist_edit-song_info").renderTag(song); + template = $.spawn("div").append(template); + const text_area = template.find(".property-metadata-raw textarea"); + template.find(".toggle-metadata").on('click', event => { + if (text_area.is(":visible")) { + template.find(".toggle-metadata").text("show"); + } + else { + template.find(".toggle-metadata").text("hide"); + } + text_area.slideToggle({ duration: 250 }); + }); + text_area.hide(); + return template; + }, + footer: undefined, + width: 750 + }); + modal.open(); + } + Modals.spawnPlaylistSongInfo = spawnPlaylistSongInfo; + function spawnSongAdd(playlist, callback_add) { + let modal; + modal = createModal({ + header: _translations.NQh5eGr5 || (_translations.NQh5eGr5 = tr("Add a song")), + body: () => { + let template = $("#tmpl_playlist_edit-song_add").renderTag(); + template = $.spawn("div").append(template); + const url = template.find(".property-url .value"); + const url_loader = template.find(".property-loader .value"); + const button_add = template.find(".container-buttons .button-add"); + const button_cancel = template.find(".container-buttons .button-cancel"); + url.on('change keyup', event => { + button_add.prop("disabled", url.val().toString().length == 0); + }).trigger('change'); + button_cancel.on('click', event => modal.close()); + button_add.on('click', event => { + callback_add(url.val(), url_loader.val()); + modal.close(); + }); + return template; + }, + footer: undefined, + width: 750 + }); + modal.open(); + } + Modals.spawnSongAdd = spawnSongAdd; + function spawnPlaylistEdit(client, playlist) { + let modal; + let changed_properties = {}; + let changed_permissions = {}; + let callback_permission_update; + const update_save = () => { + const save_button = modal.htmlTag.find(".buttons .button-save"); + save_button.prop("disabled", (Object.keys(changed_properties).length + Object.keys(changed_permissions).length) == 0); + }; + modal = createModal({ + header: _translations.tmSzNTzy || (_translations.tmSzNTzy = tr("Edit playlist")), + body: () => { + let template = $("#tmpl_playlist_edit").renderTag().tabify(); + callback_permission_update = apply_permissions(template, client, playlist, (key, value) => { + console.log("Change permission %o => %o", key, value); + changed_permissions[key] = value; + update_save(); + }); + const callback_song_id = apply_songs(template, client, playlist); + apply_properties(template, client, playlist, (key, value) => { + console.log("Change property %o => %o", key, value); + changed_properties[key] = value; + update_save(); + }, callback_song_id); + template.find(".buttons .button-save").on('click', event => { + if (Object.keys(changed_properties).length != 0) { + changed_properties["playlist_id"] = playlist.playlist_id; + client.serverConnection.send_command("playlistedit", changed_properties).then(() => { + changed_properties = {}; + update_save(); + }).catch(error => { + if (error instanceof CommandResult) + error = error.extra_message || error.message; + createErrorModal(_translations.n7VcWm07 || (_translations.n7VcWm07 = tr("Failed to change properties.")), (_translations.a_TZcP0H || (_translations.a_TZcP0H = tr("Failed to change playlist properties.
    Error: "))) + error).open(); + }); + } + if (Object.keys(changed_permissions).length != 0) { + const array = []; + for (const permission_key of Object.keys(changed_permissions)) { + array.push({ + permvalue: changed_permissions[permission_key], + permnegated: false, + permskip: false, + permsid: permission_key + }); + } + array[0]["playlist_id"] = playlist.playlist_id; + client.serverConnection.send_command("playlistaddperm", array).then(() => { + changed_permissions = {}; + update_save(); + }).catch(error => { + if (error instanceof CommandResult) + error = error.extra_message || error.message; + createErrorModal(_translations.NB7sciFG || (_translations.NB7sciFG = tr("Failed to change permission.")), (_translations.mnek9ENK || (_translations.mnek9ENK = tr("Failed to change playlist permissions.
    Error: "))) + error).open(); + }); + } + }); + template.find(".buttons .button-close").on('click', event => { + if ((Object.keys(changed_properties).length + Object.keys(changed_permissions).length) != 0) { + Modals.spawnYesNo(_translations.m6AIHquf || (_translations.m6AIHquf = tr("Are you sure?")), _translations.jEelVGXf || (_translations.jEelVGXf = tr("Do you really want to discard all your changes?")), result => { + if (result) + modal.close(); + }); + return; + } + modal.close(); + }); + return template; + }, + footer: undefined, + width: 750 + }); + update_save(); + modal.open(); + return modal; + } + Modals.spawnPlaylistEdit = spawnPlaylistEdit; + function apply_songs(tag, client, playlist) { + const owns_playlist = playlist.playlist_owner_dbid == client.getClient().properties.client_database_id; + const song_tag = tag.find(".container-songs"); + let replaying_song_id = 0; + let selected_song; + const set_song_info = (text) => { + const tag = song_tag.find(".info-message"); + if (text && text.length > 0) { + tag.text(text).show(); + } + else + tag.hide(); + }; + const set_current_song = (id) => { + /* this method shall enforce an update */ + replaying_song_id = id; + update_songs(); + }; + const update_songs = () => { + set_song_info(_translations.eWqk1aTM || (_translations.eWqk1aTM = tr("loading song list"))); + client.serverConnection.command_helper.request_playlist_songs(playlist.playlist_id).then(result => { + const entries_tag = song_tag.find(".song-list-entries"); + const entry_template = $("#tmpl_playlist_edit-song_entry"); + entries_tag.empty(); + for (const song of result) { + const rendered = entry_template.renderTag(song); + rendered.find(".button-info").on('click', event => { + spawnPlaylistSongInfo(song); + }); + const button_delete = rendered.find(".button-delete"); + if (!owns_playlist && !client.permissions.neededPermission(PermissionType.I_PLAYLIST_SONG_REMOVE_POWER).granted(playlist.needed_power_song_remove)) + button_delete.detach(); + else + button_delete.on('click', event => { + client.serverConnection.send_command("playlistsongremove", { + playlist_id: playlist.playlist_id, + song_id: song.song_id + }).then(() => { + rendered.slideToggle({ duration: 250, done(animation, jumpedToEnd) { + rendered.detach(); + } }); + rendered.hide(250); + }).catch(error => { + if (error instanceof CommandResult) + error = error.extra_message || error.message; + createErrorModal(_translations.zynyuRv_ || (_translations.zynyuRv_ = tr("Failed to remove song.")), (_translations.EaOaEwhp || (_translations.EaOaEwhp = tr("Failed to remove song/url from the playlist.
    Error: "))) + error).open(); + }); + }); + if (song.song_id == replaying_song_id) + rendered.addClass("playing"); + rendered.on('click', event => { + selected_song = song; + entries_tag.find(".selected").removeClass("selected"); + rendered.addClass("selected"); + }); + entries_tag.append(rendered); + } + const entry_container = song_tag.find(".song-list-entries-container"); + if (entry_container.hasScrollBar()) + entry_container.addClass("scrollbar"); + set_song_info("displaying " + result.length + " songs"); + }).catch(error => { + console.error(error); + set_song_info(_translations.v6RuZ030 || (_translations.v6RuZ030 = tr("failed to load song list"))); + //TODO improve error handling! + }); + }; + song_tag.find(".button-refresh").on('click', event => update_songs()); + song_tag.find(".button-song-add").on('click', event => { + spawnSongAdd(playlist, (url, loader) => { + //playlist_id invoker previous url + client.serverConnection.send_command("playlistsongadd", { + playlist_id: playlist.playlist_id, + invoker: loader, + url: url + }).then(() => { + update_songs(); + }).catch(error => { + if (error instanceof CommandResult) + error = error.extra_message || error.message; + createErrorModal(_translations.I43FEeaW || (_translations.I43FEeaW = tr("Failed to add song.")), (_translations.KwvQCSiF || (_translations.KwvQCSiF = tr("Failed to add song/url to the playlist.
    Error: "))) + error).open(); + }); + }); + }).prop("disabled", !owns_playlist && !client.permissions.neededPermission(PermissionType.I_PLAYLIST_SONG_ADD_POWER).granted(playlist.needed_power_song_add)); + /* setTimeout(update_songs, 100); */ /* We dont have to call that here because it will get called over set_current_song when we received the current song id */ + return set_current_song; + } + function apply_permissions(tag, client, playlist, change_permission) { + const owns_playlist = playlist.playlist_owner_dbid == client.getClient().properties.client_database_id; + const permission_tag = tag.find(".container-permissions"); + const nopermission_tag = tag.find(".container-no-permissions"); + const update_permissions = () => { + if (!client.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_PLAYLIST_PERMISSION_LIST).granted(1)) { + nopermission_tag.show(); + permission_tag.hide(); + } + else { + nopermission_tag.hide(); + permission_tag.show(); + permission_tag.find(".permission input").prop("disabled", true); + client.permissions.requestPlaylistPermissions(playlist.playlist_id).then(permissions => { + permission_tag.find(".permission input") + .val(0) + .prop("disabled", !owns_playlist && !client.permissions.neededPermission(PermissionType.I_PLAYLIST_PERMISSION_MODIFY_POWER).granted(playlist.needed_power_permission_modify)); + for (const permission of permissions) { + const tag = permission_tag.find(".permission[permission='" + permission.type.name + "']"); + if (permission.value != -2) + tag.find("input").val(permission.value); + } + }); + } + }; + permission_tag.find(".permission").each((index, _element) => { + const element = $(_element); + element.find("input").on('change', event => { + console.log(element.find("input").val()); + change_permission(element.attr("permission"), parseInt(element.find("input").val().toString())); + }); + }); + update_permissions(); + return update_permissions; + } + function apply_properties(tag, client, playlist, change_property, callback_current_song) { + const owns_playlist = playlist.playlist_owner_dbid == client.getClient().properties.client_database_id; + client.serverConnection.command_helper.request_playlist_info(playlist.playlist_id).then(info => { + tag.find(".property-owner input") + .val(info.playlist_owner_name + " (" + info.playlist_owner_dbid + ")"); + tag.find(".property-title input") + .val(info.playlist_title) + .prop("disabled", !owns_playlist && !client.permissions.neededPermission(PermissionType.I_PLAYLIST_MODIFY_POWER).granted(playlist.needed_power_modify)) + .on('change', event => { + change_property("playlist_title", event.target.value); + }); + tag.find(".property-description textarea") + .val(info.playlist_description) + .prop("disabled", !owns_playlist && !client.permissions.neededPermission(PermissionType.I_PLAYLIST_MODIFY_POWER).granted(playlist.needed_power_modify)) + .on('change', event => { + change_property("playlist_description", event.target.value); + }); + tag.find(".property-type select") + .val(info.playlist_type.toString()) + .prop("disabled", !owns_playlist && !client.permissions.neededPermission(PermissionType.I_PLAYLIST_MODIFY_POWER).granted(playlist.needed_power_modify)) + .on('change', event => { + change_property("playlist_description", event.target.selectedIndex.toString()); + }); + tag.find(".property-replay-mode select") + .val(info.playlist_replay_mode.toString()) + .prop("disabled", !owns_playlist && !client.permissions.neededPermission(PermissionType.I_PLAYLIST_MODIFY_POWER).granted(playlist.needed_power_modify)) + .on('change', event => { + change_property("playlist_replay_mode", event.target.selectedIndex.toString()); + }); + tag.find(".property-flag-delete-played input") + .prop("checked", info.playlist_flag_delete_played) + .prop("disabled", !owns_playlist && !client.permissions.neededPermission(PermissionType.I_PLAYLIST_MODIFY_POWER).granted(playlist.needed_power_modify)) + .on('change', event => { + change_property("playlist_flag_delete_played", event.target.checked ? "1" : "0"); + }); + tag.find(".property-current-song input") + .val(info.playlist_current_song_id); + callback_current_song(info.playlist_current_song_id); + tag.find(".property-flag-finished input") + .prop("checked", info.playlist_flag_finished) + .prop("disabled", !owns_playlist && !client.permissions.neededPermission(PermissionType.I_PLAYLIST_MODIFY_POWER).granted(playlist.needed_power_modify)) + .on('change', event => { + change_property("playlist_flag_finished", event.target.checked ? "1" : "0"); + }); + }).catch(error => { + if (error instanceof CommandResult) + error = error.extra_message || error.message; + createErrorModal(_translations.YI9EW4YZ || (_translations.YI9EW4YZ = tr("Failed to query playlist info")), (_translations.LuuiZhoN || (_translations.LuuiZhoN = tr("Failed to query playlist info.
    Error:"))) + error).open(); + }); + } +})(Modals || (Modals = {})); +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["410ea43c3dc2c1ee49cfbfb643a182f0e9981c36f14cd6a6a6e29f5ca30a135a"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["410ea43c3dc2c1ee49cfbfb643a182f0e9981c36f14cd6a6a6e29f5ca30a135a"] = "410ea43c3dc2c1ee49cfbfb643a182f0e9981c36f14cd6a6a6e29f5ca30a135a"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "nIUCwZBR", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPlaylistList.ts (81,21)" }, { name: "tdwJZI2z", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPlaylistList.ts (99,44)" }, { name: "CBw6VfB6", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPlaylistList.ts (99,79)" }, { name: "g2hAzei0", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPlaylistList.ts (120,42)" }, { name: "WrenQWBa", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPlaylistList.ts (120,75)" }, { name: "a7w2YrqD", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPlaylistList.ts (132,39)" }, { name: "T4u_R_ZA", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPlaylistList.ts (132,60)" }, { name: "BDEB3Orm", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPlaylistList.ts (135,49)" }, { name: "LYoSicUY", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPlaylistList.ts (135,84)" }, { name: "kAx45VX1", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPlaylistList.ts (143,50)" }, { name: "euCGSQsE", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPlaylistList.ts (143,83)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +/// +/// +/// +var Modals; +(function (Modals) { + function spawnPlaylistManage(client) { + let modal; + let selected_playlist; + let available_playlists; + let highlight_own = settings.global("playlist-list-highlight-own", true); + const update_selected = () => { + const buttons = modal.htmlTag.find(".header .buttons"); + buttons.find(".button-playlist-edit").prop("disabled", !selected_playlist); + buttons.find(".button-playlist-delete").prop("disabled", !selected_playlist || !( /* not owner or permission */client.permissions.neededPermission(PermissionType.I_PLAYLIST_DELETE_POWER).granted(selected_playlist.needed_power_delete) || /* client has permissions */ + client.getClient().properties.client_database_id == selected_playlist.playlist_owner_dbid /* client is playlist owner */)); + buttons.find(".button-playlist-create").prop("disabled", !client.permissions.neededPermission(PermissionType.B_PLAYLIST_CREATE).granted(1)); + if (selected_playlist) { + buttons.find(".button-playlist-edit").prop("disabled", false); + } + }; + const update_list = () => __awaiter(this, void 0, void 0, function* () { + const info_tag = modal.htmlTag.find(".footer .info a"); + info_tag.text("loading..."); + selected_playlist = undefined; + update_selected(); + try { + available_playlists = yield client.serverConnection.command_helper.request_playlist_list(); + } + catch (error) { + info_tag.text("failed to query playlist list."); + //FIXME error handling? + return; + } + const entries_tag = modal.htmlTag.find(".playlist-list-entries"); + const entry_template = $("#tmpl_playlist_list-list_entry"); + entries_tag.empty(); + const owndbid = client.getClient().properties.client_database_id; + for (const query of available_playlists) { + const tag = entry_template.renderTag(query).on('click', event => { + entries_tag.find(".entry.selected").removeClass("selected"); + $(event.target).parent(".entry").addClass("selected"); + selected_playlist = query; + update_selected(); + }); + if (highlight_own && query.playlist_owner_dbid == owndbid) + tag.addClass("highlighted"); + entries_tag.append(tag); + } + const entry_container = modal.htmlTag.find(".playlist-list-entries-container"); + if (entry_container.hasScrollBar()) + entry_container.addClass("scrollbar"); + info_tag.text("Showing " + available_playlists.length + " entries"); + update_selected(); + }); + modal = createModal({ + header: _translations.nIUCwZBR || (_translations.nIUCwZBR = tr("Manage playlists")), + body: () => { + let template = $("#tmpl_playlist_list").renderTag(); + /* first open the modal */ + setTimeout(() => { + const entry_container = template.find(".playlist-list-entries-container"); + if (entry_container.hasScrollBar()) + entry_container.addClass("scrollbar"); + }, 100); + template.find(".footer .buttons .button-refresh").on('click', update_list); + template.find(".button-playlist-create").on('click', event => { + const single_handler = { + function: command => { + const json = command.arguments; + update_list().then(() => { + Modals.spawnYesNo(_translations.tdwJZI2z || (_translations.tdwJZI2z = tr("Playlist created successful")), _translations.CBw6VfB6 || (_translations.CBw6VfB6 = tr("The playlist has been successfully created.
    Should we open the editor?")), result => { + if (result) { + for (const playlist of available_playlists) { + if (playlist.playlist_id == json[0]["playlist_id"]) { + Modals.spawnPlaylistEdit(client, playlist).close_listener.push(update_list); + return; + } + } + } + }); + }); + return true; + }, + command: "notifyplaylistcreated" + }; + client.serverConnection.command_handler_boss().register_single_handler(single_handler); + client.serverConnection.send_command("playlistcreate").catch(error => { + client.serverConnection.command_handler_boss().remove_single_handler(single_handler); + if (error instanceof CommandResult) + error = error.extra_message || error.message; + createErrorModal(_translations.g2hAzei0 || (_translations.g2hAzei0 = tr("Unable to create playlist")), (_translations.WrenQWBa || (_translations.WrenQWBa = tr("Failed to create playlist
    Message: "))) + error).open(); + }); + }); + template.find(".button-playlist-edit").on('click', event => { + if (!selected_playlist) + return; + Modals.spawnPlaylistEdit(client, selected_playlist).close_listener.push(update_list); + }); + template.find(".button-playlist-delete").on('click', () => { + if (!selected_playlist) + return; + Modals.spawnYesNo(_translations.a7w2YrqD || (_translations.a7w2YrqD = tr("Are you sure?")), _translations.T4u_R_ZA || (_translations.T4u_R_ZA = tr("Do you really want to delete this playlist?")), result => { + if (result) { + client.serverConnection.send_command("playlistdelete", { playlist_id: selected_playlist.playlist_id }).then(() => { + createInfoModal(_translations.BDEB3Orm || (_translations.BDEB3Orm = tr("Playlist deleted successful")), _translations.LYoSicUY || (_translations.LYoSicUY = tr("This playlist has been deleted successfully."))).open(); + update_list(); + }).catch(error => { + if (error instanceof CommandResult) { + /* TODO extra handling here */ + //if(error.id == ErrorID.PLAYLIST_IS_IN_USE) { } + error = error.extra_message || error.message; + } + createErrorModal(_translations.kAx45VX1 || (_translations.kAx45VX1 = tr("Unable to delete playlist")), (_translations.euCGSQsE || (_translations.euCGSQsE = tr("Failed to delete playlist
    Message: "))) + error).open(); + }); + } + }); + }); + template.find(".input-search").on('change keyup', () => { + const text = (template.find(".input-search").val() || "").toLowerCase(); + if (text.length == 0) { + template.find(".playlist-list-entries .entry").show(); + } + else { + template.find(".playlist-list-entries .entry").each((_, e) => { + const element = $(e); + if (element.text().toLowerCase().indexOf(text) == -1) + element.hide(); + else + element.show(); + }); + } + }); + template.find(".button-highlight-own").on('change', event => { + const flag = event.target.checked; + settings.changeGlobal("playlist-list-highlight-own", flag); + if (flag) { + const owndbid = client.getClient().properties.client_database_id; + template.find(".playlist-list-entries .entry").each((index, _element) => { + const element = $(_element); + if (parseInt(element.attr("playlist-owner-dbid")) == owndbid) + element.addClass("highlighted"); + }); + } + else { + template.find(".playlist-list-entries .highlighted").removeClass("highlighted"); + } + }).prop("checked", highlight_own); + return template; + }, + footer: undefined, + width: 750 + }); + update_list(); + modal.open(); + } + Modals.spawnPlaylistManage = spawnPlaylistManage; +})(Modals || (Modals = {})); +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["d30dd7a3f50901e5febbc38e30fb6224f5e4ed888c0f4fa7bf99fe2aeb94db13"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["d30dd7a3f50901e5febbc38e30fb6224f5e4ed888c0f4fa7bf99fe2aeb94db13"] = "d30dd7a3f50901e5febbc38e30fb6224f5e4ed888c0f4fa7bf99fe2aeb94db13"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "okdb6XT1", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPoke.ts (13,21)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +/// +/// +/// +var Modals; +(function (Modals) { + function spawnPoke(invoker, message) { + let modal; + modal = createModal({ + header: _translations.okdb6XT1 || (_translations.okdb6XT1 = tr("You have been poked!")), + body: () => { + let template = $("#tmpl_poke_popup").renderTag({ + "invoker": ClientEntry.chatTag(invoker.id, invoker.name, invoker.unique_id, true), + "message": message + }); + template = $.spawn("div").append(template); + template.find(".button-close").on('click', event => modal.close()); + return template; + }, + footer: undefined, + width: 750 + }); + modal.open(); + } + Modals.spawnPoke = spawnPoke; +})(Modals || (Modals = {})); +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["01ff91f95f4ae8eb6f70a7e16b455d57e8626e346ef7af1720c934bccbdb4948"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["01ff91f95f4ae8eb6f70a7e16b455d57e8626e346ef7af1720c934bccbdb4948"] = "01ff91f95f4ae8eb6f70a7e16b455d57e8626e346ef7af1720c934bccbdb4948"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "i0fIl3oL", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalQuery.ts (9,21)" }, { name: "VWS3eA1A", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalQuery.ts (18,42)" }, { name: "HfLP3u1c", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalQuery.ts (18,66)" }, { name: "sUeYqhYy", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalQuery.ts (45,42)" }, { name: "_NxrXhp1", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalQuery.ts (45,74)" }, { name: "phsdCzyk", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalQuery.ts (65,36)" }, { name: "H3PUMR9C", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalQuery.ts (65,69)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +/// +/// +/// +var Modals; +(function (Modals) { + function spawnQueryCreate(callback_created) { + let modal; + modal = createModal({ + header: _translations.i0fIl3oL || (_translations.i0fIl3oL = tr("Create a server query login")), + body: () => { + let template = $("#tmpl_query_create").renderTag(); + template = $.spawn("div").append(template); + template.find(".button-close").on('click', event => modal.close()); + template.find(".button-create").on('click', event => { + const name = template.find(".input-name").val(); + if (name.length < 3 || name.length > 64) { + createErrorModal(_translations.VWS3eA1A || (_translations.VWS3eA1A = tr("Invalid username")), _translations.HfLP3u1c || (_translations.HfLP3u1c = tr("Please enter a valid name!"))).open(); + return; + } + //client_login_password + const single_handler = { + function: command => { + const json = command.arguments[0]; + spawnQueryCreated({ + username: name, + password: json.client_login_password + }, true); + if (callback_created) + callback_created(name, json.client_login_password); + return true; + } + }; + globalClient.serverConnection.command_handler_boss().register_single_handler(single_handler); + globalClient.serverConnection.send_command("querycreate", { + client_login_name: name + }).catch(error => { + globalClient.serverConnection.command_handler_boss().remove_single_handler(single_handler); + if (error instanceof CommandResult) + error = error.extra_message || error.message; + createErrorModal(_translations.sUeYqhYy || (_translations.sUeYqhYy = tr("Unable to create account")), (_translations._NxrXhp1 || (_translations._NxrXhp1 = tr("Failed to create account
    Message: "))) + error).open(); + }); + modal.close(); + //TODO create account + }); + return template; + }, + footer: undefined, + width: 750 + }); + modal.open(); + } + Modals.spawnQueryCreate = spawnQueryCreate; + function spawnQueryCreated(credentials, just_created) { + let modal; + modal = createModal({ + header: just_created ? _translations.phsdCzyk || (_translations.phsdCzyk = tr("Server query credentials")) : _translations.H3PUMR9C || (_translations.H3PUMR9C = tr("New server query credentials")), + body: () => { + let template = $("#tmpl_query_created").renderTag(credentials); + template = $.spawn("div").append(template); + template.find(".button-close").on('click', event => modal.close()); + template.find(".query_name").text(credentials.username); + template.find(".query_password").text(credentials.password); + template.find(".btn_copy_name").on('click', () => { + template.find(".query_name").select(); + document.execCommand("copy"); + }); + template.find(".btn_copy_password").on('click', () => { + template.find(".query_password").select(); + document.execCommand("copy"); + }); + return template; + }, + footer: undefined, + width: 750 + }); + modal.open(); + } + Modals.spawnQueryCreated = spawnQueryCreated; +})(Modals || (Modals = {})); +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["3e1485745c7efc1d480698267e44a5aa2180cb996a613004e480ed3d2aed118a"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["3e1485745c7efc1d480698267e44a5aa2180cb996a613004e480ed3d2aed118a"] = "3e1485745c7efc1d480698267e44a5aa2180cb996a613004e480ed3d2aed118a"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "GmzgCKRw", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalQueryManage.ts (55,21)" }, { name: "ULvkthEJ", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalQueryManage.ts (74,38)" }, { name: "Flid_Dnh", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalQueryManage.ts (74,65)" }, { name: "ZP4DmU5Y", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalQueryManage.ts (82,50)" }, { name: "oPA981GT", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalQueryManage.ts (82,82)" }, { name: "k_mQLmYi", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalQueryManage.ts (84,49)" }, { name: "NCQMkX7N", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalQueryManage.ts (84,85)" }, { name: "u8hcZjr9", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalQueryManage.ts (93,38)" }, { name: "MKf0Oy9V", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalQueryManage.ts (93,71)" }, { name: "fwE3FxKx", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalQueryManage.ts (115,50)" }, { name: "JN32xB1a", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalQueryManage.ts (115,83)" }, { name: "k6O9cTdo", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalQueryManage.ts (123,39)" }, { name: "blDGb16q", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalQueryManage.ts (123,60)" }, { name: "XwJxu075", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalQueryManage.ts (130,50)" }, { name: "Ncf1HghS", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalQueryManage.ts (130,82)" }, { name: "WuT4UVFU", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalQueryManage.ts (132,49)" }, { name: "Wg3DKkcV", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalQueryManage.ts (132,85)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +/// +/// +/// +var Modals; +(function (Modals) { + function spawnQueryManage(client) { + let modal; + let selected_query; + const update_selected = () => { + const buttons = modal.htmlTag.find(".header .buttons"); + //TODO gray out if no permissions (Server needs to send that... :D) + buttons.find(".button-query-delete").prop("disabled", selected_query === undefined); + buttons.find(".button-query-rename").prop("disabled", selected_query === undefined); + buttons.find(".button-query-change-password").prop("disabled", selected_query === undefined); + }; + const update_list = () => { + const info_tag = modal.htmlTag.find(".footer .info a"); + info_tag.text("loading..."); + client.serverConnection.command_helper.current_virtual_server_id().then(server_id => { + client.serverConnection.command_helper.request_query_list(server_id).then(result => { + selected_query = undefined; + const entries_tag = modal.htmlTag.find(".query-list-entries"); + const entry_template = $("#tmpl_query_manager-list_entry"); + entries_tag.empty(); + for (const query of result.queries || []) { + entries_tag.append(entry_template.renderTag(query).on('click', event => { + entries_tag.find(".entry.selected").removeClass("selected"); + $(event.target).parent(".entry").addClass("selected"); + selected_query = query; + update_selected(); + })); + } + const entry_container = modal.htmlTag.find(".query-list-entries-container"); + if (entry_container.hasScrollBar()) + entry_container.addClass("scrollbar"); + if (!result || result.flag_all) { + info_tag.text("Showing all server queries"); + } + else { + info_tag.text("Showing your server queries"); + } + update_selected(); + }); + }); + //TODO error handling + }; + modal = createModal({ + header: _translations.GmzgCKRw || (_translations.GmzgCKRw = tr("Manage query accounts")), + body: () => { + let template = $("#tmpl_query_manager").renderTag(); + template = $.spawn("div").append(template); + /* first open the modal */ + setTimeout(() => { + const entry_container = template.find(".query-list-entries-container"); + if (entry_container.hasScrollBar()) + entry_container.addClass("scrollbar"); + }, 100); + template.find(".footer .buttons .button-refresh").on('click', update_list); + template.find(".button-query-create").on('click', () => { + Modals.spawnQueryCreate((user, pass) => update_list()); + }); + template.find(".button-query-rename").on('click', () => { + if (!selected_query) + return; + createInputModal(_translations.ULvkthEJ || (_translations.ULvkthEJ = tr("Change account name")), _translations.Flid_Dnh || (_translations.Flid_Dnh = tr("Enter the new name for the login:
    ")), text => text.length >= 3, result => { + if (result) { + client.serverConnection.send_command("queryrename", { + client_login_name: selected_query.username, + client_new_login_name: result + }).catch(error => { + if (error instanceof CommandResult) + error = error.extra_message || error.message; + createErrorModal(_translations.ZP4DmU5Y || (_translations.ZP4DmU5Y = tr("Unable to rename account")), (_translations.oPA981GT || (_translations.oPA981GT = tr("Failed to rename account
    Message: "))) + error).open(); + }).then(() => { + createInfoModal(_translations.k_mQLmYi || (_translations.k_mQLmYi = tr("Account successfully renamed")), _translations.NCQMkX7N || (_translations.NCQMkX7N = tr("The query account has been renamed!"))).open(); + update_list(); + }); + } + }).open(); + }); + template.find(".button-query-change-password").on('click', () => { + if (!selected_query) + return; + createInputModal(_translations.u8hcZjr9 || (_translations.u8hcZjr9 = tr("Change account's password")), _translations.MKf0Oy9V || (_translations.MKf0Oy9V = tr("Enter a new password (leave blank for auto generation):
    ")), text => true, result => { + if (result !== false) { + const single_handler = { + command: "notifyquerypasswordchanges", + function: command => { + Modals.spawnQueryCreated({ + username: command.arguments[0]["client_login_name"], + password: command.arguments[0]["client_login_password"] + }, false); + return true; + } + }; + client.serverConnection.command_handler_boss().register_single_handler(single_handler); + client.serverConnection.send_command("querychangepassword", { + client_login_name: selected_query.username, + client_login_password: result + }).catch(error => { + client.serverConnection.command_handler_boss().remove_single_handler(single_handler); + if (error instanceof CommandResult) + error = error.extra_message || error.message; + createErrorModal(_translations.fwE3FxKx || (_translations.fwE3FxKx = tr("Unable to change password")), (_translations.JN32xB1a || (_translations.JN32xB1a = tr("Failed to change password
    Message: "))) + error).open(); + }); + } + }).open(); + }); + template.find(".button-query-delete").on('click', () => { + if (!selected_query) + return; + Modals.spawnYesNo(_translations.k6O9cTdo || (_translations.k6O9cTdo = tr("Are you sure?")), _translations.blDGb16q || (_translations.blDGb16q = tr("Do you really want to delete this account?")), result => { + if (result) { + client.serverConnection.send_command("querydelete", { + client_login_name: selected_query.username + }).catch(error => { + if (error instanceof CommandResult) + error = error.extra_message || error.message; + createErrorModal(_translations.XwJxu075 || (_translations.XwJxu075 = tr("Unable to delete account")), (_translations.Ncf1HghS || (_translations.Ncf1HghS = tr("Failed to delete account
    Message: "))) + error).open(); + }).then(() => { + createInfoModal(_translations.WuT4UVFU || (_translations.WuT4UVFU = tr("Account successfully deleted")), _translations.Wg3DKkcV || (_translations.Wg3DKkcV = tr("The query account has been successfully deleted!"))).open(); + update_list(); + }); + } + }); + }); + template.find(".input-search").on('change keyup', () => { + const text = (template.find(".input-search").val() || "").toLowerCase(); + if (text.length == 0) { + template.find(".query-list-entries .entry").show(); + } + else { + template.find(".query-list-entries .entry").each((_, e) => { + const element = $(e); + if (element.text().toLowerCase().indexOf(text) == -1) + element.hide(); + else + element.show(); + }); + } + }); + return template; + }, + footer: undefined, + width: 750 + }); + update_list(); + modal.open(); + } + Modals.spawnQueryManage = spawnQueryManage; +})(Modals || (Modals = {})); +typeof _translations !== "undefined" || (_translations = {}); +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}); +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}); +unique_translation_check: { + if (_translations["declared_files"]["72abf2a1657d8a2c16b9bc58f4676dd9d92f3a5b082d8bbefa32c7f07d9c8121"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?"); + break unique_translation_check; + } + else + _translations["declared_files"]["72abf2a1657d8a2c16b9bc58f4676dd9d92f3a5b082d8bbefa32c7f07d9c8121"] = "72abf2a1657d8a2c16b9bc58f4676dd9d92f3a5b082d8bbefa32c7f07d9c8121"; + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of [{ name: "xWglwJfu", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/AudioResampler.ts (7,82)" }, { name: "gYuR48US", path: "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/voice/AudioResampler.ts (12,26)" }]) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a; + } +} +class AudioResampler { + constructor(targetSampleRate) { + this.targetSampleRate = targetSampleRate; + if (this.targetSampleRate < 3000 || this.targetSampleRate > 384000) + throw _translations.xWglwJfu || (_translations.xWglwJfu = tr("The target sample rate is outside the range [3000, 384000].")); + } + resample(buffer) { + if (!buffer) { + console.warn(_translations.gYuR48US || (_translations.gYuR48US = tr("Received empty buffer as input! Returning empty output!"))); + return Promise.resolve(buffer); + } + //console.log("Encode from %i to %i", buffer.sampleRate, this.targetSampleRate); + if (buffer.sampleRate == this.targetSampleRate) + return Promise.resolve(buffer); + let context; + context = new (window.webkitOfflineAudioContext || window.OfflineAudioContext)(buffer.numberOfChannels, Math.ceil(buffer.length * this.targetSampleRate / buffer.sampleRate), this.targetSampleRate); + let source = context.createBufferSource(); + source.buffer = buffer; + source.start(0); + source.connect(context.destination); + if (typeof (this._use_promise) === "undefined") { + this._use_promise = navigator.browserSpecs.name != 'Safari'; + } + if (this._use_promise) + return context.startRendering(); + else { + return new Promise((resolve, reject) => { + context.oncomplete = event => resolve(event.renderedBuffer); + try { + context.startRendering(); + } + catch (ex) { + reject(ex); + } + }); + } + } +} +//# sourceMappingURL=shared.js.map +//# sourceMappingURL=client.js.map \ No newline at end of file diff --git a/test/js/load.js b/test/js/load.js new file mode 100644 index 00000000..3b4e10db --- /dev/null +++ b/test/js/load.js @@ -0,0 +1,797 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var app; +(function (app) { + let Type; + (function (Type) { + Type[Type["UNKNOWN"] = 0] = "UNKNOWN"; + Type[Type["CLIENT_RELEASE"] = 1] = "CLIENT_RELEASE"; + Type[Type["CLIENT_DEBUG"] = 2] = "CLIENT_DEBUG"; + Type[Type["WEB_DEBUG"] = 3] = "WEB_DEBUG"; + Type[Type["WEB_RELEASE"] = 4] = "WEB_RELEASE"; + })(Type = app.Type || (app.Type = {})); + app.type = Type.UNKNOWN; +})(app || (app = {})); +var loader; +(function (loader) { + let Stage; + (function (Stage) { + /* + loading loader required files (incl this) + */ + Stage[Stage["INITIALIZING"] = 0] = "INITIALIZING"; + /* + setting up the loading process + */ + Stage[Stage["SETUP"] = 1] = "SETUP"; + /* + loading all style sheet files + */ + Stage[Stage["STYLE"] = 2] = "STYLE"; + /* + loading all javascript files + */ + Stage[Stage["JAVASCRIPT"] = 3] = "JAVASCRIPT"; + /* + loading all template files + */ + Stage[Stage["TEMPLATES"] = 4] = "TEMPLATES"; + /* + initializing static/global stuff + */ + Stage[Stage["JAVASCRIPT_INITIALIZING"] = 5] = "JAVASCRIPT_INITIALIZING"; + /* + finalizing load process + */ + Stage[Stage["FINALIZING"] = 6] = "FINALIZING"; + /* + invoking main task + */ + Stage[Stage["LOADED"] = 7] = "LOADED"; + Stage[Stage["DONE"] = 8] = "DONE"; + })(Stage = loader.Stage || (loader.Stage = {})); + loader.allow_cached_files = false; + let current_stage = Stage.INITIALIZING; + const tasks = {}; + function finished() { + return current_stage == Stage.DONE; + } + loader.finished = finished; + function register_task(stage, task) { + if (current_stage > stage) { + console.warn("Register loading task, but it had already been finished. Executing task anyways!"); + task.function().catch(error => { + console.error("Failed to execute delayed loader task!"); + console.log(" - %s: %o", task.name, error); + displayCriticalError(error); + }); + return; + } + const task_array = tasks[stage] || []; + task_array.push(task); + tasks[stage] = task_array.sort((a, b) => a.priority > b.priority ? 1 : 0); + } + loader.register_task = register_task; + function execute() { + return __awaiter(this, void 0, void 0, function* () { + const load_begin = Date.now(); + let begin = Date.now(); + let end; + while (current_stage <= Stage.LOADED) { + let current_tasks = []; + while ((tasks[current_stage] || []).length > 0) { + if (current_tasks.length == 0 || current_tasks[0].priority == tasks[current_stage][0].priority) { + current_tasks.push(tasks[current_stage].pop()); + } + else + break; + } + const errors = []; + const promises = []; + for (const task of current_tasks) { + try { + console.debug("Executing loader %s (%d)", task.name, task.priority); + promises.push(task.function().catch(error => { + errors.push({ + task: task, + error: error + }); + return Promise.resolve(); + })); + } + catch (error) { + errors.push({ + task: task, + error: error + }); + } + } + yield Promise.all([...promises]); + if (errors.length > 0) { + console.error("Failed to execute loader. The following tasks failed (%d):", errors.length); + for (const error of errors) + console.error(" - %s: %o", error.task.name, error.error); + throw "failed to process step " + Stage[current_stage]; + } + if (current_tasks.length == 0) { + if (current_stage < Stage.LOADED) + console.debug("[loader] entering next state (%s). Last state took %dms", Stage[current_stage + 1], (end = Date.now()) - begin); + else + console.debug("[loader] Finish invoke took %dms", (end = Date.now()) - begin); + begin = end; + current_stage += 1; + } + } + console.debug("[loader] finished loader. (Total time: %dms)", Date.now() - load_begin); + }); + } + loader.execute = execute; + function script_name(path) { + if (Array.isArray(path)) { + let buffer = ""; + let _or = " or "; + for (let entry of path) + buffer += _or + script_name(entry); + return buffer.slice(_or.length); + } + else + return "" + path + ""; + } + class SyntaxError { + constructor(source) { + this.source = source; + } + } + function load_script(path) { + return __awaiter(this, void 0, void 0, function* () { + if (Array.isArray(path)) { //We have some fallback + return load_script(path[0]).catch(error => { + if (error instanceof SyntaxError) + return Promise.reject(error.source); + if (path.length > 1) + return load_script(path.slice(1)); + return Promise.reject(error); + }); + } + else { + return new Promise((resolve, reject) => { + const tag = document.createElement("script"); + let error = false; + const error_handler = (event) => { + if (event.filename == tag.src && event.message.indexOf("Illegal constructor") == -1) { //Our tag throw an uncaught error + console.log("msg: %o, url: %o, line: %o, col: %o, error: %o", event.message, event.filename, event.lineno, event.colno, event.error); + window.removeEventListener('error', error_handler); + reject(new SyntaxError(event.error)); + event.preventDefault(); + error = true; + } + }; + window.addEventListener('error', error_handler); + const timeout_handle = setTimeout(() => { + reject("timeout"); + }, 5000); + tag.type = "application/javascript"; + tag.async = true; + tag.defer = true; + tag.onerror = error => { + clearTimeout(timeout_handle); + window.removeEventListener('error', error_handler); + tag.remove(); + reject(error); + }; + tag.onload = () => { + clearTimeout(timeout_handle); + window.removeEventListener('error', error_handler); + console.debug("Script %o loaded", path); + setTimeout(resolve, 100); + }; + document.getElementById("scripts").appendChild(tag); + tag.src = path + (loader.allow_cached_files ? "" : "?_ts=" + Date.now()); + }); + } + }); + } + loader.load_script = load_script; + function load_scripts(paths) { + return __awaiter(this, void 0, void 0, function* () { + const promises = []; + const errors = []; + for (const script of paths) + promises.push(load_script(script).catch(error => { + errors.push({ + script: script, + error: error + }); + return Promise.resolve(); + })); + yield Promise.all([...promises]); + if (errors.length > 0) { + console.error("Failed to load the following scripts:"); + for (const script of errors) + console.log(" - %o: %o", script.script, script.error); + displayCriticalError("Failed to load script " + script_name(errors[0].script) + "
    " + "View the browser console for more information!"); + throw "failed to load script " + script_name(errors[0].script); + } + }); + } + loader.load_scripts = load_scripts; + function load_style(path) { + return __awaiter(this, void 0, void 0, function* () { + if (Array.isArray(path)) { //We have some fallback + return load_script(path[0]).catch(error => { + if (error instanceof SyntaxError) + return Promise.reject(error.source); + if (path.length > 1) + return load_script(path.slice(1)); + return Promise.reject(error); + }); + } + else { + return new Promise((resolve, reject) => { + const tag = document.createElement("link"); + let error = false; + const error_handler = (event) => { + console.log("msg: %o, url: %o, line: %o, col: %o, error: %o", event.message, event.filename, event.lineno, event.colno, event.error); + if (event.filename == tag.href) { //FIXME! + window.removeEventListener('error', error_handler); + reject(new SyntaxError(event.error)); + event.preventDefault(); + error = true; + } + }; + window.addEventListener('error', error_handler); + const timeout_handle = setTimeout(() => { + reject("timeout"); + }, 5000); + tag.type = "text/css"; + tag.rel = "stylesheet"; + tag.onerror = error => { + clearTimeout(timeout_handle); + window.removeEventListener('error', error_handler); + tag.remove(); + console.error("File load error for file %s: %o", path, error); + reject("failed to load file " + path); + }; + tag.onload = () => { + { + const css = tag.sheet; + const rules = css.cssRules; + const rules_remove = []; + const rules_add = []; + for (let index = 0; index < rules.length; index++) { + const rule = rules.item(index); + let rule_text = rule.cssText; + if (rule.cssText.indexOf("%%base_path%%") != -1) { + rules_remove.push(index); + rules_add.push(rule_text.replace("%%base_path%%", document.location.origin + document.location.pathname)); + } + } + for (const index of rules_remove.sort((a, b) => b > a ? 1 : 0)) { + if (css.removeRule) + css.removeRule(index); + else + css.deleteRule(index); + } + for (const rule of rules_add) + css.insertRule(rule, rules_remove[0]); + } + clearTimeout(timeout_handle); + window.removeEventListener('error', error_handler); + console.debug("Style sheet %o loaded", path); + setTimeout(resolve, 100); + }; + document.getElementById("style").appendChild(tag); + tag.href = path + (loader.allow_cached_files ? "" : "?_ts=" + Date.now()); + }); + } + }); + } + loader.load_style = load_style; + function load_styles(paths) { + return __awaiter(this, void 0, void 0, function* () { + const promises = []; + const errors = []; + for (const sheet of paths) + promises.push(load_style(sheet).catch(error => { + errors.push({ + sheet: sheet, + error: error + }); + return Promise.resolve(); + })); + yield Promise.all([...promises]); + if (errors.length > 0) { + console.error("Failed to load the following style sheet:"); + for (const sheet of errors) + console.log(" - %o: %o", sheet.sheet, sheet.error); + displayCriticalError("Failed to load style sheet " + script_name(errors[0].sheet) + "
    " + "View the browser console for more information!"); + throw "failed to load style sheet " + script_name(errors[0].sheet); + } + }); + } + loader.load_styles = load_styles; +})(loader || (loader = {})); +/* define that here */ +let _critical_triggered = false; +const display_critical_load = message => { + if (_critical_triggered) + return; /* only show the first error */ + _critical_triggered = true; + let tag = document.getElementById("critical-load"); + let detail = tag.getElementsByClassName("detail")[0]; + detail.innerHTML = message; + tag.style.display = "block"; + fadeoutLoader(); +}; +const loader_impl_display_critical_error = message => { + if (typeof (createErrorModal) !== 'undefined' && typeof (window.ModalFunctions) !== 'undefined') { + createErrorModal("A critical error occurred while loading the page!", message, { closeable: false }).open(); + } + else { + display_critical_load(message); + } + fadeoutLoader(); +}; +if (!window.impl_display_critical_error) { /* default impl */ + window.impl_display_critical_error = loader_impl_display_critical_error; +} +function displayCriticalError(message) { + if (window.impl_display_critical_error) + window.impl_display_critical_error(message); + else + loader_impl_display_critical_error(message); +} +/* all javascript loaders */ +const loader_javascript = { + detect_type: () => __awaiter(this, void 0, void 0, function* () { + /* test if js/proto.js is available. If so we're in debug mode */ + const request = new XMLHttpRequest(); + request.open('GET', 'js/proto.js', true); + yield new Promise((resolve, reject) => { + request.onreadystatechange = () => { + if (request.readyState === 4) { + if (request.status === 404) { + app.type = app.Type.WEB_RELEASE; + } + else { + app.type = app.Type.WEB_DEBUG; + } + resolve(); + } + }; + request.onerror = () => { + reject("Failed to detect app type"); + }; + request.send(); + }); + }), + load_scripts: () => __awaiter(this, void 0, void 0, function* () { + /* + if(window.require !== undefined) { + console.log("Loading node specific things"); + const remote = require('electron').remote; + module.paths.push(remote.app.getAppPath() + "/node_modules"); + module.paths.push(remote.app.getAppPath() + "/app"); + module.paths.push(remote.getGlobal("browser-root") + "js/"); + window.$ = require("assets/jquery.min.js"); + require("native/loader_adapter.js"); + } + */ + if (!window.require) { + yield loader.load_script(["vendor/jquery/jquery.min.js"]); + } + /* bootstrap material design and libs */ + yield loader.load_script(["vendor/popper/popper.js"]); + //depends on popper + yield loader.load_script(["vendor/bootstrap-material/bootstrap-material-design.js"]); + loader.register_task(loader.Stage.JAVASCRIPT_INITIALIZING, { + name: "materialize body", + priority: 10, + function: () => __awaiter(this, void 0, void 0, function* () { $(document).ready(function () { $('body').bootstrapMaterialDesign(); }); }) + }); + yield loader.load_script("vendor/jsrender/jsrender.min.js"); + yield loader.load_scripts([ + ["vendor/bbcode/xbbcode.js"], + ["vendor/moment/moment.js"], + ["https://webrtc.github.io/adapter/adapter-latest.js"] + ]); + if (app.type == app.Type.WEB_RELEASE || app.type == app.Type.CLIENT_RELEASE) { + loader.register_task(loader.Stage.JAVASCRIPT, { + name: "scripts release", + priority: 20, + function: loader_javascript.loadRelease + }); + } + else { + loader.register_task(loader.Stage.JAVASCRIPT, { + name: "scripts debug", + priority: 20, + function: loader_javascript.load_scripts_debug + }); + } + }), + load_scripts_debug: () => __awaiter(this, void 0, void 0, function* () { + /* test if we're loading as TeaClient or WebClient */ + if (!window.require) { + loader.register_task(loader.Stage.JAVASCRIPT, { + name: "javascript web", + priority: 10, + function: loader_javascript.load_scripts_debug_web + }); + } + /* load some extends classes */ + yield loader.load_scripts([ + ["js/connection/ConnectionBase.js"] + ]); + /* load the main app */ + yield loader.load_scripts([ + //Load general API's + "js/proto.js", + "js/i18n/localize.js", + "js/log.js", + "js/sound/Sounds.js", + "js/utils/modal.js", + "js/utils/tab.js", + "js/utils/helpers.js", + "js/crypto/sha.js", + "js/crypto/hex.js", + "js/crypto/asn1.js", + //load the profiles + "js/profiles/ConnectionProfile.js", + "js/profiles/Identity.js", + //Load UI + "js/ui/modal/ModalQuery.js", + "js/ui/modal/ModalQueryManage.js", + "js/ui/modal/ModalPlaylistList.js", + "js/ui/modal/ModalPlaylistEdit.js", + "js/ui/modal/ModalBookmarks.js", + "js/ui/modal/ModalConnect.js", + "js/ui/modal/ModalSettings.js", + "js/ui/modal/ModalCreateChannel.js", + "js/ui/modal/ModalServerEdit.js", + "js/ui/modal/ModalChangeVolume.js", + "js/ui/modal/ModalBanClient.js", + "js/ui/modal/ModalBanCreate.js", + "js/ui/modal/ModalBanList.js", + "js/ui/modal/ModalYesNo.js", + "js/ui/modal/ModalPoke.js", + "js/ui/modal/ModalPermissionEdit.js", + "js/ui/modal/ModalServerGroupDialog.js", + "js/ui/channel.js", + "js/ui/client.js", + "js/ui/server.js", + "js/ui/view.js", + "js/ui/client_move.js", + "js/ui/context_divider.js", + "js/ui/htmltags.js", + "js/ui/frames/SelectedItemInfo.js", + "js/ui/frames/ControlBar.js", + //Load permissions + "js/permission/PermissionManager.js", + "js/permission/GroupManager.js", + //Load audio + "js/voice/VoiceHandler.js", + "js/voice/VoiceRecorder.js", + "js/voice/AudioResampler.js", + "js/voice/AudioController.js", + //Load codec + "js/codec/Codec.js", + "js/codec/BasicCodec.js", + //Load general stuff + "js/settings.js", + "js/bookmarks.js", + "js/contextMenu.js", + "js/FileManager.js", + "js/client.js", + "js/chat.js", + //Connection + "js/connection/CommandHandler.js", + "js/connection/CommandHelper.js", + "js/connection/HandshakeHandler.js", + "js/connection/ServerConnection.js", + "js/stats.js", + "js/PPTListener.js", + "js/codec/CodecWrapperWorker.js", + "js/profiles/identities/NameIdentity.js", + "js/profiles/identities/TeaForumIdentity.js", + "js/profiles/identities/TeamSpeakIdentity.js", + ]); + yield loader.load_script("js/main.js"); + }), + load_scripts_debug_web: () => __awaiter(this, void 0, void 0, function* () { + yield loader.load_scripts([ + ["js/audio/AudioPlayer.js"], + ["js/audio/WebCodec.js"], + ["js/WebPPTListener.js"] + ]); + }), + loadRelease: () => __awaiter(this, void 0, void 0, function* () { + console.log("Load for release!"); + yield loader.load_scripts([ + //Load general API's + ["js/client.min.js", "js/client.js"] + ]); + }) +}; +const loader_webassembly = { + test_webassembly: () => __awaiter(this, void 0, void 0, function* () { + /* 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: () => __awaiter(this, void 0, void 0, function* () { + yield loader.load_styles([ + "vendor/bbcode/xbbcode.css" + ]); + if (app.type == app.Type.WEB_DEBUG || app.type == app.Type.CLIENT_DEBUG) { + yield loader_style.load_style_debug(); + } + else { + yield loader_style.load_style_release(); + } + /* the material design */ + yield loader.load_style("css/theme/bootstrap-material-design.css"); + }), + load_style_debug: () => __awaiter(this, void 0, void 0, function* () { + yield loader.load_styles([ + "css/static/main.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/general.css", + "css/static/modals.css", + "css/static/modal-bookmarks.css", + "css/static/modal-connect.css", + "css/static/modal-channel.css", + "css/static/modal-query.css", + "css/static/modal-playlist.css", + "css/static/modal-banlist.css", + "css/static/modal-bancreate.css", + "css/static/modal-settings.css", + "css/static/modal-poke.css", + "css/static/modal-server.css", + "css/static/modal-permissions.css", + "css/static/music/info_plate.css", + "css/static/frame/SelectInfo.css", + "css/static/control_bar.css", + "css/static/context_menu.css", + "css/static/htmltags.css" + ]); + }), + load_style_release: () => __awaiter(this, void 0, void 0, function* () { + yield loader.load_styles([ + "css/static/base.css", + "css/static/main.css", + ]); + }) +}; +function load_templates() { + return __awaiter(this, void 0, void 0, function* () { + try { + const response = yield $.ajax("templates.html" + (loader.allow_cached_files ? "" : "?_ts" + Date.now())); + let node = document.createElement("html"); + node.innerHTML = response; + let tags; + if (node.getElementsByTagName("body").length > 0) + tags = node.getElementsByTagName("body")[0].children; + else + tags = node.children; + let root = document.getElementById("templates"); + if (!root) { + displayCriticalError("Failed to find template tag!"); + return; + } + while (tags.length > 0) { + let tag = tags.item(0); + root.appendChild(tag); + } + } + catch (error) { + displayCriticalError("Failed to find template tag!"); + throw "template error"; + } + }); +} +/* test if all files shall be load from cache or fetch again */ +function check_updates() { + return __awaiter(this, void 0, void 0, function* () { + const app_version = (() => { + 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; + if (version == "unknown" || version.replace(/0+/, "").length == 0) + return undefined; + return version; + })(); + console.log("Found current app version: %o", app_version); + if (!app_version) { + /* TODO add warning */ + loader.allow_cached_files = false; + return; + } + const cached_version = localStorage.getItem("cached_version"); + if (!cached_version || cached_version != app_version) { + loader.allow_cached_files = false; + loader.register_task(loader.Stage.LOADED, { + priority: 0, + name: "cached version updater", + function: () => __awaiter(this, void 0, void 0, function* () { + localStorage.setItem("cached_version", app_version); + }) + }); + /* loading screen */ + return; + } + loader.allow_cached_files = true; + }); +} +//FUN: loader_ignore_age=0&loader_default_duration=1500&loader_default_age=5000 +let _fadeout_warned = false; +function fadeoutLoader(duration = undefined, minAge = undefined, ignoreAge = undefined) { + if (typeof ($) === "undefined") { + if (!_fadeout_warned) + console.warn("Could not fadeout loader screen. Missing jquery functions."); + _fadeout_warned = true; + return; + } + let settingsDefined = typeof (StaticSettings) !== "undefined"; + if (!duration) { + if (settingsDefined) + duration = StaticSettings.instance.static("loader_default_duration", 750); + else + duration = 750; + } + if (!minAge) { + if (settingsDefined) + minAge = StaticSettings.instance.static("loader_default_age", 1750); + else + minAge = 750; + } + if (!ignoreAge) { + if (settingsDefined) + ignoreAge = StaticSettings.instance.static("loader_ignore_age", false); + else + ignoreAge = false; + } + /* + let age = Date.now() - app.appLoaded; + if(age < minAge && !ignoreAge) { + setTimeout(() => fadeoutLoader(duration, 0, true), minAge - age); + return; + } + */ + $(".loader .bookshelf_wrapper").animate({ top: 0, opacity: 0 }, duration); + $(".loader .half").animate({ width: 0 }, duration, () => { + $(".loader").detach(); + }); +} +window["Module"] = window["Module"] || {}; +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(navigator.browserSpecs); //Object { name: "Firefox", version: "42" } +/* register tasks */ +loader.register_task(loader.Stage.INITIALIZING, { + name: "safari fix", + function: () => __awaiter(this, void 0, void 0, function* () { + /* 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 +}); +/* TeaClient */ +if (window.require) { + const path = require("path"); + const remote = require('electron').remote; + module.paths.push(path.join(remote.app.getAppPath(), "/modules")); + module.paths.push(path.join(path.dirname(remote.getGlobal("browser-root")), "js")); + const connector = require("renderer"); + console.log(connector); + loader.register_task(loader.Stage.INITIALIZING, { + name: "teaclient initialize", + function: connector.initialize, + priority: 40 + }); +} +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.INITIALIZING, { + name: "update tester", + priority: 60, + function: check_updates +}); +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: load_templates, + priority: 10 +}); +loader.register_task(loader.Stage.LOADED, { + name: "loaded handler", + function: () => __awaiter(this, void 0, void 0, function* () { + fadeoutLoader(); + }), + priority: 10 +}); +loader.register_task(loader.Stage.LOADED, { + name: "error task", + function: () => __awaiter(this, void 0, void 0, function* () { + if (Settings.instance.static("dummy_load_error", false)) { + displayCriticalError("The tea is cold!"); + throw "The tea is cold!"; + } + }), + priority: 20 +}); +loader.execute().then(() => { + console.log("app successfully loaded!"); +}).catch(error => { + displayCriticalError("failed to load app!
    Please lookup the browser console for more details"); + console.error("Failed to load app!\nError: %o", error); +}); +//# sourceMappingURL=load.js.map \ No newline at end of file diff --git a/test/js/workers/WorkerCodec.js b/test/js/workers/WorkerCodec.js new file mode 100644 index 00000000..b14612ca --- /dev/null +++ b/test/js/workers/WorkerCodec.js @@ -0,0 +1,234 @@ +const prefix = "[CodecWorker] "; +const workerCallbackToken = "callback_token"; +let codecInstance; +onmessage = function (e) { + let data = e.data; + let res = {}; + res.token = data.token; + res.success = false; + //console.log(prefix + " Got from main: %o", data); + switch (data.command) { + case "initialise": + let error; + console.log(prefix + "Got initialize for type " + CodecType[data.type]); + switch (data.type) { + case CodecType.OPUS_MUSIC: + codecInstance = new OpusWorker(2, OpusType.AUDIO); + break; + case CodecType.OPUS_VOICE: + codecInstance = new OpusWorker(1, OpusType.VOIP); + break; + default: + error = "Could not find worker type!"; + console.error("Could not resolve opus type!"); + break; + } + error = error || codecInstance.initialise(); + if (error) + res["message"] = error; + else + res["success"] = true; + break; + case "encodeSamples": + let encodeArray = new Float32Array(data.dataLength); + for (let index = 0; index < encodeArray.length; index++) + encodeArray[index] = data.data[index]; + let encodeResult = codecInstance.encode(encodeArray); + if (typeof encodeResult === "string") { + res.message = encodeResult; + } + else { + res.success = true; + res.data = encodeResult; + res.dataLength = encodeResult.length; + } + break; + case "decodeSamples": + let decodeArray = new Uint8Array(data.dataLength); + for (let index = 0; index < decodeArray.length; index++) + decodeArray[index] = data.data[index]; + let decodeResult = codecInstance.decode(decodeArray); + if (typeof decodeResult === "string") { + res.message = decodeResult; + } + else { + res.success = true; + res.data = decodeResult; + res.dataLength = decodeResult.length; + } + break; + case "reset": + codecInstance.reset(); + break; + default: + console.error(prefix + "Unknown type " + data.command); + } + if (res.token && res.token.length > 0) + sendMessage(res, e.origin); +}; +function printMessageToServerTab(message) { + /* + sendMessage({ + token: workerCallbackToken, + type: "chatmessage_server", + message: message + }); + */ +} +function sendMessage(message, origin) { + message["timestamp"] = Date.now(); + postMessage(message); +} +/// +const WASM_ERROR_MESSAGES = [ + 'no native wasm support detected' +]; +this["Module"] = this["Module"] || {}; +let initialized = false; +Module['onRuntimeInitialized'] = function () { + initialized = true; + console.log(prefix + "Initialized!"); + sendMessage({ + token: workerCallbackToken, + type: "loaded", + success: true + }); +}; +let abort_message = undefined; +let last_error_message; +Module['print'] = function () { + if (arguments.length == 1 && arguments[0] == abort_message) + return; /* we don't need to reprint the abort message! */ + console.log(...arguments); +}; +Module['printErr'] = function () { + if (arguments.length == 1 && arguments[0] == abort_message) + return; /* we don't need to reprint the abort message! */ + last_error_message = arguments[0]; + for (const suppress of WASM_ERROR_MESSAGES) + if (arguments[0].indexOf(suppress) != -1) + return; + console.error(...arguments); +}; +Module['onAbort'] = (message) => { + /* no native wasm support detected */ + Module['onAbort'] = undefined; + if (message instanceof DOMException) + message = "DOMException (" + message.name + "): " + message.code + " => " + message.message; + else { + abort_message = message; + if (message.indexOf("no binaryen method succeeded") != -1) + for (const error of WASM_ERROR_MESSAGES) + if (last_error_message.indexOf(error) != -1) { + message = "no native wasm support detected, but its required"; + break; + } + } + sendMessage({ + token: workerCallbackToken, + type: "loaded", + success: false, + message: message + }); +}; +try { + console.log("Node init!"); + Module['locateFile'] = file => "../../wasm/" + file; + importScripts("../../wasm/TeaWeb-Worker-Codec-Opus.js"); +} +catch (e) { + if (typeof (Module['onAbort']) === "function") { + console.log(e); + Module['onAbort']("Failed to load native scripts"); + } /* else the error had been already handled because its a WASM error */ +} +var OpusType; +(function (OpusType) { + OpusType[OpusType["VOIP"] = 2048] = "VOIP"; + OpusType[OpusType["AUDIO"] = 2049] = "AUDIO"; + OpusType[OpusType["RESTRICTED_LOWDELAY"] = 2051] = "RESTRICTED_LOWDELAY"; +})(OpusType || (OpusType = {})); +class OpusWorker { + constructor(channelCount, type) { + this.bufferSize = 4096 * 2; + this.channelCount = channelCount; + this.type = type; + } + name() { + return "Opus (Type: " + OpusWorker[this.type] + " Channels: " + this.channelCount + ")"; + } + initialise() { + this.fn_newHandle = Module.cwrap("codec_opus_createNativeHandle", "pointer", ["number", "number"]); + this.fn_decode = Module.cwrap("codec_opus_decode", "number", ["pointer", "pointer", "number", "number"]); + /* codec_opus_decode(handle, buffer, length, maxlength) */ + this.fn_encode = Module.cwrap("codec_opus_encode", "number", ["pointer", "pointer", "number", "number"]); + this.fn_reset = Module.cwrap("codec_opus_reset", "number", ["pointer"]); + this.nativeHandle = this.fn_newHandle(this.channelCount, this.type); + this.encodeBufferRaw = Module._malloc(this.bufferSize); + this.encodeBuffer = new Float32Array(Module.HEAPF32.buffer, this.encodeBufferRaw, this.bufferSize / 4); + this.decodeBufferRaw = Module._malloc(this.bufferSize); + this.decodeBuffer = new Uint8Array(Module.HEAPU8.buffer, this.decodeBufferRaw, this.bufferSize); + return undefined; + } + deinitialise() { } //TODO + decode(data) { + if (data.byteLength > this.decodeBuffer.byteLength) + return "Data to long!"; + this.decodeBuffer.set(data); + //console.log("decode(" + data.length + ")"); + //console.log(data); + let result = this.fn_decode(this.nativeHandle, this.decodeBuffer.byteOffset, data.byteLength, this.decodeBuffer.byteLength); + if (result < 0) { + return "invalid result on decode (" + result + ")"; + } + return Module.HEAPF32.slice(this.decodeBuffer.byteOffset / 4, (this.decodeBuffer.byteOffset / 4) + (result * this.channelCount)); + } + encode(data) { + this.encodeBuffer.set(data); + let result = this.fn_encode(this.nativeHandle, this.encodeBuffer.byteOffset, data.length, this.encodeBuffer.byteLength); + if (result < 0) { + return "invalid result on encode (" + result + ")"; + } + let buf = Module.HEAP8.slice(this.encodeBuffer.byteOffset, this.encodeBuffer.byteOffset + result); + return Uint8Array.from(buf); + } + reset() { + console.log(prefix + " Reseting opus codec!"); + this.fn_reset(this.nativeHandle); + } +} +var CodecType; +(function (CodecType) { + CodecType[CodecType["OPUS_VOICE"] = 0] = "OPUS_VOICE"; + CodecType[CodecType["OPUS_MUSIC"] = 1] = "OPUS_MUSIC"; + CodecType[CodecType["SPEEX_NARROWBAND"] = 2] = "SPEEX_NARROWBAND"; + CodecType[CodecType["SPEEX_WIDEBAND"] = 3] = "SPEEX_WIDEBAND"; + CodecType[CodecType["SPEEX_ULTRA_WIDEBAND"] = 4] = "SPEEX_ULTRA_WIDEBAND"; + CodecType[CodecType["CELT_MONO"] = 5] = "CELT_MONO"; +})(CodecType || (CodecType = {})); +class BufferChunk { + constructor(buffer) { + this.buffer = buffer; + this.index = 0; + } + copyRangeTo(target, maxLength, offset) { + let copy = Math.min(this.buffer.length - this.index, maxLength); + //TODO may warning if channel counts are not queal? + for (let channel = 0; channel < Math.min(target.numberOfChannels, this.buffer.numberOfChannels); channel++) { + target.getChannelData(channel).set(this.buffer.getChannelData(channel).subarray(this.index, this.index + copy), offset); + } + return copy; + } +} +class CodecClientCache { + constructor() { + this._chunks = []; + } + bufferedSamples(max = 0) { + let value = 0; + for (let i = 0; i < this._chunks.length && value < max; i++) + value += this._chunks[i].buffer.length - this._chunks[i].index; + return value; + } +} +//# sourceMappingURL=WorkerCodec.js.map \ No newline at end of file diff --git a/test/js/workers/WorkerPOW.js b/test/js/workers/WorkerPOW.js new file mode 100644 index 00000000..753cf059 --- /dev/null +++ b/test/js/workers/WorkerPOW.js @@ -0,0 +1,90 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +const prefix = "[POWWorker] "; +let initialized = false; +let memory; +let memory_u8; +let wasm_object; +function post_status(code, result) { + let data = {}; + data.code = code; + if (typeof (result) === "string") { + data.success = false; + data.message = result; + } + else if (typeof (result) === "boolean") { + data.success = result; + } + else { + data.success = true; + Object.assign(data, result); + } + postMessage(data); +} +{ + memory = new WebAssembly.Memory({ initial: 1 }); + memory_u8 = new Uint8Array(memory.buffer); + if (typeof (WebAssembly.instantiateStreaming) === "undefined") { + WebAssembly.instantiateStreaming = (stream, imports) => __awaiter(this, void 0, void 0, function* () { + const response = yield stream; + const buffer = yield response.arrayBuffer(); + return WebAssembly.instantiate(buffer, imports); + }); + } + WebAssembly.instantiateStreaming(fetch('../../wat/pow/sha1.wasm'), { + env: { + memory: memory + } + }).then(object => { + wasm_object = object; + post_status("initialize", true); + }).catch(error => { + post_status("initialize", "failed to initialize WASM handle (" + error + ")"); + }); +} +let key_offset = 0; +let hash_offset = 0; +onmessage = function (e) { + let data = e.data; + //console.log(prefix + "Got data: %o", data); + if (data.type == "set_data") { + const key = data.private_key; + key_offset = 0; + for (const char of key) + memory_u8[0x0A0 + key_offset++] = char.charCodeAt(0); + post_status(data.code, true); + } + else if (data.type == "mine") { + let hash = data.hash; + const iterations = data.iterations; + const target = data.target; + hash_offset = 0; + for (const char of hash) { + memory_u8[0x0A0 + key_offset + hash_offset++] = char.charCodeAt(0); + } + let level = wasm_object.instance.exports.mine(key_offset, hash_offset, iterations, target > 1 ? target - 1 : target); + hash = ""; + hash_offset = 0; + while (memory_u8[0x0A0 + key_offset + hash_offset] != 0) + hash = hash + String.fromCharCode(memory_u8[0x0A0 + key_offset + hash_offset++]); + console.log(prefix + "New hash: %s, level %o", hash, level); + post_status(data.code, { + result: level >= target, + hash: hash, + level: level + }); + } + else if (data.type == "finalize") { + wasm_object = undefined; + memory = undefined; + memory_u8 = undefined; + post_status(data.code, true); + } +}; +//# sourceMappingURL=WorkerPOW.js.map \ No newline at end of file diff --git a/test/templates.html b/test/templates.html new file mode 100644 index 00000000..76903b09 --- /dev/null +++ b/test/templates.html @@ -0,0 +1,2893 @@ + + + + + + TeaSpeak-Web client templates + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/vendor/bbcode/examples/example.js b/test/vendor/bbcode/examples/example.js new file mode 100644 index 00000000..d009b535 --- /dev/null +++ b/test/vendor/bbcode/examples/example.js @@ -0,0 +1,8 @@ +var result = XBBCODE.process({ + text: "[b]bolded text[/b]", + removeMisalignedTags: false, + addInLineBreaks: false +}); +console.log("Errors: " + result.error); +console.dir(result.errorQueue); +console.log(result.html);// the HTML form of your BBCode \ No newline at end of file diff --git a/test/vendor/bbcode/examples/layout.css b/test/vendor/bbcode/examples/layout.css new file mode 100644 index 00000000..57a4fdf9 --- /dev/null +++ b/test/vendor/bbcode/examples/layout.css @@ -0,0 +1,101 @@ +body { + font-size:14px; + font-family:Verdana, Arial, Helvetica, sans-serif; + margin:0px; + padding:0px; + background-color:#eeeeee; +} + +#container { + position:relative; + margin: 20px auto; + padding: 20px; + border-width: 4px; + border-style:solid; + border-color:#cccccc; + width:1024px; + background-color:#ffffff; + -moz-border-radius: 25px; + -webkit-border-radius: 25px; + border-radius: 25px; +} + +#heading { + font-size:25px; + text-align:center; +} + +#controlsContainer { + position:relative; +} + +#col1 { + float:left; + width:650px; + border-width:0px; + padding:0px; +} + +#inputCode { + width:95%; + height:250px; +} + +.errMsg-fine { + margin-left: 20px; + padding:4px; + background-color:#FFFFc0; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + border-radius: 5px; +} + +.errMsg-error { + margin-left: 20px; + padding:4px; + background-color:#FF8080; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + border-radius: 5px; +} + +#errMsgs { + width:95%; + display:none; + padding:4px; + background-color:#FF8080; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + border-radius: 5px; +} + +#outputContainer { + border-width:1px; + border-style:solid; + border-color:black; + width:100%; + height:500px; + overflow:auto; +} + +#col2 { + float:right; + width:350px; + border-width:0px; + padding:0px; + /*background-color:#cccccc;*/ +} + +#formatDisplay { + padding-top:10px; + padding-bottom:10px; + background-color:#cccccc; + font-family:monospace; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} + +.clearFloats { + clear:both; +} \ No newline at end of file diff --git a/test/vendor/bbcode/examples/page-setup.js b/test/vendor/bbcode/examples/page-setup.js new file mode 100644 index 00000000..d3ec4f9d --- /dev/null +++ b/test/vendor/bbcode/examples/page-setup.js @@ -0,0 +1,198 @@ +(function() { + + var btn = document.getElementById("btnTest"), + tcList = document.getElementById("testCaseList"), + inputTextArea = document.getElementById("inputCode"), + errMsgs = document.getElementById("errMsgs"), + cbRmMisTags = document.getElementById("cbRmMisTags"), + cbAddLb = document.getElementById("cbAddLb"); + + // For IE + if (!btn.addEventListener) { + btn.addEventListener = function(method, funct, evtCap) { + btn.attachEvent("on" + method, funct); + }; + tcList.addEventListener = function(method, funct, evtCap) { + tcList.attachEvent("on" + method, funct); + }; + cbRmMisTags.addEventListener = function(method, funct, evtCap) { + cbRmMisTags.attachEvent("on" + method, funct); + }; + cbAddLb.addEventListener = function(method, funct, evtCap) { + cbAddLb.attachEvent("on" + method, funct); + }; + } + + + /* + What happens when a user selects a new element in the Test Case list + */ + var testCaseCode = []; + testCaseCode[""] = ""; + testCaseCode["Nested Color Tags"] = +"[color=red]This text is red\n\ +[color=blue]This text is blue[/color]\n\ +[color=#00ff00][b]This text is green and [i]bold[/i].[/b] [color=00ffff]Another color change...[/color] green again.[/color]\n\ +This text is red[/color]\n\ +[b][color=yellow]This text is yellow.[/color][/b]\n\ +[color=gray]This text is gray.[/color]\n\ +"; + testCaseCode["Color Faded Text"] = "[color=#FF0000]T[/color][color=#F3000C]h[/color][color=#E80017]i[/color][color=#DC0023]s[/color][color=#D1002E] [/color] [color=#C5003A]t[/color][color=#B90046]e[/color][color=#AE0051]x[/color][color=#A2005D]t[/color][color=#970068] [/color] [color=#8B0074]c[/color][color=#7F0080]h[/color][color=#74008B]a[/color][color=#680097]n[/color][color=#5D00A2]g[/color][color=#5100AE]e[/color][color=#4600B9]s[/color][color=#3A00C5] [/color] [color=#2E00D1]i[/color][color=#2300DC]n[/color][color=#1700E8] [/color] [color=#0C00F3]c[/color][color=#0000FF]o[/color][color=#000CF3]l[/color][color=#0017E8]o[/color][color=#0023DC]r[/color][color=#002ED1] [/color] [color=#003AC5]a[/color][color=#0046B9]s[/color][color=#0051AE] [/color] [color=#005DA2]i[/color][color=#006897]t[/color][color=#00748B] [/color] [color=#00807F]g[/color][color=#008B74]o[/color][color=#009768]e[/color][color=#00A25D]s[/color][color=#00AE51] [/color] [color=#00B946]a[/color][color=#00C53A]l[/color][color=#00D12E]o[/color][color=#00DC23]n[/color][color=#00E817]g[/color][color=#00F30C].[/color][color=#00FF00].[/color]"; + testCaseCode["Nested List Tags"] = +"[list]\n\ +[*] Item 1\n\ +[*] Item 2\n\ +[*] Lets display a sub-list:\n\ + [list]\n\ + [*] Another Sub List:\n\ + [list]\n\ + [*] [color=red]This text is red.[/color]\n\ + [*] [color=blue]This sub-list is blue\n\ + [list]\n\ + [*] Blue list item.\n\ + [*] [color=green]Except this item, it's green![/color]\n\ + [/list]\n\ + [/color]\n\ + [/list]\n\ + [*] List item\n\ + [*] Sub-list:\n\ + [list]\n\ + [*] Only one item in this list...\n\ + [/list]\n\ + [/list]\n\ +[*] Last item in list\n\ +[/list]\n\ +[b]And now onto another list[/b]\n\ +[list]\n\ +[*] Another list here.\n\ +[*] This is just a simple list.\n\ +[*] It has three items.\n\ +[/list]\n\ +One last list to try things out on\n\ +[list]\n\ +[*] 1\n\ + [list]\n\ + [*] 1.1\n\ + [list]\n\ + [*] 1.1.1\n\ + [*] 1.1.2\n\ + [*] 1.1.3\n\ + [/list]\n\ + [*] 1.2\n\ + [/list]\n\ +[*] 2\n\ + [list]\n\ + [*] 2.1\n\ + [*] 2.2\n\ + [/list]\n\ +[*] 3\n\ + [list]\n\ + [*] 3.1\n\ + [*] 3.2\n\ + [/list]\n\ +[/list]"; + testCaseCode["Nested Table Tags"] = +"[table]\n\ +[tr]\n\ +[td]cell 1,1[/td]\n\ +[td]cell 1,2[/td]\n\ +[td]cell 1,3 - here's a sub-table\n\ + [table]\n\ + [tr]\n\ + [td]cell 1,1[/td]\n\ + [td]cell 1,2[/td]\n\ + [td]cell 1,3[/td]\n\ + [/tr]\n\ + [tr]\n\ + [td]cell 2,1[/td]\n\ + [td]cell 2,2[/td]\n\ + [td]cell 2,3[/td]\n\ + [/tr]\n\ + [/table]\n\ +[/td]\n\ +[/tr]\n\ +[tr]\n\ +[td]cell 2,1[/td]\n\ +[td]cell 2,2[/td]\n\ +[td]cell 2,3[/td]\n\ +[/tr]\n\ +[/table]"; + testCaseCode["Misaligned Tags 1"] = "[b][u]Text with misaligned tags[/b][/u]"; + testCaseCode["Misaligned Tags 2"] = "[color=red]Text with misaligned tags[/color][/color]"; + testCaseCode["Mismatched Parent-Child Tags"] = +"[list]\n\ +[b]Not a list item[/b]\n\ +[*]A list item\n\ +[/list]\n\ +\n\ +[*]What's this?\n\ +[td]What's this?[/td]\n\ +\n\ +[table]\n\ +[color=blue]This should be in a cell[/color]\n\ +[tr]\n\ +[s]test![/s]\n\ +[td]cell\n\ +[tr]\n\ +What's this?\n\ +[/tr]\n\ +[/td]\n\ +[/tr]\n\ +[/table]"; + testCaseCode["No Parse Tag"] = +"[noparse]\n\ +[list]\n\ +[*] List item!\n\ +[/list]\n\ +[b]BBCode![/b]\n\ +[/noparse]"; + + var testBbcode = function() { + + var myText = document.getElementById("inputCode").value, + errMsgElm, + removeExcessTags = document.getElementById("cbRmMisTags").checked, + addInLineBreaks = document.getElementById("cbAddLb").checked; + + var result = XBBCODE.process({ + text: myText, + removeMisalignedTags: removeExcessTags, + addInLineBreaks: addInLineBreaks + }); + + errMsgElm = document.getElementById("errMsg"); + if ( result.error ) { + errMsgElm.className = "errMsg-error"; + errMsgElm.innerHTML = "Errors: True"; + errMsgs.innerHTML = result.errorQueue.join("
    "); + errMsgs.style.display = "block"; + } else { + errMsgElm.className = "errMsg-fine"; + errMsgElm.innerHTML = "Errors: False"; + errMsgs.style.display = "none"; + } + + document.getElementById("output").innerHTML = result.html; + }; + + var tcListChange = function() { + if (tcList.selectedIndex === -1) {return;} + + var index = tcList.selectedIndex, + optionValue = tcList.options[index].value; + + inputTextArea.value = testCaseCode[ optionValue ]; + testBbcode(); + }; + tcList.addEventListener("change", tcListChange, false); + tcList.addEventListener("keyup", tcListChange, false); + + cbRmMisTags.addEventListener("click", testBbcode, false); + cbAddLb.addEventListener("click", testBbcode, false); + + /* + What happens when the "Test" button gets pressed + */ + btn.addEventListener("click", testBbcode, false); + +})(); \ No newline at end of file diff --git a/test/vendor/bbcode/xbbcode.css b/test/vendor/bbcode/xbbcode.css new file mode 100644 index 00000000..553bdcb2 --- /dev/null +++ b/test/vendor/bbcode/xbbcode.css @@ -0,0 +1,100 @@ +.xbbcode-b { + font-weight:bold; +} + +.xbbcode-blockquote { + +} + +.xbbcode-center { + margin-left:auto; + margin-right:auto; + display: block; + text-align: center; +} + +.xbbcode-code { + white-space: pre-wrap; + font-family: monospace; +} + +.xbbcode-i { + font-style: italic; +} + +.xbbcode-justify { + display: block; + text-align: justify; +} + +.xbbcode-left { + display: block; + text-align: left; +} + +.xbbcode-right { + display: block; + text-align: right; +} + +.xbbcode-s { + text-decoration: line-through; +} + +.xbbcode-size-4 {font-size:4px;} +.xbbcode-size-5 {font-size:5px;} +.xbbcode-size-6 {font-size:6px;} +.xbbcode-size-7 {font-size:7px;} +.xbbcode-size-8 {font-size:8px;} +.xbbcode-size-9 {font-size:9px;} +.xbbcode-size-10 {font-size:10px;} +.xbbcode-size-11 {font-size:11px;} +.xbbcode-size-12 {font-size:12px;} +.xbbcode-size-13 {font-size:13px;} +.xbbcode-size-14 {font-size:14px;} +.xbbcode-size-15 {font-size:15px;} +.xbbcode-size-16 {font-size:16px;} +.xbbcode-size-17 {font-size:17px;} +.xbbcode-size-18 {font-size:18px;} +.xbbcode-size-19 {font-size:19px;} +.xbbcode-size-20 {font-size:20px;} +.xbbcode-size-21 {font-size:21px;} +.xbbcode-size-22 {font-size:22px;} +.xbbcode-size-23 {font-size:23px;} +.xbbcode-size-24 {font-size:24px;} +.xbbcode-size-25 {font-size:25px;} +.xbbcode-size-26 {font-size:26px;} +.xbbcode-size-27 {font-size:27px;} +.xbbcode-size-28 {font-size:28px;} +.xbbcode-size-29 {font-size:29px;} +.xbbcode-size-30 {font-size:30px;} +.xbbcode-size-31 {font-size:31px;} +.xbbcode-size-32 {font-size:32px;} +.xbbcode-size-33 {font-size:33px;} +.xbbcode-size-34 {font-size:34px;} +.xbbcode-size-35 {font-size:35px;} +.xbbcode-size-36 {font-size:36px;} +.xbbcode-size-37 {font-size:37px;} +.xbbcode-size-38 {font-size:38px;} +.xbbcode-size-39 {font-size:39px;} +.xbbcode-size-40 {font-size:40px;} + +.xbbcode-u { + text-decoration: underline; +} + +.xbbcode-table { + border-collapse:collapse; +} + +.xbbcode-tr { + +} + +.xbbcode-table , .xbbcode-th, .xbbcode-td { + border: 1px solid #666; +} + +.xbbcode img { + max-width: 100%; +} \ No newline at end of file diff --git a/test/vendor/bbcode/xbbcode.js b/test/vendor/bbcode/xbbcode.js new file mode 100644 index 00000000..438863fe --- /dev/null +++ b/test/vendor/bbcode/xbbcode.js @@ -0,0 +1,742 @@ +typeof _translations !== "undefined" || (_translations = {}) +_translations["declared"] = _translations["declared"] || (_translations["declared"] = {}) +_translations["declared_files"] = _translations["declared_files"] || (_translations["declared_files"] = {}) +unique_translation_check: { + if (_translations["declared_files"]["f7ffefe1f23e9f41f63ecb2759b0052d274d4984d577731464ae6be88cf1b89f"] !== undefined) { + console.warn("This file has already been loaded!\nAre you executing scripts twice?") + break unique_translation_check; + } + else + _translations["declared_files"]["f7ffefe1f23e9f41f63ecb2759b0052d274d4984d577731464ae6be88cf1b89f"] = "f7ffefe1f23e9f41f63ecb2759b0052d274d4984d577731464ae6be88cf1b89f" + /*Auto generated helper for testing if the translation keys are unique*/ + for (var { name: _i, path: _a } of []) { + if (_translations["declared"][_i] !== undefined) + throw "Translation with generated name \"" + _i + "\" already exists!\nIt has been already defined here: " + _translations["declared"][_i] + "\nAttempted to redefine here: " + _a + "\nRegenerate and/or fix your program!"; + else + _translations["declared"][_i] = _a + } +} +/* +Copyright (C) 2011 Patrick Gillespie, http://patorjk.com/ + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +/* + Extendible BBCode Parser v1.0.0 + By Patrick Gillespie (patorjk@gmail.com) + Website: http://patorjk.com/ + + This module allows you to parse BBCode and to extend to the mark-up language + to add in your own tags. +*/ +var XBBCODE; +(function (XBBCODE) { + // ----------------------------------------------------------------------------- + // Set up private variables + // ----------------------------------------------------------------------------- + const urlPattern = /^(?:https?|file|c):(?:\/{1,3}|\\{1})[-a-zA-Z0-9:;,@#%&()~_?\+=\/\\\.]*$/, colorNamePattern = /^(?:aliceblue|antiquewhite|aqua|aquamarine|azure|beige|bisque|black|blanchedalmond|blue|blueviolet|brown|burlywood|cadetblue|chartreuse|chocolate|coral|cornflowerblue|cornsilk|crimson|cyan|darkblue|darkcyan|darkgoldenrod|darkgray|darkgreen|darkkhaki|darkmagenta|darkolivegreen|darkorange|darkorchid|darkred|darksalmon|darkseagreen|darkslateblue|darkslategray|darkturquoise|darkviolet|deeppink|deepskyblue|dimgray|dodgerblue|firebrick|floralwhite|forestgreen|fuchsia|gainsboro|ghostwhite|gold|goldenrod|gray|green|greenyellow|honeydew|hotpink|indianred|indigo|ivory|khaki|lavender|lavenderblush|lawngreen|lemonchiffon|lightblue|lightcoral|lightcyan|lightgoldenrodyellow|lightgray|lightgreen|lightpink|lightsalmon|lightseagreen|lightskyblue|lightslategray|lightsteelblue|lightyellow|lime|limegreen|linen|magenta|maroon|mediumaquamarine|mediumblue|mediumorchid|mediumpurple|mediumseagreen|mediumslateblue|mediumspringgreen|mediumturquoise|mediumvioletred|midnightblue|mintcream|mistyrose|moccasin|navajowhite|navy|oldlace|olive|olivedrab|orange|orangered|orchid|palegoldenrod|palegreen|paleturquoise|palevioletred|papayawhip|peachpuff|peru|pink|plum|powderblue|purple|red|rosybrown|royalblue|saddlebrown|salmon|sandybrown|seagreen|seashell|sienna|silver|skyblue|slateblue|slategray|snow|springgreen|steelblue|tan|teal|thistle|tomato|turquoise|violet|wheat|white|whitesmoke|yellow|yellowgreen)$/, colorCodePattern = /^#?[a-fA-F0-9]{6}$/, emailPattern = /[^\s@]+@[^\s@]+\.[^\s@]+/, fontFacePattern = /^([a-z][a-z0-9_]+|"[a-z][a-z0-9_\s]+")$/i; + let tagList, tagsNoParseList = [], bbRegExp, pbbRegExp, pbbRegExp2, openTags, closeTags; + /* ----------------------------------------------------------------------------- + * _tags + * This object contains a list of _tags that your code will be able to understand. + * Each tag object has the following properties: + * + * openTag - A function that takes in the tag's parameters (if any) and its + * contents, and returns what its HTML open tag should be. + * Example: [color=red]test[/color] would take in "=red" as a + * parameter input, and "test" as a content input. + * It should be noted that any BBCode inside of "content" will have + * been processed by the time it enter the openTag function. + * + * closeTag - A function that takes in the tag's parameters (if any) and its + * contents, and returns what its HTML close tag should be. + * + * displayContent - Defaults to true. If false, the content for the tag will + * not be displayed. This is useful for _tags like IMG where + * its contents are actually a parameter input. + * + * restrictChildrenTo - A list of BBCode _tags which are allowed to be nested + * within this BBCode tag. If this property is omitted, + * any BBCode tag may be nested within the tag. + * + * restrictParentsTo - A list of BBCode _tags which are allowed to be parents of + * this BBCode tag. If this property is omitted, any BBCode + * tag may be a parent of the tag. + * + * noParse - true or false. If true, none of the content WITHIN this tag will be + * parsed by the XBBCode parser. + * + * + * + * LIMITIONS on adding NEW TAGS: + * - Tag names should be alphanumeric (including underscores) and all _tags should have an opening tag + * and a closing tag. + * The [*] tag is an exception because it was already a standard + * bbcode tag. Technecially _tags don't *have* to be alphanumeric, but since + * regular expressions are used to parse the text, if you use a non-alphanumeric + * tag names, just make sure the tag name gets escaped properly (if needed). + * --------------------------------------------------------------------------- */ + let _tags = { + "b": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + } + }, + /* + This tag does nothing and is here mostly to be used as a classification for + the bbcode input when evaluating parent-child tag relationships + */ + "bbcode": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + } + }, + "center": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + } + }, + "code": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + }, + noParse: true + }, + "color": { + openTag: function (params, content) { + params = params || ''; + var colorCode = (params.substr(1)).toLowerCase() || "black"; + colorNamePattern.lastIndex = 0; + colorCodePattern.lastIndex = 0; + if (!colorNamePattern.test(colorCode)) { + if (!colorCodePattern.test(colorCode)) { + colorCode = "black"; + } + else { + if (colorCode.substr(0, 1) !== "#") { + colorCode = "#" + colorCode; + } + } + } + return ''; + }, + closeTag: function (params, content) { + return ''; + } + }, + "email": { + openTag: function (params, content) { + var myEmail; + if (!params) { + myEmail = content.replace(/<.*?>/g, ""); + } + else { + myEmail = params.substr(1); + } + emailPattern.lastIndex = 0; + if (!emailPattern.test(myEmail)) { + return ''; + } + return ''; + }, + closeTag: function (params, content) { + return ''; + } + }, + "face": { + openTag: function (params, content) { + params = params || ''; + var faceCode = params.substr(1) || "inherit"; + fontFacePattern.lastIndex = 0; + if (!fontFacePattern.test(faceCode)) { + faceCode = "inherit"; + } + return ''; + }, + closeTag: function (params, content) { + return ''; + } + }, + "font": { + openTag: function (params, content) { + params = params || ''; + var faceCode = params.substr(1) || "inherit"; + fontFacePattern.lastIndex = 0; + if (!fontFacePattern.test(faceCode)) { + faceCode = "inherit"; + } + return ''; + }, + closeTag: function (params, content) { + return ''; + } + }, + "i": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + } + }, + "img": { + openTag: function (params, content) { + var myUrl = content; + urlPattern.lastIndex = 0; + if (!urlPattern.test(myUrl)) { + myUrl = ""; + } + return ''; + }, + closeTag: function (params, content) { + return ''; + }, + displayContent: false + }, + "justify": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + } + }, + "large": { + openTag: function (params, content) { + params = params || ''; + var colorCode = params.substr(1) || "inherit"; + colorNamePattern.lastIndex = 0; + colorCodePattern.lastIndex = 0; + if (!colorNamePattern.test(colorCode)) { + if (!colorCodePattern.test(colorCode)) { + colorCode = "inherit"; + } + else { + if (colorCode.substr(0, 1) !== "#") { + colorCode = "#" + colorCode; + } + } + } + return ''; + }, + closeTag: function (params, content) { + return ''; + } + }, + "left": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + } + }, + "li": { + openTag: function (params, content) { + return "
  • "; + }, + closeTag: function (params, content) { + return "
  • "; + }, + restrictParentsTo: ["list", "ul", "ol"] + }, + "list": { + openTag: function (params, content) { + return '
      '; + }, + closeTag: function (params, content) { + return '
    '; + }, + restrictChildrenTo: ["*", "li"] + }, + "noparse": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + }, + noParse: true + }, + "ol": { + openTag: function (params, content) { + return '
      '; + }, + closeTag: function (params, content) { + return '
    '; + }, + restrictChildrenTo: ["*", "li"] + }, + "php": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + }, + noParse: true + }, + "quote": { + openTag: function (params, content) { + return '
    '; + }, + closeTag: function (params, content) { + return '
    '; + } + }, + "right": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + } + }, + "s": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + } + }, + "size": { + openTag: function (params, content) { + params = params || ''; + var mySize = parseInt(params.substr(1), 10) || 0; + if (mySize < 4 || mySize > 40) { + mySize = 14; + } + return ''; + }, + closeTag: function (params, content) { + return ''; + } + }, + "small": { + openTag: function (params, content) { + params = params || ''; + var colorCode = params.substr(1) || "inherit"; + colorNamePattern.lastIndex = 0; + colorCodePattern.lastIndex = 0; + if (!colorNamePattern.test(colorCode)) { + if (!colorCodePattern.test(colorCode)) { + colorCode = "inherit"; + } + else { + if (colorCode.substr(0, 1) !== "#") { + colorCode = "#" + colorCode; + } + } + } + return ''; + }, + closeTag: function (params, content) { + return ''; + } + }, + "sub": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + } + }, + "sup": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + } + }, + "table": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return '
    '; + }, + restrictChildrenTo: ["tbody", "thead", "tfoot", "tr"] + }, + "tbody": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + }, + restrictChildrenTo: ["tr"], + restrictParentsTo: ["table"] + }, + "tfoot": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + }, + restrictChildrenTo: ["tr"], + restrictParentsTo: ["table"] + }, + "thead": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + }, + restrictChildrenTo: ["tr"], + restrictParentsTo: ["table"] + }, + "td": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + }, + restrictParentsTo: ["tr"] + }, + "th": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + }, + restrictParentsTo: ["tr"] + }, + "tr": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + }, + restrictChildrenTo: ["td", "th"], + restrictParentsTo: ["table", "tbody", "tfoot", "thead"] + }, + "u": { + openTag: function (params, content) { + return ''; + }, + closeTag: function (params, content) { + return ''; + } + }, + "ul": { + openTag: function (params, content) { + return '
      '; + }, + closeTag: function (params, content) { + return '
    '; + }, + restrictChildrenTo: ["*", "li"] + }, + "url": { + openTag: function (params, content) { + let myUrl; + if (!params) { + myUrl = content.replace(/<.*?>/g, ""); + } + else { + myUrl = params.substr(1); + } + urlPattern.lastIndex = 0; + if (!urlPattern.test(myUrl)) { + myUrl = "#"; + } + return ''; + }, + closeTag: function (params, content) { + return ''; + } + }, + "hr": { + openTag: (params, content) => { + return "
    "; + }, + closeTag: (params, content) => { + return ""; + } + }, + /* + The [*] tag is special since the user does not define a closing [/*] tag when writing their bbcode. + Instead this module parses the code and adds the closing [/*] tag in for them. None of the _tags you + add will act like this and this tag is an exception to the others. + */ + "*": { + openTag: function (params, content) { + return "
  • "; + }, + closeTag: function (params, content) { + return "
  • "; + }, + restrictParentsTo: ["list", "ul", "ol"] + } + }; + // create tag list and lookup fields + function initTags() { + tagList = []; + let prop, ii, len; + for (prop in _tags) { + if (_tags.hasOwnProperty(prop)) { + if (prop === "*") { + tagList.push("\\" + prop); + } + else { + tagList.push(prop); + if (_tags[prop].noParse) { + tagsNoParseList.push(prop); + } + } + _tags[prop].validChildLookup = {}; + _tags[prop].validParentLookup = {}; + _tags[prop].restrictParentsTo = _tags[prop].restrictParentsTo || []; + _tags[prop].restrictChildrenTo = _tags[prop].restrictChildrenTo || []; + len = _tags[prop].restrictChildrenTo.length; + for (ii = 0; ii < len; ii++) { + _tags[prop].validChildLookup[_tags[prop].restrictChildrenTo[ii]] = true; + } + len = _tags[prop].restrictParentsTo.length; + for (ii = 0; ii < len; ii++) { + _tags[prop].validParentLookup[_tags[prop].restrictParentsTo[ii]] = true; + } + } + } + bbRegExp = new RegExp("]*?)?>((?:.|[\\r\\n])*?)", "gi"); + pbbRegExp = new RegExp("\\[(" + tagList.join("|") + ")([ =][^\\]]*?)?\\]([^\\[]*?)\\[/\\1\\]", "gi"); + pbbRegExp2 = new RegExp("\\[(" + tagsNoParseList.join("|") + ")([ =][^\\]]*?)?\\]([\\s\\S]*?)\\[/\\1\\]", "gi"); + // create the regex for escaping ['s that aren't apart of _tags + (function () { + var closeTagList = []; + for (var ii = 0; ii < tagList.length; ii++) { + if (tagList[ii] !== "\\*") { // the * tag doesn't have an offical closing tag + closeTagList.push("/" + tagList[ii]); + } + } + openTags = new RegExp("(\\[)((?:" + tagList.join("|") + ")(?:[ =][^\\]]*?)?)(\\])", "gi"); + closeTags = new RegExp("(\\[)(" + closeTagList.join("|") + ")(\\])", "gi"); + })(); + } + initTags(); + // ----------------------------------------------------------------------------- + // private functions + // ----------------------------------------------------------------------------- + function checkParentChildRestrictions(parentTag, bbcode, bbcodeLevel, tagName, tagParams, tagContents, errQueue) { + errQueue = errQueue || []; + bbcodeLevel++; + // get a list of all of the child _tags to this tag + var reTagNames = new RegExp("(])", "gi"), reTagNamesParts = new RegExp("(])", "i"), matchingTags = tagContents.match(reTagNames) || [], cInfo, errStr, ii, childTag, pInfo = _tags[parentTag] || {}; + reTagNames.lastIndex = 0; + if (!matchingTags) { + tagContents = ""; + } + for (ii = 0; ii < matchingTags.length; ii++) { + reTagNamesParts.lastIndex = 0; + childTag = (matchingTags[ii].match(reTagNamesParts))[2].toLowerCase(); + if (pInfo && pInfo.restrictChildrenTo && pInfo.restrictChildrenTo.length > 0) { + if (!pInfo.validChildLookup[childTag]) { + errStr = "The tag \"" + childTag + "\" is not allowed as a child of the tag \"" + parentTag + "\"."; + errQueue.push(errStr); + } + } + cInfo = _tags[childTag] || {}; + if (cInfo.restrictParentsTo.length > 0) { + if (!cInfo.validParentLookup[parentTag]) { + errStr = "The tag \"" + parentTag + "\" is not allowed as a parent of the tag \"" + childTag + "\"."; + errQueue.push(errStr); + } + } + } + tagContents = tagContents.replace(bbRegExp, function (matchStr, bbcodeLevel, tagName, tagParams, tagContents) { + errQueue = checkParentChildRestrictions(tagName.toLowerCase(), matchStr, bbcodeLevel, tagName, tagParams, tagContents, errQueue); + return matchStr; + }); + return errQueue; + } + /* + This function updates or adds a piece of metadata to each tag called "bbcl" which + indicates how deeply nested a particular tag was in the bbcode. This property is removed + from the HTML code _tags at the end of the processing. + */ + function updateTagDepths(tagContents) { + tagContents = tagContents.replace(/\<([^\>][^\>]*?)\>/gi, function (matchStr, subMatchStr) { + var bbCodeLevel = subMatchStr.match(/^bbcl=([0-9]+) /); + if (bbCodeLevel === null) { + return ""; + } + else { + return "<" + subMatchStr.replace(/^(bbcl=)([0-9]+)/, function (matchStr, m1, m2) { + return m1 + (parseInt(m2, 10) + 1); + }) + ">"; + } + }); + return tagContents; + } + /* + This function removes the metadata added by the updateTagDepths function + */ + function unprocess(tagContent) { + return tagContent.replace(//gi, "").replace(//gi, "]"); + } + var replaceFunct = function (matchStr, bbcodeLevel, tagName, tagParams, tagContents) { + tagName = tagName.toLowerCase(); + var processedContent = _tags[tagName].noParse ? unprocess(tagContents) : tagContents.replace(bbRegExp, replaceFunct), openTag = _tags[tagName].openTag(tagParams, processedContent), closeTag = _tags[tagName].closeTag(tagParams, processedContent); + if (_tags[tagName].displayContent === false) { + processedContent = ""; + } + return openTag + processedContent + closeTag; + }; + function parse(config) { + var output = config.text; + output = output.replace(bbRegExp, replaceFunct); + return output; + } + /* + The star tag [*] is special in that it does not use a closing tag. Since this parser requires that _tags to have a closing + tag, we must pre-process the input and add in closing _tags [/*] for the star tag. + We have a little levaridge in that we know the text we're processing wont contain the <> characters (they have been + changed into their HTML entity form to prevent XSS and code injection), so we can use those characters as markers to + help us define boundaries and figure out where to place the [/*] _tags. + */ + function fixStarTag(text) { + text = text.replace(/\[(?!\*[ =\]]|list([ =][^\]]*)?\]|\/list[\]])/ig, "<"); + text = text.replace(/\[(?=list([ =][^\]]*)?\]|\/list[\]])/ig, ">"); + while (text !== (text = text.replace(/>list([ =][^\]]*)?\]([^>]*?)(>\/list])/gi, function (matchStr, contents, endTag) { + var innerListTxt = matchStr; + while (innerListTxt !== (innerListTxt = innerListTxt.replace(/\[\*\]([^\[]*?)(\[\*\]|>\/list])/i, function (matchStr, contents, endTag) { + if (endTag.toLowerCase() === ">/list]") { + endTag = "/g, "<"); + return innerListTxt; + }))) + ; + // add ['s for our _tags back in + text = text.replace(/"); + return updateTagDepths(matchStr); + }))) + ; + return text; + } + // ----------------------------------------------------------------------------- + // public functions + // ----------------------------------------------------------------------------- + // API, Expose all available _tags + function tags() { + return _tags; + } + XBBCODE.tags = tags; + ; + function addTags(...tags) { + for (const tag of tags) + _tags[tag.tag] = tag.function; + initTags(); + } + XBBCODE.addTags = addTags; + ; + class ProcessResult { + } + XBBCODE.ProcessResult = ProcessResult; + function process(config) { + let result = new ProcessResult(); + result.errorQueue = []; + config.text = config.text.replace(//g, ">"); // escape HTML tag brackets + config.text = config.text.replace(openTags, function (matchStr, openB, contents, closeB) { + return "<" + contents + ">"; + }); + config.text = config.text.replace(closeTags, function (matchStr, openB, contents, closeB) { + return "<" + contents + ">"; + }); + config.text = config.text.replace(/\[/g, "["); // escape ['s that aren't apart of _tags + config.text = config.text.replace(/\]/g, "]"); // escape ['s that aren't apart of _tags + config.text = config.text.replace(//g, "]"); // escape ['s that aren't apart of _tags + // process _tags that don't have their content parsed + while (config.text !== (config.text = config.text.replace(pbbRegExp2, function (matchStr, tagName, tagParams, tagContents) { + tagContents = tagContents.replace(/\[/g, "["); + tagContents = tagContents.replace(/\]/g, "]"); + tagParams = tagParams || ""; + tagContents = tagContents || ""; + return "[" + tagName + tagParams + "]" + tagContents + "[/" + tagName + "]"; + }))) + ; + config.text = fixStarTag(config.text); // add in closing _tags for the [*] tag + config.text = config.text.replace(/\[hr](?!.*\[\/hr])/gmi, "[hr][/hr]"); /* fix hr tag */ + config.text = addBbcodeLevels(config.text); // add in level metadata + result.errorQueue = checkParentChildRestrictions("bbcode", config.text, -1, "", "", config.text); + result.html = parse(config); + if (result.html.indexOf("[") !== -1 || result.html.indexOf("]") !== -1) { + result.errorQueue.push("Some _tags appear to be misaligned."); + } + if (config.removeMisalignedTags) { + result.html = result.html.replace(/\[.*?\]/g, ""); + } + if (config.addInLineBreaks) { + result.html = '
    ' + result.html + '
    '; + } + if (!config.escapeHtml) { + result.html = result.html.replace("[", "["); // put ['s back in + result.html = result.html.replace("]", "]"); // put ['s back in + } + if (result.errorQueue.length == 0) { + result.error = false; + result.errorQueue = undefined; + } + else { + result.error = true; + } + return result; + } + XBBCODE.process = process; + ; +})(XBBCODE || (XBBCODE = {})); +// for node +if (typeof module !== "undefined") { + module.exports = XBBCODE; +} +//# sourceMappingURL=xbbcode.js.map \ No newline at end of file diff --git a/test/vendor/bootstrap-material/bootstrap-material-design.js b/test/vendor/bootstrap-material/bootstrap-material-design.js new file mode 100644 index 00000000..3e396bdc --- /dev/null +++ b/test/vendor/bootstrap-material/bootstrap-material-design.js @@ -0,0 +1,6537 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(require('jquery'), require('popper.js')) : + typeof define === 'function' && define.amd ? define(['jquery', 'popper.js'], factory) : + (factory(global.jQuery,global.Popper)); +}(this, (function ($,Popper$1) { 'use strict'; + + $ = $ && $.hasOwnProperty('default') ? $['default'] : $; + Popper$1 = Popper$1 && Popper$1.hasOwnProperty('default') ? Popper$1['default'] : Popper$1; + + function _defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + function _createClass(Constructor, protoProps, staticProps) { + if (protoProps) _defineProperties(Constructor.prototype, protoProps); + if (staticProps) _defineProperties(Constructor, staticProps); + return Constructor; + } + + function _extends() { + _extends = Object.assign || function (target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + + for (var key in source) { + if (Object.prototype.hasOwnProperty.call(source, key)) { + target[key] = source[key]; + } + } + } + + return target; + }; + + return _extends.apply(this, arguments); + } + + function _inheritsLoose(subClass, superClass) { + subClass.prototype = Object.create(superClass.prototype); + subClass.prototype.constructor = subClass; + subClass.__proto__ = superClass; + } + + /** + * -------------------------------------------------------------------------- + * Bootstrap (v4.0.0): util.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * -------------------------------------------------------------------------- + */ + + var Util = function ($$$1) { + /** + * ------------------------------------------------------------------------ + * Private TransitionEnd Helpers + * ------------------------------------------------------------------------ + */ + var transition = false; + var MAX_UID = 1000000; // Shoutout AngusCroll (https://goo.gl/pxwQGp) + + function toType(obj) { + return {}.toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase(); + } + + function getSpecialTransitionEndEvent() { + return { + bindType: transition.end, + delegateType: transition.end, + handle: function handle(event) { + if ($$$1(event.target).is(this)) { + return event.handleObj.handler.apply(this, arguments); // eslint-disable-line prefer-rest-params + } + + return undefined; // eslint-disable-line no-undefined + } + }; + } + + function transitionEndTest() { + if (typeof window !== 'undefined' && window.QUnit) { + return false; + } + + return { + end: 'transitionend' + }; + } + + function transitionEndEmulator(duration) { + var _this = this; + + var called = false; + $$$1(this).one(Util.TRANSITION_END, function () { + called = true; + }); + setTimeout(function () { + if (!called) { + Util.triggerTransitionEnd(_this); + } + }, duration); + return this; + } + + function setTransitionEndSupport() { + transition = transitionEndTest(); + $$$1.fn.emulateTransitionEnd = transitionEndEmulator; + + if (Util.supportsTransitionEnd()) { + $$$1.event.special[Util.TRANSITION_END] = getSpecialTransitionEndEvent(); + } + } + + function escapeId(selector) { + // We escape IDs in case of special selectors (selector = '#myId:something') + // $.escapeSelector does not exist in jQuery < 3 + selector = typeof $$$1.escapeSelector === 'function' ? $$$1.escapeSelector(selector).substr(1) : selector.replace(/(:|\.|\[|\]|,|=|@)/g, '\\$1'); + return selector; + } + /** + * -------------------------------------------------------------------------- + * Public Util Api + * -------------------------------------------------------------------------- + */ + + + var Util = { + TRANSITION_END: 'bsTransitionEnd', + getUID: function getUID(prefix) { + do { + // eslint-disable-next-line no-bitwise + prefix += ~~(Math.random() * MAX_UID); // "~~" acts like a faster Math.floor() here + } while (document.getElementById(prefix)); + + return prefix; + }, + getSelectorFromElement: function getSelectorFromElement(element) { + var selector = element.getAttribute('data-target'); + + if (!selector || selector === '#') { + selector = element.getAttribute('href') || ''; + } // If it's an ID + + + if (selector.charAt(0) === '#') { + selector = escapeId(selector); + } + + try { + var $selector = $$$1(document).find(selector); + return $selector.length > 0 ? selector : null; + } catch (err) { + return null; + } + }, + reflow: function reflow(element) { + return element.offsetHeight; + }, + triggerTransitionEnd: function triggerTransitionEnd(element) { + $$$1(element).trigger(transition.end); + }, + supportsTransitionEnd: function supportsTransitionEnd() { + return Boolean(transition); + }, + isElement: function isElement(obj) { + return (obj[0] || obj).nodeType; + }, + typeCheckConfig: function typeCheckConfig(componentName, config, configTypes) { + for (var property in configTypes) { + if (Object.prototype.hasOwnProperty.call(configTypes, property)) { + var expectedTypes = configTypes[property]; + var value = config[property]; + var valueType = value && Util.isElement(value) ? 'element' : toType(value); + + if (!new RegExp(expectedTypes).test(valueType)) { + throw new Error(componentName.toUpperCase() + ": " + ("Option \"" + property + "\" provided type \"" + valueType + "\" ") + ("but expected type \"" + expectedTypes + "\".")); + } + } + } + } + }; + setTransitionEndSupport(); + return Util; + }($); + + /** + * -------------------------------------------------------------------------- + * Bootstrap (v4.0.0): alert.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * -------------------------------------------------------------------------- + */ + + var Alert = function ($$$1) { + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + var NAME = 'alert'; + var VERSION = '4.0.0'; + var DATA_KEY = 'bs.alert'; + var EVENT_KEY = "." + DATA_KEY; + var DATA_API_KEY = '.data-api'; + var JQUERY_NO_CONFLICT = $$$1.fn[NAME]; + var TRANSITION_DURATION = 150; + var Selector = { + DISMISS: '[data-dismiss="alert"]' + }; + var Event = { + CLOSE: "close" + EVENT_KEY, + CLOSED: "closed" + EVENT_KEY, + CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY + }; + var ClassName = { + ALERT: 'alert', + FADE: 'fade', + SHOW: 'show' + /** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + + }; + + var Alert = + /*#__PURE__*/ + function () { + function Alert(element) { + this._element = element; + } // Getters + + + var _proto = Alert.prototype; + + // Public + _proto.close = function close(element) { + element = element || this._element; + + var rootElement = this._getRootElement(element); + + var customEvent = this._triggerCloseEvent(rootElement); + + if (customEvent.isDefaultPrevented()) { + return; + } + + this._removeElement(rootElement); + }; + + _proto.dispose = function dispose() { + $$$1.removeData(this._element, DATA_KEY); + this._element = null; + }; // Private + + + _proto._getRootElement = function _getRootElement(element) { + var selector = Util.getSelectorFromElement(element); + var parent = false; + + if (selector) { + parent = $$$1(selector)[0]; + } + + if (!parent) { + parent = $$$1(element).closest("." + ClassName.ALERT)[0]; + } + + return parent; + }; + + _proto._triggerCloseEvent = function _triggerCloseEvent(element) { + var closeEvent = $$$1.Event(Event.CLOSE); + $$$1(element).trigger(closeEvent); + return closeEvent; + }; + + _proto._removeElement = function _removeElement(element) { + var _this = this; + + $$$1(element).removeClass(ClassName.SHOW); + + if (!Util.supportsTransitionEnd() || !$$$1(element).hasClass(ClassName.FADE)) { + this._destroyElement(element); + + return; + } + + $$$1(element).one(Util.TRANSITION_END, function (event) { + return _this._destroyElement(element, event); + }).emulateTransitionEnd(TRANSITION_DURATION); + }; + + _proto._destroyElement = function _destroyElement(element) { + $$$1(element).detach().trigger(Event.CLOSED).remove(); + }; // Static + + + Alert._jQueryInterface = function _jQueryInterface(config) { + return this.each(function () { + var $element = $$$1(this); + var data = $element.data(DATA_KEY); + + if (!data) { + data = new Alert(this); + $element.data(DATA_KEY, data); + } + + if (config === 'close') { + data[config](this); + } + }); + }; + + Alert._handleDismiss = function _handleDismiss(alertInstance) { + return function (event) { + if (event) { + event.preventDefault(); + } + + alertInstance.close(this); + }; + }; + + _createClass(Alert, null, [{ + key: "VERSION", + get: function get() { + return VERSION; + } + }]); + return Alert; + }(); + /** + * ------------------------------------------------------------------------ + * Data Api implementation + * ------------------------------------------------------------------------ + */ + + + $$$1(document).on(Event.CLICK_DATA_API, Selector.DISMISS, Alert._handleDismiss(new Alert())); + /** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + */ + + $$$1.fn[NAME] = Alert._jQueryInterface; + $$$1.fn[NAME].Constructor = Alert; + + $$$1.fn[NAME].noConflict = function () { + $$$1.fn[NAME] = JQUERY_NO_CONFLICT; + return Alert._jQueryInterface; + }; + + return Alert; + }($); + + /** + * -------------------------------------------------------------------------- + * Bootstrap (v4.0.0): button.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * -------------------------------------------------------------------------- + */ + + var Button = function ($$$1) { + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + var NAME = 'button'; + var VERSION = '4.0.0'; + var DATA_KEY = 'bs.button'; + var EVENT_KEY = "." + DATA_KEY; + var DATA_API_KEY = '.data-api'; + var JQUERY_NO_CONFLICT = $$$1.fn[NAME]; + var ClassName = { + ACTIVE: 'active', + BUTTON: 'btn', + FOCUS: 'focus' + }; + var Selector = { + DATA_TOGGLE_CARROT: '[data-toggle^="button"]', + DATA_TOGGLE: '[data-toggle="buttons"]', + INPUT: 'input', + ACTIVE: '.active', + BUTTON: '.btn' + }; + var Event = { + CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY, + FOCUS_BLUR_DATA_API: "focus" + EVENT_KEY + DATA_API_KEY + " " + ("blur" + EVENT_KEY + DATA_API_KEY) + /** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + + }; + + var Button = + /*#__PURE__*/ + function () { + function Button(element) { + this._element = element; + } // Getters + + + var _proto = Button.prototype; + + // Public + _proto.toggle = function toggle() { + var triggerChangeEvent = true; + var addAriaPressed = true; + var rootElement = $$$1(this._element).closest(Selector.DATA_TOGGLE)[0]; + + if (rootElement) { + var input = $$$1(this._element).find(Selector.INPUT)[0]; + + if (input) { + if (input.type === 'radio') { + if (input.checked && $$$1(this._element).hasClass(ClassName.ACTIVE)) { + triggerChangeEvent = false; + } else { + var activeElement = $$$1(rootElement).find(Selector.ACTIVE)[0]; + + if (activeElement) { + $$$1(activeElement).removeClass(ClassName.ACTIVE); + } + } + } + + if (triggerChangeEvent) { + if (input.hasAttribute('disabled') || rootElement.hasAttribute('disabled') || input.classList.contains('disabled') || rootElement.classList.contains('disabled')) { + return; + } + + input.checked = !$$$1(this._element).hasClass(ClassName.ACTIVE); + $$$1(input).trigger('change'); + } + + input.focus(); + addAriaPressed = false; + } + } + + if (addAriaPressed) { + this._element.setAttribute('aria-pressed', !$$$1(this._element).hasClass(ClassName.ACTIVE)); + } + + if (triggerChangeEvent) { + $$$1(this._element).toggleClass(ClassName.ACTIVE); + } + }; + + _proto.dispose = function dispose() { + $$$1.removeData(this._element, DATA_KEY); + this._element = null; + }; // Static + + + Button._jQueryInterface = function _jQueryInterface(config) { + return this.each(function () { + var data = $$$1(this).data(DATA_KEY); + + if (!data) { + data = new Button(this); + $$$1(this).data(DATA_KEY, data); + } + + if (config === 'toggle') { + data[config](); + } + }); + }; + + _createClass(Button, null, [{ + key: "VERSION", + get: function get() { + return VERSION; + } + }]); + return Button; + }(); + /** + * ------------------------------------------------------------------------ + * Data Api implementation + * ------------------------------------------------------------------------ + */ + + + $$$1(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE_CARROT, function (event) { + event.preventDefault(); + var button = event.target; + + if (!$$$1(button).hasClass(ClassName.BUTTON)) { + button = $$$1(button).closest(Selector.BUTTON); + } + + Button._jQueryInterface.call($$$1(button), 'toggle'); + }).on(Event.FOCUS_BLUR_DATA_API, Selector.DATA_TOGGLE_CARROT, function (event) { + var button = $$$1(event.target).closest(Selector.BUTTON)[0]; + $$$1(button).toggleClass(ClassName.FOCUS, /^focus(in)?$/.test(event.type)); + }); + /** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + */ + + $$$1.fn[NAME] = Button._jQueryInterface; + $$$1.fn[NAME].Constructor = Button; + + $$$1.fn[NAME].noConflict = function () { + $$$1.fn[NAME] = JQUERY_NO_CONFLICT; + return Button._jQueryInterface; + }; + + return Button; + }($); + + /** + * -------------------------------------------------------------------------- + * Bootstrap (v4.0.0): carousel.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * -------------------------------------------------------------------------- + */ + + var Carousel = function ($$$1) { + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + var NAME = 'carousel'; + var VERSION = '4.0.0'; + var DATA_KEY = 'bs.carousel'; + var EVENT_KEY = "." + DATA_KEY; + var DATA_API_KEY = '.data-api'; + var JQUERY_NO_CONFLICT = $$$1.fn[NAME]; + var TRANSITION_DURATION = 600; + var ARROW_LEFT_KEYCODE = 37; // KeyboardEvent.which value for left arrow key + + var ARROW_RIGHT_KEYCODE = 39; // KeyboardEvent.which value for right arrow key + + var TOUCHEVENT_COMPAT_WAIT = 500; // Time for mouse compat events to fire after touch + + var Default = { + interval: 5000, + keyboard: true, + slide: false, + pause: 'hover', + wrap: true + }; + var DefaultType = { + interval: '(number|boolean)', + keyboard: 'boolean', + slide: '(boolean|string)', + pause: '(string|boolean)', + wrap: 'boolean' + }; + var Direction = { + NEXT: 'next', + PREV: 'prev', + LEFT: 'left', + RIGHT: 'right' + }; + var Event = { + SLIDE: "slide" + EVENT_KEY, + SLID: "slid" + EVENT_KEY, + KEYDOWN: "keydown" + EVENT_KEY, + MOUSEENTER: "mouseenter" + EVENT_KEY, + MOUSELEAVE: "mouseleave" + EVENT_KEY, + TOUCHEND: "touchend" + EVENT_KEY, + LOAD_DATA_API: "load" + EVENT_KEY + DATA_API_KEY, + CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY + }; + var ClassName = { + CAROUSEL: 'carousel', + ACTIVE: 'active', + SLIDE: 'slide', + RIGHT: 'carousel-item-right', + LEFT: 'carousel-item-left', + NEXT: 'carousel-item-next', + PREV: 'carousel-item-prev', + ITEM: 'carousel-item' + }; + var Selector = { + ACTIVE: '.active', + ACTIVE_ITEM: '.active.carousel-item', + ITEM: '.carousel-item', + NEXT_PREV: '.carousel-item-next, .carousel-item-prev', + INDICATORS: '.carousel-indicators', + DATA_SLIDE: '[data-slide], [data-slide-to]', + DATA_RIDE: '[data-ride="carousel"]' + /** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + + }; + + var Carousel = + /*#__PURE__*/ + function () { + function Carousel(element, config) { + this._items = null; + this._interval = null; + this._activeElement = null; + this._isPaused = false; + this._isSliding = false; + this.touchTimeout = null; + this._config = this._getConfig(config); + this._element = $$$1(element)[0]; + this._indicatorsElement = $$$1(this._element).find(Selector.INDICATORS)[0]; + + this._addEventListeners(); + } // Getters + + + var _proto = Carousel.prototype; + + // Public + _proto.next = function next() { + if (!this._isSliding) { + this._slide(Direction.NEXT); + } + }; + + _proto.nextWhenVisible = function nextWhenVisible() { + // Don't call next when the page isn't visible + // or the carousel or its parent isn't visible + if (!document.hidden && $$$1(this._element).is(':visible') && $$$1(this._element).css('visibility') !== 'hidden') { + this.next(); + } + }; + + _proto.prev = function prev() { + if (!this._isSliding) { + this._slide(Direction.PREV); + } + }; + + _proto.pause = function pause(event) { + if (!event) { + this._isPaused = true; + } + + if ($$$1(this._element).find(Selector.NEXT_PREV)[0] && Util.supportsTransitionEnd()) { + Util.triggerTransitionEnd(this._element); + this.cycle(true); + } + + clearInterval(this._interval); + this._interval = null; + }; + + _proto.cycle = function cycle(event) { + if (!event) { + this._isPaused = false; + } + + if (this._interval) { + clearInterval(this._interval); + this._interval = null; + } + + if (this._config.interval && !this._isPaused) { + this._interval = setInterval((document.visibilityState ? this.nextWhenVisible : this.next).bind(this), this._config.interval); + } + }; + + _proto.to = function to(index) { + var _this = this; + + this._activeElement = $$$1(this._element).find(Selector.ACTIVE_ITEM)[0]; + + var activeIndex = this._getItemIndex(this._activeElement); + + if (index > this._items.length - 1 || index < 0) { + return; + } + + if (this._isSliding) { + $$$1(this._element).one(Event.SLID, function () { + return _this.to(index); + }); + return; + } + + if (activeIndex === index) { + this.pause(); + this.cycle(); + return; + } + + var direction = index > activeIndex ? Direction.NEXT : Direction.PREV; + + this._slide(direction, this._items[index]); + }; + + _proto.dispose = function dispose() { + $$$1(this._element).off(EVENT_KEY); + $$$1.removeData(this._element, DATA_KEY); + this._items = null; + this._config = null; + this._element = null; + this._interval = null; + this._isPaused = null; + this._isSliding = null; + this._activeElement = null; + this._indicatorsElement = null; + }; // Private + + + _proto._getConfig = function _getConfig(config) { + config = _extends({}, Default, config); + Util.typeCheckConfig(NAME, config, DefaultType); + return config; + }; + + _proto._addEventListeners = function _addEventListeners() { + var _this2 = this; + + if (this._config.keyboard) { + $$$1(this._element).on(Event.KEYDOWN, function (event) { + return _this2._keydown(event); + }); + } + + if (this._config.pause === 'hover') { + $$$1(this._element).on(Event.MOUSEENTER, function (event) { + return _this2.pause(event); + }).on(Event.MOUSELEAVE, function (event) { + return _this2.cycle(event); + }); + + if ('ontouchstart' in document.documentElement) { + // If it's a touch-enabled device, mouseenter/leave are fired as + // part of the mouse compatibility events on first tap - the carousel + // would stop cycling until user tapped out of it; + // here, we listen for touchend, explicitly pause the carousel + // (as if it's the second time we tap on it, mouseenter compat event + // is NOT fired) and after a timeout (to allow for mouse compatibility + // events to fire) we explicitly restart cycling + $$$1(this._element).on(Event.TOUCHEND, function () { + _this2.pause(); + + if (_this2.touchTimeout) { + clearTimeout(_this2.touchTimeout); + } + + _this2.touchTimeout = setTimeout(function (event) { + return _this2.cycle(event); + }, TOUCHEVENT_COMPAT_WAIT + _this2._config.interval); + }); + } + } + }; + + _proto._keydown = function _keydown(event) { + if (/input|textarea/i.test(event.target.tagName)) { + return; + } + + switch (event.which) { + case ARROW_LEFT_KEYCODE: + event.preventDefault(); + this.prev(); + break; + + case ARROW_RIGHT_KEYCODE: + event.preventDefault(); + this.next(); + break; + + default: + } + }; + + _proto._getItemIndex = function _getItemIndex(element) { + this._items = $$$1.makeArray($$$1(element).parent().find(Selector.ITEM)); + return this._items.indexOf(element); + }; + + _proto._getItemByDirection = function _getItemByDirection(direction, activeElement) { + var isNextDirection = direction === Direction.NEXT; + var isPrevDirection = direction === Direction.PREV; + + var activeIndex = this._getItemIndex(activeElement); + + var lastItemIndex = this._items.length - 1; + var isGoingToWrap = isPrevDirection && activeIndex === 0 || isNextDirection && activeIndex === lastItemIndex; + + if (isGoingToWrap && !this._config.wrap) { + return activeElement; + } + + var delta = direction === Direction.PREV ? -1 : 1; + var itemIndex = (activeIndex + delta) % this._items.length; + return itemIndex === -1 ? this._items[this._items.length - 1] : this._items[itemIndex]; + }; + + _proto._triggerSlideEvent = function _triggerSlideEvent(relatedTarget, eventDirectionName) { + var targetIndex = this._getItemIndex(relatedTarget); + + var fromIndex = this._getItemIndex($$$1(this._element).find(Selector.ACTIVE_ITEM)[0]); + + var slideEvent = $$$1.Event(Event.SLIDE, { + relatedTarget: relatedTarget, + direction: eventDirectionName, + from: fromIndex, + to: targetIndex + }); + $$$1(this._element).trigger(slideEvent); + return slideEvent; + }; + + _proto._setActiveIndicatorElement = function _setActiveIndicatorElement(element) { + if (this._indicatorsElement) { + $$$1(this._indicatorsElement).find(Selector.ACTIVE).removeClass(ClassName.ACTIVE); + + var nextIndicator = this._indicatorsElement.children[this._getItemIndex(element)]; + + if (nextIndicator) { + $$$1(nextIndicator).addClass(ClassName.ACTIVE); + } + } + }; + + _proto._slide = function _slide(direction, element) { + var _this3 = this; + + var activeElement = $$$1(this._element).find(Selector.ACTIVE_ITEM)[0]; + + var activeElementIndex = this._getItemIndex(activeElement); + + var nextElement = element || activeElement && this._getItemByDirection(direction, activeElement); + + var nextElementIndex = this._getItemIndex(nextElement); + + var isCycling = Boolean(this._interval); + var directionalClassName; + var orderClassName; + var eventDirectionName; + + if (direction === Direction.NEXT) { + directionalClassName = ClassName.LEFT; + orderClassName = ClassName.NEXT; + eventDirectionName = Direction.LEFT; + } else { + directionalClassName = ClassName.RIGHT; + orderClassName = ClassName.PREV; + eventDirectionName = Direction.RIGHT; + } + + if (nextElement && $$$1(nextElement).hasClass(ClassName.ACTIVE)) { + this._isSliding = false; + return; + } + + var slideEvent = this._triggerSlideEvent(nextElement, eventDirectionName); + + if (slideEvent.isDefaultPrevented()) { + return; + } + + if (!activeElement || !nextElement) { + // Some weirdness is happening, so we bail + return; + } + + this._isSliding = true; + + if (isCycling) { + this.pause(); + } + + this._setActiveIndicatorElement(nextElement); + + var slidEvent = $$$1.Event(Event.SLID, { + relatedTarget: nextElement, + direction: eventDirectionName, + from: activeElementIndex, + to: nextElementIndex + }); + + if (Util.supportsTransitionEnd() && $$$1(this._element).hasClass(ClassName.SLIDE)) { + $$$1(nextElement).addClass(orderClassName); + Util.reflow(nextElement); + $$$1(activeElement).addClass(directionalClassName); + $$$1(nextElement).addClass(directionalClassName); + $$$1(activeElement).one(Util.TRANSITION_END, function () { + $$$1(nextElement).removeClass(directionalClassName + " " + orderClassName).addClass(ClassName.ACTIVE); + $$$1(activeElement).removeClass(ClassName.ACTIVE + " " + orderClassName + " " + directionalClassName); + _this3._isSliding = false; + setTimeout(function () { + return $$$1(_this3._element).trigger(slidEvent); + }, 0); + }).emulateTransitionEnd(TRANSITION_DURATION); + } else { + $$$1(activeElement).removeClass(ClassName.ACTIVE); + $$$1(nextElement).addClass(ClassName.ACTIVE); + this._isSliding = false; + $$$1(this._element).trigger(slidEvent); + } + + if (isCycling) { + this.cycle(); + } + }; // Static + + + Carousel._jQueryInterface = function _jQueryInterface(config) { + return this.each(function () { + var data = $$$1(this).data(DATA_KEY); + + var _config = _extends({}, Default, $$$1(this).data()); + + if (typeof config === 'object') { + _config = _extends({}, _config, config); + } + + var action = typeof config === 'string' ? config : _config.slide; + + if (!data) { + data = new Carousel(this, _config); + $$$1(this).data(DATA_KEY, data); + } + + if (typeof config === 'number') { + data.to(config); + } else if (typeof action === 'string') { + if (typeof data[action] === 'undefined') { + throw new TypeError("No method named \"" + action + "\""); + } + + data[action](); + } else if (_config.interval) { + data.pause(); + data.cycle(); + } + }); + }; + + Carousel._dataApiClickHandler = function _dataApiClickHandler(event) { + var selector = Util.getSelectorFromElement(this); + + if (!selector) { + return; + } + + var target = $$$1(selector)[0]; + + if (!target || !$$$1(target).hasClass(ClassName.CAROUSEL)) { + return; + } + + var config = _extends({}, $$$1(target).data(), $$$1(this).data()); + var slideIndex = this.getAttribute('data-slide-to'); + + if (slideIndex) { + config.interval = false; + } + + Carousel._jQueryInterface.call($$$1(target), config); + + if (slideIndex) { + $$$1(target).data(DATA_KEY).to(slideIndex); + } + + event.preventDefault(); + }; + + _createClass(Carousel, null, [{ + key: "VERSION", + get: function get() { + return VERSION; + } + }, { + key: "Default", + get: function get() { + return Default; + } + }]); + return Carousel; + }(); + /** + * ------------------------------------------------------------------------ + * Data Api implementation + * ------------------------------------------------------------------------ + */ + + + $$$1(document).on(Event.CLICK_DATA_API, Selector.DATA_SLIDE, Carousel._dataApiClickHandler); + $$$1(window).on(Event.LOAD_DATA_API, function () { + $$$1(Selector.DATA_RIDE).each(function () { + var $carousel = $$$1(this); + + Carousel._jQueryInterface.call($carousel, $carousel.data()); + }); + }); + /** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + */ + + $$$1.fn[NAME] = Carousel._jQueryInterface; + $$$1.fn[NAME].Constructor = Carousel; + + $$$1.fn[NAME].noConflict = function () { + $$$1.fn[NAME] = JQUERY_NO_CONFLICT; + return Carousel._jQueryInterface; + }; + + return Carousel; + }($); + + /** + * -------------------------------------------------------------------------- + * Bootstrap (v4.0.0): collapse.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * -------------------------------------------------------------------------- + */ + + var Collapse = function ($$$1) { + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + var NAME = 'collapse'; + var VERSION = '4.0.0'; + var DATA_KEY = 'bs.collapse'; + var EVENT_KEY = "." + DATA_KEY; + var DATA_API_KEY = '.data-api'; + var JQUERY_NO_CONFLICT = $$$1.fn[NAME]; + var TRANSITION_DURATION = 600; + var Default = { + toggle: true, + parent: '' + }; + var DefaultType = { + toggle: 'boolean', + parent: '(string|element)' + }; + var Event = { + SHOW: "show" + EVENT_KEY, + SHOWN: "shown" + EVENT_KEY, + HIDE: "hide" + EVENT_KEY, + HIDDEN: "hidden" + EVENT_KEY, + CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY + }; + var ClassName = { + SHOW: 'show', + COLLAPSE: 'collapse', + COLLAPSING: 'collapsing', + COLLAPSED: 'collapsed' + }; + var Dimension = { + WIDTH: 'width', + HEIGHT: 'height' + }; + var Selector = { + ACTIVES: '.show, .collapsing', + DATA_TOGGLE: '[data-toggle="collapse"]' + /** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + + }; + + var Collapse = + /*#__PURE__*/ + function () { + function Collapse(element, config) { + this._isTransitioning = false; + this._element = element; + this._config = this._getConfig(config); + this._triggerArray = $$$1.makeArray($$$1("[data-toggle=\"collapse\"][href=\"#" + element.id + "\"]," + ("[data-toggle=\"collapse\"][data-target=\"#" + element.id + "\"]"))); + var tabToggles = $$$1(Selector.DATA_TOGGLE); + + for (var i = 0; i < tabToggles.length; i++) { + var elem = tabToggles[i]; + var selector = Util.getSelectorFromElement(elem); + + if (selector !== null && $$$1(selector).filter(element).length > 0) { + this._selector = selector; + + this._triggerArray.push(elem); + } + } + + this._parent = this._config.parent ? this._getParent() : null; + + if (!this._config.parent) { + this._addAriaAndCollapsedClass(this._element, this._triggerArray); + } + + if (this._config.toggle) { + this.toggle(); + } + } // Getters + + + var _proto = Collapse.prototype; + + // Public + _proto.toggle = function toggle() { + if ($$$1(this._element).hasClass(ClassName.SHOW)) { + this.hide(); + } else { + this.show(); + } + }; + + _proto.show = function show() { + var _this = this; + + if (this._isTransitioning || $$$1(this._element).hasClass(ClassName.SHOW)) { + return; + } + + var actives; + var activesData; + + if (this._parent) { + actives = $$$1.makeArray($$$1(this._parent).find(Selector.ACTIVES).filter("[data-parent=\"" + this._config.parent + "\"]")); + + if (actives.length === 0) { + actives = null; + } + } + + if (actives) { + activesData = $$$1(actives).not(this._selector).data(DATA_KEY); + + if (activesData && activesData._isTransitioning) { + return; + } + } + + var startEvent = $$$1.Event(Event.SHOW); + $$$1(this._element).trigger(startEvent); + + if (startEvent.isDefaultPrevented()) { + return; + } + + if (actives) { + Collapse._jQueryInterface.call($$$1(actives).not(this._selector), 'hide'); + + if (!activesData) { + $$$1(actives).data(DATA_KEY, null); + } + } + + var dimension = this._getDimension(); + + $$$1(this._element).removeClass(ClassName.COLLAPSE).addClass(ClassName.COLLAPSING); + this._element.style[dimension] = 0; + + if (this._triggerArray.length > 0) { + $$$1(this._triggerArray).removeClass(ClassName.COLLAPSED).attr('aria-expanded', true); + } + + this.setTransitioning(true); + + var complete = function complete() { + $$$1(_this._element).removeClass(ClassName.COLLAPSING).addClass(ClassName.COLLAPSE).addClass(ClassName.SHOW); + _this._element.style[dimension] = ''; + + _this.setTransitioning(false); + + $$$1(_this._element).trigger(Event.SHOWN); + }; + + if (!Util.supportsTransitionEnd()) { + complete(); + return; + } + + var capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1); + var scrollSize = "scroll" + capitalizedDimension; + $$$1(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(TRANSITION_DURATION); + this._element.style[dimension] = this._element[scrollSize] + "px"; + }; + + _proto.hide = function hide() { + var _this2 = this; + + if (this._isTransitioning || !$$$1(this._element).hasClass(ClassName.SHOW)) { + return; + } + + var startEvent = $$$1.Event(Event.HIDE); + $$$1(this._element).trigger(startEvent); + + if (startEvent.isDefaultPrevented()) { + return; + } + + var dimension = this._getDimension(); + + this._element.style[dimension] = this._element.getBoundingClientRect()[dimension] + "px"; + Util.reflow(this._element); + $$$1(this._element).addClass(ClassName.COLLAPSING).removeClass(ClassName.COLLAPSE).removeClass(ClassName.SHOW); + + if (this._triggerArray.length > 0) { + for (var i = 0; i < this._triggerArray.length; i++) { + var trigger = this._triggerArray[i]; + var selector = Util.getSelectorFromElement(trigger); + + if (selector !== null) { + var $elem = $$$1(selector); + + if (!$elem.hasClass(ClassName.SHOW)) { + $$$1(trigger).addClass(ClassName.COLLAPSED).attr('aria-expanded', false); + } + } + } + } + + this.setTransitioning(true); + + var complete = function complete() { + _this2.setTransitioning(false); + + $$$1(_this2._element).removeClass(ClassName.COLLAPSING).addClass(ClassName.COLLAPSE).trigger(Event.HIDDEN); + }; + + this._element.style[dimension] = ''; + + if (!Util.supportsTransitionEnd()) { + complete(); + return; + } + + $$$1(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(TRANSITION_DURATION); + }; + + _proto.setTransitioning = function setTransitioning(isTransitioning) { + this._isTransitioning = isTransitioning; + }; + + _proto.dispose = function dispose() { + $$$1.removeData(this._element, DATA_KEY); + this._config = null; + this._parent = null; + this._element = null; + this._triggerArray = null; + this._isTransitioning = null; + }; // Private + + + _proto._getConfig = function _getConfig(config) { + config = _extends({}, Default, config); + config.toggle = Boolean(config.toggle); // Coerce string values + + Util.typeCheckConfig(NAME, config, DefaultType); + return config; + }; + + _proto._getDimension = function _getDimension() { + var hasWidth = $$$1(this._element).hasClass(Dimension.WIDTH); + return hasWidth ? Dimension.WIDTH : Dimension.HEIGHT; + }; + + _proto._getParent = function _getParent() { + var _this3 = this; + + var parent = null; + + if (Util.isElement(this._config.parent)) { + parent = this._config.parent; // It's a jQuery object + + if (typeof this._config.parent.jquery !== 'undefined') { + parent = this._config.parent[0]; + } + } else { + parent = $$$1(this._config.parent)[0]; + } + + var selector = "[data-toggle=\"collapse\"][data-parent=\"" + this._config.parent + "\"]"; + $$$1(parent).find(selector).each(function (i, element) { + _this3._addAriaAndCollapsedClass(Collapse._getTargetFromElement(element), [element]); + }); + return parent; + }; + + _proto._addAriaAndCollapsedClass = function _addAriaAndCollapsedClass(element, triggerArray) { + if (element) { + var isOpen = $$$1(element).hasClass(ClassName.SHOW); + + if (triggerArray.length > 0) { + $$$1(triggerArray).toggleClass(ClassName.COLLAPSED, !isOpen).attr('aria-expanded', isOpen); + } + } + }; // Static + + + Collapse._getTargetFromElement = function _getTargetFromElement(element) { + var selector = Util.getSelectorFromElement(element); + return selector ? $$$1(selector)[0] : null; + }; + + Collapse._jQueryInterface = function _jQueryInterface(config) { + return this.each(function () { + var $this = $$$1(this); + var data = $this.data(DATA_KEY); + + var _config = _extends({}, Default, $this.data(), typeof config === 'object' && config); + + if (!data && _config.toggle && /show|hide/.test(config)) { + _config.toggle = false; + } + + if (!data) { + data = new Collapse(this, _config); + $this.data(DATA_KEY, data); + } + + if (typeof config === 'string') { + if (typeof data[config] === 'undefined') { + throw new TypeError("No method named \"" + config + "\""); + } + + data[config](); + } + }); + }; + + _createClass(Collapse, null, [{ + key: "VERSION", + get: function get() { + return VERSION; + } + }, { + key: "Default", + get: function get() { + return Default; + } + }]); + return Collapse; + }(); + /** + * ------------------------------------------------------------------------ + * Data Api implementation + * ------------------------------------------------------------------------ + */ + + + $$$1(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) { + // preventDefault only for elements (which change the URL) not inside the collapsible element + if (event.currentTarget.tagName === 'A') { + event.preventDefault(); + } + + var $trigger = $$$1(this); + var selector = Util.getSelectorFromElement(this); + $$$1(selector).each(function () { + var $target = $$$1(this); + var data = $target.data(DATA_KEY); + var config = data ? 'toggle' : $trigger.data(); + + Collapse._jQueryInterface.call($target, config); + }); + }); + /** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + */ + + $$$1.fn[NAME] = Collapse._jQueryInterface; + $$$1.fn[NAME].Constructor = Collapse; + + $$$1.fn[NAME].noConflict = function () { + $$$1.fn[NAME] = JQUERY_NO_CONFLICT; + return Collapse._jQueryInterface; + }; + + return Collapse; + }($); + + /** + * -------------------------------------------------------------------------- + * Bootstrap (v4.0.0): modal.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * -------------------------------------------------------------------------- + */ + + var Modal = function ($$$1) { + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + var NAME = 'modal'; + var VERSION = '4.0.0'; + var DATA_KEY = 'bs.modal'; + var EVENT_KEY = "." + DATA_KEY; + var DATA_API_KEY = '.data-api'; + var JQUERY_NO_CONFLICT = $$$1.fn[NAME]; + var TRANSITION_DURATION = 300; + var BACKDROP_TRANSITION_DURATION = 150; + var ESCAPE_KEYCODE = 27; // KeyboardEvent.which value for Escape (Esc) key + + var Default = { + backdrop: true, + keyboard: true, + focus: true, + show: true + }; + var DefaultType = { + backdrop: '(boolean|string)', + keyboard: 'boolean', + focus: 'boolean', + show: 'boolean' + }; + var Event = { + HIDE: "hide" + EVENT_KEY, + HIDDEN: "hidden" + EVENT_KEY, + SHOW: "show" + EVENT_KEY, + SHOWN: "shown" + EVENT_KEY, + FOCUSIN: "focusin" + EVENT_KEY, + RESIZE: "resize" + EVENT_KEY, + CLICK_DISMISS: "click.dismiss" + EVENT_KEY, + KEYDOWN_DISMISS: "keydown.dismiss" + EVENT_KEY, + MOUSEUP_DISMISS: "mouseup.dismiss" + EVENT_KEY, + MOUSEDOWN_DISMISS: "mousedown.dismiss" + EVENT_KEY, + CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY + }; + var ClassName = { + SCROLLBAR_MEASURER: 'modal-scrollbar-measure', + BACKDROP: 'modal-backdrop', + OPEN: 'modal-open', + FADE: 'fade', + SHOW: 'show' + }; + var Selector = { + DIALOG: '.modal-dialog', + DATA_TOGGLE: '[data-toggle="modal"]', + DATA_DISMISS: '[data-dismiss="modal"]', + FIXED_CONTENT: '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top', + STICKY_CONTENT: '.sticky-top', + NAVBAR_TOGGLER: '.navbar-toggler' + /** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + + }; + + var Modal = + /*#__PURE__*/ + function () { + function Modal(element, config) { + this._config = this._getConfig(config); + this._element = element; + this._dialog = $$$1(element).find(Selector.DIALOG)[0]; + this._backdrop = null; + this._isShown = false; + this._isBodyOverflowing = false; + this._ignoreBackdropClick = false; + this._originalBodyPadding = 0; + this._scrollbarWidth = 0; + } // Getters + + + var _proto = Modal.prototype; + + // Public + _proto.toggle = function toggle(relatedTarget) { + return this._isShown ? this.hide() : this.show(relatedTarget); + }; + + _proto.show = function show(relatedTarget) { + var _this = this; + + if (this._isTransitioning || this._isShown) { + return; + } + + if (Util.supportsTransitionEnd() && $$$1(this._element).hasClass(ClassName.FADE)) { + this._isTransitioning = true; + } + + var showEvent = $$$1.Event(Event.SHOW, { + relatedTarget: relatedTarget + }); + $$$1(this._element).trigger(showEvent); + + if (this._isShown || showEvent.isDefaultPrevented()) { + return; + } + + this._isShown = true; + + this._checkScrollbar(); + + this._setScrollbar(); + + this._adjustDialog(); + + $$$1(document.body).addClass(ClassName.OPEN); + + this._setEscapeEvent(); + + this._setResizeEvent(); + + $$$1(this._element).on(Event.CLICK_DISMISS, Selector.DATA_DISMISS, function (event) { + return _this.hide(event); + }); + $$$1(this._dialog).on(Event.MOUSEDOWN_DISMISS, function () { + $$$1(_this._element).one(Event.MOUSEUP_DISMISS, function (event) { + if ($$$1(event.target).is(_this._element)) { + _this._ignoreBackdropClick = true; + } + }); + }); + + this._showBackdrop(function () { + return _this._showElement(relatedTarget); + }); + }; + + _proto.hide = function hide(event) { + var _this2 = this; + + if (event) { + event.preventDefault(); + } + + if (this._isTransitioning || !this._isShown) { + return; + } + + var hideEvent = $$$1.Event(Event.HIDE); + $$$1(this._element).trigger(hideEvent); + + if (!this._isShown || hideEvent.isDefaultPrevented()) { + return; + } + + this._isShown = false; + var transition = Util.supportsTransitionEnd() && $$$1(this._element).hasClass(ClassName.FADE); + + if (transition) { + this._isTransitioning = true; + } + + this._setEscapeEvent(); + + this._setResizeEvent(); + + $$$1(document).off(Event.FOCUSIN); + $$$1(this._element).removeClass(ClassName.SHOW); + $$$1(this._element).off(Event.CLICK_DISMISS); + $$$1(this._dialog).off(Event.MOUSEDOWN_DISMISS); + + if (transition) { + $$$1(this._element).one(Util.TRANSITION_END, function (event) { + return _this2._hideModal(event); + }).emulateTransitionEnd(TRANSITION_DURATION); + } else { + this._hideModal(); + } + }; + + _proto.dispose = function dispose() { + $$$1.removeData(this._element, DATA_KEY); + $$$1(window, document, this._element, this._backdrop).off(EVENT_KEY); + this._config = null; + this._element = null; + this._dialog = null; + this._backdrop = null; + this._isShown = null; + this._isBodyOverflowing = null; + this._ignoreBackdropClick = null; + this._scrollbarWidth = null; + }; + + _proto.handleUpdate = function handleUpdate() { + this._adjustDialog(); + }; // Private + + + _proto._getConfig = function _getConfig(config) { + config = _extends({}, Default, config); + Util.typeCheckConfig(NAME, config, DefaultType); + return config; + }; + + _proto._showElement = function _showElement(relatedTarget) { + var _this3 = this; + + var transition = Util.supportsTransitionEnd() && $$$1(this._element).hasClass(ClassName.FADE); + + if (!this._element.parentNode || this._element.parentNode.nodeType !== Node.ELEMENT_NODE) { + // Don't move modal's DOM position + document.body.appendChild(this._element); + } + + this._element.style.display = 'block'; + + this._element.removeAttribute('aria-hidden'); + + this._element.scrollTop = 0; + + if (transition) { + Util.reflow(this._element); + } + + $$$1(this._element).addClass(ClassName.SHOW); + + if (this._config.focus) { + this._enforceFocus(); + } + + var shownEvent = $$$1.Event(Event.SHOWN, { + relatedTarget: relatedTarget + }); + + var transitionComplete = function transitionComplete() { + if (_this3._config.focus) { + _this3._element.focus(); + } + + _this3._isTransitioning = false; + $$$1(_this3._element).trigger(shownEvent); + }; + + if (transition) { + $$$1(this._dialog).one(Util.TRANSITION_END, transitionComplete).emulateTransitionEnd(TRANSITION_DURATION); + } else { + transitionComplete(); + } + }; + + _proto._enforceFocus = function _enforceFocus() { + var _this4 = this; + + $$$1(document).off(Event.FOCUSIN) // Guard against infinite focus loop + .on(Event.FOCUSIN, function (event) { + if (document !== event.target && _this4._element !== event.target && $$$1(_this4._element).has(event.target).length === 0) { + _this4._element.focus(); + } + }); + }; + + _proto._setEscapeEvent = function _setEscapeEvent() { + var _this5 = this; + + if (this._isShown && this._config.keyboard) { + $$$1(this._element).on(Event.KEYDOWN_DISMISS, function (event) { + if (event.which === ESCAPE_KEYCODE) { + event.preventDefault(); + + _this5.hide(); + } + }); + } else if (!this._isShown) { + $$$1(this._element).off(Event.KEYDOWN_DISMISS); + } + }; + + _proto._setResizeEvent = function _setResizeEvent() { + var _this6 = this; + + if (this._isShown) { + $$$1(window).on(Event.RESIZE, function (event) { + return _this6.handleUpdate(event); + }); + } else { + $$$1(window).off(Event.RESIZE); + } + }; + + _proto._hideModal = function _hideModal() { + var _this7 = this; + + this._element.style.display = 'none'; + + this._element.setAttribute('aria-hidden', true); + + this._isTransitioning = false; + + this._showBackdrop(function () { + $$$1(document.body).removeClass(ClassName.OPEN); + + _this7._resetAdjustments(); + + _this7._resetScrollbar(); + + $$$1(_this7._element).trigger(Event.HIDDEN); + }); + }; + + _proto._removeBackdrop = function _removeBackdrop() { + if (this._backdrop) { + $$$1(this._backdrop).remove(); + this._backdrop = null; + } + }; + + _proto._showBackdrop = function _showBackdrop(callback) { + var _this8 = this; + + var animate = $$$1(this._element).hasClass(ClassName.FADE) ? ClassName.FADE : ''; + + if (this._isShown && this._config.backdrop) { + var doAnimate = Util.supportsTransitionEnd() && animate; + this._backdrop = document.createElement('div'); + this._backdrop.className = ClassName.BACKDROP; + + if (animate) { + $$$1(this._backdrop).addClass(animate); + } + + $$$1(this._backdrop).appendTo(document.body); + $$$1(this._element).on(Event.CLICK_DISMISS, function (event) { + if (_this8._ignoreBackdropClick) { + _this8._ignoreBackdropClick = false; + return; + } + + if (event.target !== event.currentTarget) { + return; + } + + if (_this8._config.backdrop === 'static') { + _this8._element.focus(); + } else { + _this8.hide(); + } + }); + + if (doAnimate) { + Util.reflow(this._backdrop); + } + + $$$1(this._backdrop).addClass(ClassName.SHOW); + + if (!callback) { + return; + } + + if (!doAnimate) { + callback(); + return; + } + + $$$1(this._backdrop).one(Util.TRANSITION_END, callback).emulateTransitionEnd(BACKDROP_TRANSITION_DURATION); + } else if (!this._isShown && this._backdrop) { + $$$1(this._backdrop).removeClass(ClassName.SHOW); + + var callbackRemove = function callbackRemove() { + _this8._removeBackdrop(); + + if (callback) { + callback(); + } + }; + + if (Util.supportsTransitionEnd() && $$$1(this._element).hasClass(ClassName.FADE)) { + $$$1(this._backdrop).one(Util.TRANSITION_END, callbackRemove).emulateTransitionEnd(BACKDROP_TRANSITION_DURATION); + } else { + callbackRemove(); + } + } else if (callback) { + callback(); + } + }; // ---------------------------------------------------------------------- + // the following methods are used to handle overflowing modals + // todo (fat): these should probably be refactored out of modal.js + // ---------------------------------------------------------------------- + + + _proto._adjustDialog = function _adjustDialog() { + var isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight; + + if (!this._isBodyOverflowing && isModalOverflowing) { + this._element.style.paddingLeft = this._scrollbarWidth + "px"; + } + + if (this._isBodyOverflowing && !isModalOverflowing) { + this._element.style.paddingRight = this._scrollbarWidth + "px"; + } + }; + + _proto._resetAdjustments = function _resetAdjustments() { + this._element.style.paddingLeft = ''; + this._element.style.paddingRight = ''; + }; + + _proto._checkScrollbar = function _checkScrollbar() { + var rect = document.body.getBoundingClientRect(); + this._isBodyOverflowing = rect.left + rect.right < window.innerWidth; + this._scrollbarWidth = this._getScrollbarWidth(); + }; + + _proto._setScrollbar = function _setScrollbar() { + var _this9 = this; + + if (this._isBodyOverflowing) { + // Note: DOMNode.style.paddingRight returns the actual value or '' if not set + // while $(DOMNode).css('padding-right') returns the calculated value or 0 if not set + // Adjust fixed content padding + $$$1(Selector.FIXED_CONTENT).each(function (index, element) { + var actualPadding = $$$1(element)[0].style.paddingRight; + var calculatedPadding = $$$1(element).css('padding-right'); + $$$1(element).data('padding-right', actualPadding).css('padding-right', parseFloat(calculatedPadding) + _this9._scrollbarWidth + "px"); + }); // Adjust sticky content margin + + $$$1(Selector.STICKY_CONTENT).each(function (index, element) { + var actualMargin = $$$1(element)[0].style.marginRight; + var calculatedMargin = $$$1(element).css('margin-right'); + $$$1(element).data('margin-right', actualMargin).css('margin-right', parseFloat(calculatedMargin) - _this9._scrollbarWidth + "px"); + }); // Adjust navbar-toggler margin + + $$$1(Selector.NAVBAR_TOGGLER).each(function (index, element) { + var actualMargin = $$$1(element)[0].style.marginRight; + var calculatedMargin = $$$1(element).css('margin-right'); + $$$1(element).data('margin-right', actualMargin).css('margin-right', parseFloat(calculatedMargin) + _this9._scrollbarWidth + "px"); + }); // Adjust body padding + + var actualPadding = document.body.style.paddingRight; + var calculatedPadding = $$$1('body').css('padding-right'); + $$$1('body').data('padding-right', actualPadding).css('padding-right', parseFloat(calculatedPadding) + this._scrollbarWidth + "px"); + } + }; + + _proto._resetScrollbar = function _resetScrollbar() { + // Restore fixed content padding + $$$1(Selector.FIXED_CONTENT).each(function (index, element) { + var padding = $$$1(element).data('padding-right'); + + if (typeof padding !== 'undefined') { + $$$1(element).css('padding-right', padding).removeData('padding-right'); + } + }); // Restore sticky content and navbar-toggler margin + + $$$1(Selector.STICKY_CONTENT + ", " + Selector.NAVBAR_TOGGLER).each(function (index, element) { + var margin = $$$1(element).data('margin-right'); + + if (typeof margin !== 'undefined') { + $$$1(element).css('margin-right', margin).removeData('margin-right'); + } + }); // Restore body padding + + var padding = $$$1('body').data('padding-right'); + + if (typeof padding !== 'undefined') { + $$$1('body').css('padding-right', padding).removeData('padding-right'); + } + }; + + _proto._getScrollbarWidth = function _getScrollbarWidth() { + // thx d.walsh + var scrollDiv = document.createElement('div'); + scrollDiv.className = ClassName.SCROLLBAR_MEASURER; + document.body.appendChild(scrollDiv); + var scrollbarWidth = scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth; + document.body.removeChild(scrollDiv); + return scrollbarWidth; + }; // Static + + + Modal._jQueryInterface = function _jQueryInterface(config, relatedTarget) { + return this.each(function () { + var data = $$$1(this).data(DATA_KEY); + + var _config = _extends({}, Modal.Default, $$$1(this).data(), typeof config === 'object' && config); + + if (!data) { + data = new Modal(this, _config); + $$$1(this).data(DATA_KEY, data); + } + + if (typeof config === 'string') { + if (typeof data[config] === 'undefined') { + throw new TypeError("No method named \"" + config + "\""); + } + + data[config](relatedTarget); + } else if (_config.show) { + data.show(relatedTarget); + } + }); + }; + + _createClass(Modal, null, [{ + key: "VERSION", + get: function get() { + return VERSION; + } + }, { + key: "Default", + get: function get() { + return Default; + } + }]); + return Modal; + }(); + /** + * ------------------------------------------------------------------------ + * Data Api implementation + * ------------------------------------------------------------------------ + */ + + + $$$1(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) { + var _this10 = this; + + var target; + var selector = Util.getSelectorFromElement(this); + + if (selector) { + target = $$$1(selector)[0]; + } + + var config = $$$1(target).data(DATA_KEY) ? 'toggle' : _extends({}, $$$1(target).data(), $$$1(this).data()); + + if (this.tagName === 'A' || this.tagName === 'AREA') { + event.preventDefault(); + } + + var $target = $$$1(target).one(Event.SHOW, function (showEvent) { + if (showEvent.isDefaultPrevented()) { + // Only register focus restorer if modal will actually get shown + return; + } + + $target.one(Event.HIDDEN, function () { + if ($$$1(_this10).is(':visible')) { + _this10.focus(); + } + }); + }); + + Modal._jQueryInterface.call($$$1(target), config, this); + }); + /** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + */ + + $$$1.fn[NAME] = Modal._jQueryInterface; + $$$1.fn[NAME].Constructor = Modal; + + $$$1.fn[NAME].noConflict = function () { + $$$1.fn[NAME] = JQUERY_NO_CONFLICT; + return Modal._jQueryInterface; + }; + + return Modal; + }($); + + /** + * -------------------------------------------------------------------------- + * Bootstrap (v4.0.0): tooltip.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * -------------------------------------------------------------------------- + */ + + var Tooltip = function ($$$1) { + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + var NAME = 'tooltip'; + var VERSION = '4.0.0'; + var DATA_KEY = 'bs.tooltip'; + var EVENT_KEY = "." + DATA_KEY; + var JQUERY_NO_CONFLICT = $$$1.fn[NAME]; + var TRANSITION_DURATION = 150; + var CLASS_PREFIX = 'bs-tooltip'; + var BSCLS_PREFIX_REGEX = new RegExp("(^|\\s)" + CLASS_PREFIX + "\\S+", 'g'); + var DefaultType = { + animation: 'boolean', + template: 'string', + title: '(string|element|function)', + trigger: 'string', + delay: '(number|object)', + html: 'boolean', + selector: '(string|boolean)', + placement: '(string|function)', + offset: '(number|string)', + container: '(string|element|boolean)', + fallbackPlacement: '(string|array)', + boundary: '(string|element)' + }; + var AttachmentMap = { + AUTO: 'auto', + TOP: 'top', + RIGHT: 'right', + BOTTOM: 'bottom', + LEFT: 'left' + }; + var Default = { + animation: true, + template: '', + trigger: 'hover focus', + title: '', + delay: 0, + html: false, + selector: false, + placement: 'top', + offset: 0, + container: false, + fallbackPlacement: 'flip', + boundary: 'scrollParent' + }; + var HoverState = { + SHOW: 'show', + OUT: 'out' + }; + var Event = { + HIDE: "hide" + EVENT_KEY, + HIDDEN: "hidden" + EVENT_KEY, + SHOW: "show" + EVENT_KEY, + SHOWN: "shown" + EVENT_KEY, + INSERTED: "inserted" + EVENT_KEY, + CLICK: "click" + EVENT_KEY, + FOCUSIN: "focusin" + EVENT_KEY, + FOCUSOUT: "focusout" + EVENT_KEY, + MOUSEENTER: "mouseenter" + EVENT_KEY, + MOUSELEAVE: "mouseleave" + EVENT_KEY + }; + var ClassName = { + FADE: 'fade', + SHOW: 'show' + }; + var Selector = { + TOOLTIP: '.tooltip', + TOOLTIP_INNER: '.tooltip-inner', + ARROW: '.arrow' + }; + var Trigger = { + HOVER: 'hover', + FOCUS: 'focus', + CLICK: 'click', + MANUAL: 'manual' + /** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + + }; + + var Tooltip = + /*#__PURE__*/ + function () { + function Tooltip(element, config) { + /** + * Check for Popper dependency + * Popper - https://popper.js.org + */ + if (typeof Popper$1 === 'undefined') { + throw new TypeError('Bootstrap tooltips require Popper.js (https://popper.js.org)'); + } // private + + + this._isEnabled = true; + this._timeout = 0; + this._hoverState = ''; + this._activeTrigger = {}; + this._popper = null; // Protected + + this.element = element; + this.config = this._getConfig(config); + this.tip = null; + + this._setListeners(); + } // Getters + + + var _proto = Tooltip.prototype; + + // Public + _proto.enable = function enable() { + this._isEnabled = true; + }; + + _proto.disable = function disable() { + this._isEnabled = false; + }; + + _proto.toggleEnabled = function toggleEnabled() { + this._isEnabled = !this._isEnabled; + }; + + _proto.toggle = function toggle(event) { + if (!this._isEnabled) { + return; + } + + if (event) { + var dataKey = this.constructor.DATA_KEY; + var context = $$$1(event.currentTarget).data(dataKey); + + if (!context) { + context = new this.constructor(event.currentTarget, this._getDelegateConfig()); + $$$1(event.currentTarget).data(dataKey, context); + } + + context._activeTrigger.click = !context._activeTrigger.click; + + if (context._isWithActiveTrigger()) { + context._enter(null, context); + } else { + context._leave(null, context); + } + } else { + if ($$$1(this.getTipElement()).hasClass(ClassName.SHOW)) { + this._leave(null, this); + + return; + } + + this._enter(null, this); + } + }; + + _proto.dispose = function dispose() { + clearTimeout(this._timeout); + $$$1.removeData(this.element, this.constructor.DATA_KEY); + $$$1(this.element).off(this.constructor.EVENT_KEY); + $$$1(this.element).closest('.modal').off('hide.bs.modal'); + + if (this.tip) { + $$$1(this.tip).remove(); + } + + this._isEnabled = null; + this._timeout = null; + this._hoverState = null; + this._activeTrigger = null; + + if (this._popper !== null) { + this._popper.destroy(); + } + + this._popper = null; + this.element = null; + this.config = null; + this.tip = null; + }; + + _proto.show = function show() { + var _this = this; + + if ($$$1(this.element).css('display') === 'none') { + throw new Error('Please use show on visible elements'); + } + + var showEvent = $$$1.Event(this.constructor.Event.SHOW); + + if (this.isWithContent() && this._isEnabled) { + $$$1(this.element).trigger(showEvent); + var isInTheDom = $$$1.contains(this.element.ownerDocument.documentElement, this.element); + + if (showEvent.isDefaultPrevented() || !isInTheDom) { + return; + } + + var tip = this.getTipElement(); + var tipId = Util.getUID(this.constructor.NAME); + tip.setAttribute('id', tipId); + this.element.setAttribute('aria-describedby', tipId); + this.setContent(); + + if (this.config.animation) { + $$$1(tip).addClass(ClassName.FADE); + } + + var placement = typeof this.config.placement === 'function' ? this.config.placement.call(this, tip, this.element) : this.config.placement; + + var attachment = this._getAttachment(placement); + + this.addAttachmentClass(attachment); + var container = this.config.container === false ? document.body : $$$1(this.config.container); + $$$1(tip).data(this.constructor.DATA_KEY, this); + + if (!$$$1.contains(this.element.ownerDocument.documentElement, this.tip)) { + $$$1(tip).appendTo(container); + } + + $$$1(this.element).trigger(this.constructor.Event.INSERTED); + this._popper = new Popper$1(this.element, tip, { + placement: attachment, + modifiers: { + offset: { + offset: this.config.offset + }, + flip: { + behavior: this.config.fallbackPlacement + }, + arrow: { + element: Selector.ARROW + }, + preventOverflow: { + boundariesElement: this.config.boundary + } + }, + onCreate: function onCreate(data) { + if (data.originalPlacement !== data.placement) { + _this._handlePopperPlacementChange(data); + } + }, + onUpdate: function onUpdate(data) { + _this._handlePopperPlacementChange(data); + } + }); + $$$1(tip).addClass(ClassName.SHOW); // If this is a touch-enabled device we add extra + // empty mouseover listeners to the body's immediate children; + // only needed because of broken event delegation on iOS + // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html + + if ('ontouchstart' in document.documentElement) { + $$$1('body').children().on('mouseover', null, $$$1.noop); + } + + var complete = function complete() { + if (_this.config.animation) { + _this._fixTransition(); + } + + var prevHoverState = _this._hoverState; + _this._hoverState = null; + $$$1(_this.element).trigger(_this.constructor.Event.SHOWN); + + if (prevHoverState === HoverState.OUT) { + _this._leave(null, _this); + } + }; + + if (Util.supportsTransitionEnd() && $$$1(this.tip).hasClass(ClassName.FADE)) { + $$$1(this.tip).one(Util.TRANSITION_END, complete).emulateTransitionEnd(Tooltip._TRANSITION_DURATION); + } else { + complete(); + } + } + }; + + _proto.hide = function hide(callback) { + var _this2 = this; + + var tip = this.getTipElement(); + var hideEvent = $$$1.Event(this.constructor.Event.HIDE); + + var complete = function complete() { + if (_this2._hoverState !== HoverState.SHOW && tip.parentNode) { + tip.parentNode.removeChild(tip); + } + + _this2._cleanTipClass(); + + _this2.element.removeAttribute('aria-describedby'); + + $$$1(_this2.element).trigger(_this2.constructor.Event.HIDDEN); + + if (_this2._popper !== null) { + _this2._popper.destroy(); + } + + if (callback) { + callback(); + } + }; + + $$$1(this.element).trigger(hideEvent); + + if (hideEvent.isDefaultPrevented()) { + return; + } + + $$$1(tip).removeClass(ClassName.SHOW); // If this is a touch-enabled device we remove the extra + // empty mouseover listeners we added for iOS support + + if ('ontouchstart' in document.documentElement) { + $$$1('body').children().off('mouseover', null, $$$1.noop); + } + + this._activeTrigger[Trigger.CLICK] = false; + this._activeTrigger[Trigger.FOCUS] = false; + this._activeTrigger[Trigger.HOVER] = false; + + if (Util.supportsTransitionEnd() && $$$1(this.tip).hasClass(ClassName.FADE)) { + $$$1(tip).one(Util.TRANSITION_END, complete).emulateTransitionEnd(TRANSITION_DURATION); + } else { + complete(); + } + + this._hoverState = ''; + }; + + _proto.update = function update() { + if (this._popper !== null) { + this._popper.scheduleUpdate(); + } + }; // Protected + + + _proto.isWithContent = function isWithContent() { + return Boolean(this.getTitle()); + }; + + _proto.addAttachmentClass = function addAttachmentClass(attachment) { + $$$1(this.getTipElement()).addClass(CLASS_PREFIX + "-" + attachment); + }; + + _proto.getTipElement = function getTipElement() { + this.tip = this.tip || $$$1(this.config.template)[0]; + return this.tip; + }; + + _proto.setContent = function setContent() { + var $tip = $$$1(this.getTipElement()); + this.setElementContent($tip.find(Selector.TOOLTIP_INNER), this.getTitle()); + $tip.removeClass(ClassName.FADE + " " + ClassName.SHOW); + }; + + _proto.setElementContent = function setElementContent($element, content) { + var html = this.config.html; + + if (typeof content === 'object' && (content.nodeType || content.jquery)) { + // Content is a DOM node or a jQuery + if (html) { + if (!$$$1(content).parent().is($element)) { + $element.empty().append(content); + } + } else { + $element.text($$$1(content).text()); + } + } else { + $element[html ? 'html' : 'text'](content); + } + }; + + _proto.getTitle = function getTitle() { + var title = this.element.getAttribute('data-original-title'); + + if (!title) { + title = typeof this.config.title === 'function' ? this.config.title.call(this.element) : this.config.title; + } + + return title; + }; // Private + + + _proto._getAttachment = function _getAttachment(placement) { + return AttachmentMap[placement.toUpperCase()]; + }; + + _proto._setListeners = function _setListeners() { + var _this3 = this; + + var triggers = this.config.trigger.split(' '); + triggers.forEach(function (trigger) { + if (trigger === 'click') { + $$$1(_this3.element).on(_this3.constructor.Event.CLICK, _this3.config.selector, function (event) { + return _this3.toggle(event); + }); + } else if (trigger !== Trigger.MANUAL) { + var eventIn = trigger === Trigger.HOVER ? _this3.constructor.Event.MOUSEENTER : _this3.constructor.Event.FOCUSIN; + var eventOut = trigger === Trigger.HOVER ? _this3.constructor.Event.MOUSELEAVE : _this3.constructor.Event.FOCUSOUT; + $$$1(_this3.element).on(eventIn, _this3.config.selector, function (event) { + return _this3._enter(event); + }).on(eventOut, _this3.config.selector, function (event) { + return _this3._leave(event); + }); + } + + $$$1(_this3.element).closest('.modal').on('hide.bs.modal', function () { + return _this3.hide(); + }); + }); + + if (this.config.selector) { + this.config = _extends({}, this.config, { + trigger: 'manual', + selector: '' + }); + } else { + this._fixTitle(); + } + }; + + _proto._fixTitle = function _fixTitle() { + var titleType = typeof this.element.getAttribute('data-original-title'); + + if (this.element.getAttribute('title') || titleType !== 'string') { + this.element.setAttribute('data-original-title', this.element.getAttribute('title') || ''); + this.element.setAttribute('title', ''); + } + }; + + _proto._enter = function _enter(event, context) { + var dataKey = this.constructor.DATA_KEY; + context = context || $$$1(event.currentTarget).data(dataKey); + + if (!context) { + context = new this.constructor(event.currentTarget, this._getDelegateConfig()); + $$$1(event.currentTarget).data(dataKey, context); + } + + if (event) { + context._activeTrigger[event.type === 'focusin' ? Trigger.FOCUS : Trigger.HOVER] = true; + } + + if ($$$1(context.getTipElement()).hasClass(ClassName.SHOW) || context._hoverState === HoverState.SHOW) { + context._hoverState = HoverState.SHOW; + return; + } + + clearTimeout(context._timeout); + context._hoverState = HoverState.SHOW; + + if (!context.config.delay || !context.config.delay.show) { + context.show(); + return; + } + + context._timeout = setTimeout(function () { + if (context._hoverState === HoverState.SHOW) { + context.show(); + } + }, context.config.delay.show); + }; + + _proto._leave = function _leave(event, context) { + var dataKey = this.constructor.DATA_KEY; + context = context || $$$1(event.currentTarget).data(dataKey); + + if (!context) { + context = new this.constructor(event.currentTarget, this._getDelegateConfig()); + $$$1(event.currentTarget).data(dataKey, context); + } + + if (event) { + context._activeTrigger[event.type === 'focusout' ? Trigger.FOCUS : Trigger.HOVER] = false; + } + + if (context._isWithActiveTrigger()) { + return; + } + + clearTimeout(context._timeout); + context._hoverState = HoverState.OUT; + + if (!context.config.delay || !context.config.delay.hide) { + context.hide(); + return; + } + + context._timeout = setTimeout(function () { + if (context._hoverState === HoverState.OUT) { + context.hide(); + } + }, context.config.delay.hide); + }; + + _proto._isWithActiveTrigger = function _isWithActiveTrigger() { + for (var trigger in this._activeTrigger) { + if (this._activeTrigger[trigger]) { + return true; + } + } + + return false; + }; + + _proto._getConfig = function _getConfig(config) { + config = _extends({}, this.constructor.Default, $$$1(this.element).data(), config); + + if (typeof config.delay === 'number') { + config.delay = { + show: config.delay, + hide: config.delay + }; + } + + if (typeof config.title === 'number') { + config.title = config.title.toString(); + } + + if (typeof config.content === 'number') { + config.content = config.content.toString(); + } + + Util.typeCheckConfig(NAME, config, this.constructor.DefaultType); + return config; + }; + + _proto._getDelegateConfig = function _getDelegateConfig() { + var config = {}; + + if (this.config) { + for (var key in this.config) { + if (this.constructor.Default[key] !== this.config[key]) { + config[key] = this.config[key]; + } + } + } + + return config; + }; + + _proto._cleanTipClass = function _cleanTipClass() { + var $tip = $$$1(this.getTipElement()); + var tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX); + + if (tabClass !== null && tabClass.length > 0) { + $tip.removeClass(tabClass.join('')); + } + }; + + _proto._handlePopperPlacementChange = function _handlePopperPlacementChange(data) { + this._cleanTipClass(); + + this.addAttachmentClass(this._getAttachment(data.placement)); + }; + + _proto._fixTransition = function _fixTransition() { + var tip = this.getTipElement(); + var initConfigAnimation = this.config.animation; + + if (tip.getAttribute('x-placement') !== null) { + return; + } + + $$$1(tip).removeClass(ClassName.FADE); + this.config.animation = false; + this.hide(); + this.show(); + this.config.animation = initConfigAnimation; + }; // Static + + + Tooltip._jQueryInterface = function _jQueryInterface(config) { + return this.each(function () { + var data = $$$1(this).data(DATA_KEY); + + var _config = typeof config === 'object' && config; + + if (!data && /dispose|hide/.test(config)) { + return; + } + + if (!data) { + data = new Tooltip(this, _config); + $$$1(this).data(DATA_KEY, data); + } + + if (typeof config === 'string') { + if (typeof data[config] === 'undefined') { + throw new TypeError("No method named \"" + config + "\""); + } + + data[config](); + } + }); + }; + + _createClass(Tooltip, null, [{ + key: "VERSION", + get: function get() { + return VERSION; + } + }, { + key: "Default", + get: function get() { + return Default; + } + }, { + key: "NAME", + get: function get() { + return NAME; + } + }, { + key: "DATA_KEY", + get: function get() { + return DATA_KEY; + } + }, { + key: "Event", + get: function get() { + return Event; + } + }, { + key: "EVENT_KEY", + get: function get() { + return EVENT_KEY; + } + }, { + key: "DefaultType", + get: function get() { + return DefaultType; + } + }]); + return Tooltip; + }(); + /** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + */ + + + $$$1.fn[NAME] = Tooltip._jQueryInterface; + $$$1.fn[NAME].Constructor = Tooltip; + + $$$1.fn[NAME].noConflict = function () { + $$$1.fn[NAME] = JQUERY_NO_CONFLICT; + return Tooltip._jQueryInterface; + }; + + return Tooltip; + }($, Popper$1); + + /** + * -------------------------------------------------------------------------- + * Bootstrap (v4.0.0): popover.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * -------------------------------------------------------------------------- + */ + + var Popover = function ($$$1) { + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + var NAME = 'popover'; + var VERSION = '4.0.0'; + var DATA_KEY = 'bs.popover'; + var EVENT_KEY = "." + DATA_KEY; + var JQUERY_NO_CONFLICT = $$$1.fn[NAME]; + var CLASS_PREFIX = 'bs-popover'; + var BSCLS_PREFIX_REGEX = new RegExp("(^|\\s)" + CLASS_PREFIX + "\\S+", 'g'); + var Default = _extends({}, Tooltip.Default, { + placement: 'right', + trigger: 'click', + content: '', + template: '' + }); + var DefaultType = _extends({}, Tooltip.DefaultType, { + content: '(string|element|function)' + }); + var ClassName = { + FADE: 'fade', + SHOW: 'show' + }; + var Selector = { + TITLE: '.popover-header', + CONTENT: '.popover-body' + }; + var Event = { + HIDE: "hide" + EVENT_KEY, + HIDDEN: "hidden" + EVENT_KEY, + SHOW: "show" + EVENT_KEY, + SHOWN: "shown" + EVENT_KEY, + INSERTED: "inserted" + EVENT_KEY, + CLICK: "click" + EVENT_KEY, + FOCUSIN: "focusin" + EVENT_KEY, + FOCUSOUT: "focusout" + EVENT_KEY, + MOUSEENTER: "mouseenter" + EVENT_KEY, + MOUSELEAVE: "mouseleave" + EVENT_KEY + /** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + + }; + + var Popover = + /*#__PURE__*/ + function (_Tooltip) { + _inheritsLoose(Popover, _Tooltip); + + function Popover() { + return _Tooltip.apply(this, arguments) || this; + } + + var _proto = Popover.prototype; + + // Overrides + _proto.isWithContent = function isWithContent() { + return this.getTitle() || this._getContent(); + }; + + _proto.addAttachmentClass = function addAttachmentClass(attachment) { + $$$1(this.getTipElement()).addClass(CLASS_PREFIX + "-" + attachment); + }; + + _proto.getTipElement = function getTipElement() { + this.tip = this.tip || $$$1(this.config.template)[0]; + return this.tip; + }; + + _proto.setContent = function setContent() { + var $tip = $$$1(this.getTipElement()); // We use append for html objects to maintain js events + + this.setElementContent($tip.find(Selector.TITLE), this.getTitle()); + + var content = this._getContent(); + + if (typeof content === 'function') { + content = content.call(this.element); + } + + this.setElementContent($tip.find(Selector.CONTENT), content); + $tip.removeClass(ClassName.FADE + " " + ClassName.SHOW); + }; // Private + + + _proto._getContent = function _getContent() { + return this.element.getAttribute('data-content') || this.config.content; + }; + + _proto._cleanTipClass = function _cleanTipClass() { + var $tip = $$$1(this.getTipElement()); + var tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX); + + if (tabClass !== null && tabClass.length > 0) { + $tip.removeClass(tabClass.join('')); + } + }; // Static + + + Popover._jQueryInterface = function _jQueryInterface(config) { + return this.each(function () { + var data = $$$1(this).data(DATA_KEY); + + var _config = typeof config === 'object' ? config : null; + + if (!data && /destroy|hide/.test(config)) { + return; + } + + if (!data) { + data = new Popover(this, _config); + $$$1(this).data(DATA_KEY, data); + } + + if (typeof config === 'string') { + if (typeof data[config] === 'undefined') { + throw new TypeError("No method named \"" + config + "\""); + } + + data[config](); + } + }); + }; + + _createClass(Popover, null, [{ + key: "VERSION", + // Getters + get: function get() { + return VERSION; + } + }, { + key: "Default", + get: function get() { + return Default; + } + }, { + key: "NAME", + get: function get() { + return NAME; + } + }, { + key: "DATA_KEY", + get: function get() { + return DATA_KEY; + } + }, { + key: "Event", + get: function get() { + return Event; + } + }, { + key: "EVENT_KEY", + get: function get() { + return EVENT_KEY; + } + }, { + key: "DefaultType", + get: function get() { + return DefaultType; + } + }]); + return Popover; + }(Tooltip); + /** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + */ + + + $$$1.fn[NAME] = Popover._jQueryInterface; + $$$1.fn[NAME].Constructor = Popover; + + $$$1.fn[NAME].noConflict = function () { + $$$1.fn[NAME] = JQUERY_NO_CONFLICT; + return Popover._jQueryInterface; + }; + + return Popover; + }($); + + /** + * -------------------------------------------------------------------------- + * Bootstrap (v4.0.0): scrollspy.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * -------------------------------------------------------------------------- + */ + + var ScrollSpy = function ($$$1) { + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + var NAME = 'scrollspy'; + var VERSION = '4.0.0'; + var DATA_KEY = 'bs.scrollspy'; + var EVENT_KEY = "." + DATA_KEY; + var DATA_API_KEY = '.data-api'; + var JQUERY_NO_CONFLICT = $$$1.fn[NAME]; + var Default = { + offset: 10, + method: 'auto', + target: '' + }; + var DefaultType = { + offset: 'number', + method: 'string', + target: '(string|element)' + }; + var Event = { + ACTIVATE: "activate" + EVENT_KEY, + SCROLL: "scroll" + EVENT_KEY, + LOAD_DATA_API: "load" + EVENT_KEY + DATA_API_KEY + }; + var ClassName = { + DROPDOWN_ITEM: 'dropdown-item', + DROPDOWN_MENU: 'dropdown-menu', + ACTIVE: 'active' + }; + var Selector = { + DATA_SPY: '[data-spy="scroll"]', + ACTIVE: '.active', + NAV_LIST_GROUP: '.nav, .list-group', + NAV_LINKS: '.nav-link', + NAV_ITEMS: '.nav-item', + LIST_ITEMS: '.list-group-item', + DROPDOWN: '.dropdown', + DROPDOWN_ITEMS: '.dropdown-item', + DROPDOWN_TOGGLE: '.dropdown-toggle' + }; + var OffsetMethod = { + OFFSET: 'offset', + POSITION: 'position' + /** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + + }; + + var ScrollSpy = + /*#__PURE__*/ + function () { + function ScrollSpy(element, config) { + var _this = this; + + this._element = element; + this._scrollElement = element.tagName === 'BODY' ? window : element; + this._config = this._getConfig(config); + this._selector = this._config.target + " " + Selector.NAV_LINKS + "," + (this._config.target + " " + Selector.LIST_ITEMS + ",") + (this._config.target + " " + Selector.DROPDOWN_ITEMS); + this._offsets = []; + this._targets = []; + this._activeTarget = null; + this._scrollHeight = 0; + $$$1(this._scrollElement).on(Event.SCROLL, function (event) { + return _this._process(event); + }); + this.refresh(); + + this._process(); + } // Getters + + + var _proto = ScrollSpy.prototype; + + // Public + _proto.refresh = function refresh() { + var _this2 = this; + + var autoMethod = this._scrollElement === this._scrollElement.window ? OffsetMethod.OFFSET : OffsetMethod.POSITION; + var offsetMethod = this._config.method === 'auto' ? autoMethod : this._config.method; + var offsetBase = offsetMethod === OffsetMethod.POSITION ? this._getScrollTop() : 0; + this._offsets = []; + this._targets = []; + this._scrollHeight = this._getScrollHeight(); + var targets = $$$1.makeArray($$$1(this._selector)); + targets.map(function (element) { + var target; + var targetSelector = Util.getSelectorFromElement(element); + + if (targetSelector) { + target = $$$1(targetSelector)[0]; + } + + if (target) { + var targetBCR = target.getBoundingClientRect(); + + if (targetBCR.width || targetBCR.height) { + // TODO (fat): remove sketch reliance on jQuery position/offset + return [$$$1(target)[offsetMethod]().top + offsetBase, targetSelector]; + } + } + + return null; + }).filter(function (item) { + return item; + }).sort(function (a, b) { + return a[0] - b[0]; + }).forEach(function (item) { + _this2._offsets.push(item[0]); + + _this2._targets.push(item[1]); + }); + }; + + _proto.dispose = function dispose() { + $$$1.removeData(this._element, DATA_KEY); + $$$1(this._scrollElement).off(EVENT_KEY); + this._element = null; + this._scrollElement = null; + this._config = null; + this._selector = null; + this._offsets = null; + this._targets = null; + this._activeTarget = null; + this._scrollHeight = null; + }; // Private + + + _proto._getConfig = function _getConfig(config) { + config = _extends({}, Default, config); + + if (typeof config.target !== 'string') { + var id = $$$1(config.target).attr('id'); + + if (!id) { + id = Util.getUID(NAME); + $$$1(config.target).attr('id', id); + } + + config.target = "#" + id; + } + + Util.typeCheckConfig(NAME, config, DefaultType); + return config; + }; + + _proto._getScrollTop = function _getScrollTop() { + return this._scrollElement === window ? this._scrollElement.pageYOffset : this._scrollElement.scrollTop; + }; + + _proto._getScrollHeight = function _getScrollHeight() { + return this._scrollElement.scrollHeight || Math.max(document.body.scrollHeight, document.documentElement.scrollHeight); + }; + + _proto._getOffsetHeight = function _getOffsetHeight() { + return this._scrollElement === window ? window.innerHeight : this._scrollElement.getBoundingClientRect().height; + }; + + _proto._process = function _process() { + var scrollTop = this._getScrollTop() + this._config.offset; + + var scrollHeight = this._getScrollHeight(); + + var maxScroll = this._config.offset + scrollHeight - this._getOffsetHeight(); + + if (this._scrollHeight !== scrollHeight) { + this.refresh(); + } + + if (scrollTop >= maxScroll) { + var target = this._targets[this._targets.length - 1]; + + if (this._activeTarget !== target) { + this._activate(target); + } + + return; + } + + if (this._activeTarget && scrollTop < this._offsets[0] && this._offsets[0] > 0) { + this._activeTarget = null; + + this._clear(); + + return; + } + + for (var i = this._offsets.length; i--;) { + var isActiveTarget = this._activeTarget !== this._targets[i] && scrollTop >= this._offsets[i] && (typeof this._offsets[i + 1] === 'undefined' || scrollTop < this._offsets[i + 1]); + + if (isActiveTarget) { + this._activate(this._targets[i]); + } + } + }; + + _proto._activate = function _activate(target) { + this._activeTarget = target; + + this._clear(); + + var queries = this._selector.split(','); // eslint-disable-next-line arrow-body-style + + + queries = queries.map(function (selector) { + return selector + "[data-target=\"" + target + "\"]," + (selector + "[href=\"" + target + "\"]"); + }); + var $link = $$$1(queries.join(',')); + + if ($link.hasClass(ClassName.DROPDOWN_ITEM)) { + $link.closest(Selector.DROPDOWN).find(Selector.DROPDOWN_TOGGLE).addClass(ClassName.ACTIVE); + $link.addClass(ClassName.ACTIVE); + } else { + // Set triggered link as active + $link.addClass(ClassName.ACTIVE); // Set triggered links parents as active + // With both
      and