Merged with develop and fixed build
commit
d75e1ca492
17
ChangeLog.md
17
ChangeLog.md
|
@ -1,4 +1,21 @@
|
|||
# Changelog:
|
||||
* **23.12.18**
|
||||
- Added query account management (since server 1.2.32b)
|
||||
|
||||
* **18.12.18**
|
||||
- Added bookmarks and bookmarks management
|
||||
- Added query user visibility button and creation (Query management will follow soon)
|
||||
- Fixed overflow within the group assignment dialog
|
||||
|
||||
* **17.12.18**
|
||||
- Implemented group prefix and suffix
|
||||
|
||||
* **15.12.18**
|
||||
- Implemented a translation system with default translated language sets for
|
||||
- German
|
||||
- Turkish
|
||||
- Russian
|
||||
|
||||
* **3.12.18**
|
||||
- Fixed url connect parameters
|
||||
|
||||
|
|
|
@ -103,9 +103,7 @@ $background:lightgray;
|
|||
background-color: $background;
|
||||
border-radius: 5px;
|
||||
align-items: center;
|
||||
border: 2px solid rgba(0, 0, 0, 0);
|
||||
|
||||
border-color: $border_color_activated;
|
||||
border: 2px solid $border_color_activated;
|
||||
width: 230px;
|
||||
|
||||
user-select: none;
|
||||
|
@ -134,6 +132,10 @@ $background:lightgray;
|
|||
& > div:last-of-type {
|
||||
border-radius: 0 0 2px 2px;
|
||||
}
|
||||
|
||||
&.display_left {
|
||||
margin-left: -165px;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
|
@ -142,4 +144,10 @@ $background:lightgray;
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bookmark-dropdown {
|
||||
hr:last-child {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,173 @@
|
|||
.query-create {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.row-name {
|
||||
width: 100%;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: stretch;
|
||||
|
||||
input {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.buttons {
|
||||
margin-top: 5px;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
.query-created {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.property-row {
|
||||
width: 100%;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: stretch;
|
||||
align-items: center;
|
||||
|
||||
margin-top: 2px;
|
||||
|
||||
input {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
a:first-of-type {
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
div:last-of-type {
|
||||
margin-left: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.buttons {
|
||||
margin-top: 5px;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
.query-management {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: stretch;
|
||||
|
||||
.header, .footer {
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: stretch;
|
||||
|
||||
.buttons {
|
||||
flex-grow: 0;
|
||||
}
|
||||
|
||||
.search {
|
||||
margin-left: 5px;
|
||||
flex-grow: 1;
|
||||
|
||||
input {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.query-list {
|
||||
margin-top: 5px;
|
||||
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
flex-direction: column;
|
||||
justify-content: stretch;
|
||||
|
||||
.column {
|
||||
&.column-username {
|
||||
width: calc(50% - 75px)
|
||||
}
|
||||
|
||||
&.column-unique-id {
|
||||
width: calc(50% - 75px)
|
||||
}
|
||||
|
||||
&.column-bound-server {
|
||||
width: 150px;
|
||||
flex-grow: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.query-list-header {
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
height: 20px;
|
||||
|
||||
.column {
|
||||
border: 1px solid lightgray;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.query-list-entries-container {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: start;
|
||||
overflow-y: auto;
|
||||
min-height: 250px;
|
||||
|
||||
.entry {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
.column {
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
&.selected {
|
||||
background-color: blue;
|
||||
}
|
||||
}
|
||||
|
||||
&.scrollbar {
|
||||
.column-username {
|
||||
width: calc(50% - 75px + 30px)
|
||||
}
|
||||
|
||||
.column-unique-id {
|
||||
width: calc(50% - 75px + 30px)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
margin-top: 5px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -520,6 +520,7 @@
|
|||
.group-list {
|
||||
border: lightgray solid 1px;
|
||||
padding: 3px;
|
||||
overflow-y: auto;
|
||||
|
||||
.group-entry {
|
||||
display: flex;
|
||||
|
|
|
@ -53,11 +53,21 @@
|
|||
.channelTree div * {vertical-align: middle;display:inline-block;height: 16px;padding: 0px;}
|
||||
.channelTree div img {border: 0;}
|
||||
.channelTree div > span {position: absolute; right: 0;}
|
||||
.channelTree .name {
|
||||
vertical-align: middle;
|
||||
margin-top: 1px;
|
||||
height: 14px;
|
||||
display: inline;
|
||||
.channelTree {
|
||||
.name, .group_prefix, .group_suffix, .away {
|
||||
vertical-align: middle;
|
||||
margin-top: 1px;
|
||||
height: 14px;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.group_prefix {
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
.group_suffix {
|
||||
margin-left: 3px;
|
||||
}
|
||||
}
|
||||
.channelTree .own_name {
|
||||
font-weight: bold;
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
<link rel="stylesheet" href="css/ts/icons.css" type="text/css">
|
||||
<link rel="stylesheet" href="css/general.css" type="text/css">
|
||||
<link rel="stylesheet" href="css/modals.css" type="text/css">
|
||||
<link rel="stylesheet" href="css/modal-query.css" type="text/css">
|
||||
<link rel="stylesheet" href="css/modal-banlist.css" type="text/css">
|
||||
<link rel="stylesheet" href="css/modal-bancreate.css" type="text/css">
|
||||
<link rel="stylesheet" href="css/modal-settings.css" type="text/css">
|
||||
|
|
|
@ -19,7 +19,24 @@
|
|||
<div class="button btn_disconnect" title="{{tr 'Disconnect from server' /}}" style="display: none">
|
||||
<div class="icon_x32 client-disconnect"></div>
|
||||
</div>
|
||||
<!--<div class="button btn_disconnect"><div class="icon_x32 client-disconnect"></div></div>-->
|
||||
|
||||
<!--
|
||||
<div class="button-dropdown btn_bookmark" title="{{tr 'Bookmarks' /}}">
|
||||
<div class="buttons">
|
||||
<div class="button icon_x32 client-bookmark_manager btn_bookmark_list"></div>
|
||||
<div class="button-dropdown">
|
||||
<div class="arrow"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dropdown bookmark-dropdown" style="width: 300px">
|
||||
<div class="btn_bookmark_list"><div class="icon client-bookmark_manager"></div><a>{{tr "Manage bookmarks" /}}</a></div>
|
||||
<div class="btn_bookmark_add"><div class="icon client-bookmark_add"></div><a>{{tr "Add current server to bookmarks" /}}</a></div>
|
||||
<div class="btn_bookmark_remove"><div class="icon client-bookmark_remove"></div><a>{{tr "Remove current server to bookmarks" /}}</a></div>
|
||||
<hr>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
-->
|
||||
<div class="divider"></div>
|
||||
|
||||
<div class="button-dropdown btn_away" title="{{tr 'Toggle away status' /}}">
|
||||
|
@ -62,6 +79,21 @@
|
|||
<div class="button btn_permissions" title="{{tr 'View/edit permissions' /}}">
|
||||
<div class="icon_x32 client-permission_overview"></div>
|
||||
</div>
|
||||
|
||||
<!-- the query button -->
|
||||
<div class="button-dropdown btn_query" title="{{tr 'Show/hide server queries' /}}">
|
||||
<div class="buttons">
|
||||
<div class="button icon_x32 client-server_query btn_query_toggle"></div>
|
||||
<div class="button-dropdown">
|
||||
<div class="arrow"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dropdown display_left">
|
||||
<div class="btn_query_toggle"><div class="icon client-toggle_server_query_clients"></div><a>{{tr "Show/hide server queries" /}}</a></div>
|
||||
<div class="btn_query_manage"><div class="icon client-server_query"></div><a>{{tr "Manage server queries" /}}</a></div>
|
||||
<!-- <div class="btn_query_create"><div class="icon client-away"></div><a>{{tr "Create server query login" /}}</a></div> -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="divider"></div>
|
||||
<div class="button btn_open_settings" title="{{tr 'Edit global client settings' /}}">
|
||||
<div class="icon_x32 client-settings"></div>
|
||||
|
@ -1074,7 +1106,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
9
|
||||
<script class="jsrender-template" id="tmpl_client_ban" type="text/html">
|
||||
<div class="align_column">
|
||||
<div class="align_column" style="margin: 5px">
|
||||
|
@ -1656,5 +1688,84 @@
|
|||
<button class="button-close">{{tr "Close" /}}</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script class="jsrender-template" id="tmpl_query_create" type="text/html">
|
||||
<div class="query-create">
|
||||
<a>{{tr "Set the login name for your Server Query account." /}}</a>
|
||||
<a>{{tr "You'll receive your password within the next step." /}}</a>
|
||||
<div class="row-name">
|
||||
<a>Name:</a>
|
||||
<input type="text" maxlength="64" minlength="3" class="input-name">
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<button class="button-close">{{tr "Close" /}}</button>
|
||||
<button class="button-create">{{tr "Create" /}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script class="jsrender-template" id="tmpl_query_created" type="text/html">
|
||||
<div class="query-created">
|
||||
<a>{{tr "Your server query credentials:" /}}</a>
|
||||
<div class="property-row">
|
||||
<a>Name:</a>
|
||||
<input class="query_name" type="text" maxlength="64" minlength="3" value="{{>username}}">
|
||||
<div class="btn_copy_name icon client-copy" title="{{tr 'Copy username' /}}"></div>
|
||||
</div>
|
||||
<div class="property-row">
|
||||
<a>Password:</a>
|
||||
<input class="query_password" type="text" value="{{>password}}">
|
||||
<div class="btn_copy_password icon client-copy" title="{{tr 'Copy password' /}}"></div>
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<button class="button-close">{{tr "Close" /}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script class="jsrender-template" id="tmpl_query_manager" type="text/html">
|
||||
<div class="query-management">
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<div class="buttons">
|
||||
<button class="button button-query-create">{{tr "Create account" /}}</button>
|
||||
<button class="button button-query-delete">{{tr "Delete account" /}}</button>
|
||||
<button class="button button-query-rename">{{tr "Rename account" /}}</button>
|
||||
<button class="button button-query-change-password">{{tr "Change password" /}}</button>
|
||||
</div>
|
||||
<div class="search">
|
||||
<input class="input input-search" type="text" placeholder="search">
|
||||
</div>
|
||||
</div>
|
||||
<div class="query-list">
|
||||
<div class="query-list-header">
|
||||
<div class="column column-username">{{tr "Username" /}}</div>
|
||||
<div class="column column-unique-id">{{tr "Unique ID" /}}</div>
|
||||
<div class="column column-bound-server">{{tr "Bounded Server" /}}</div>
|
||||
</div>
|
||||
<div class="query-list-entries-container">
|
||||
<div class="query-list-entries">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<div class="info">
|
||||
<a>loading...</a>
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<button class="button-refresh">{{tr "Refresh" /}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
|
||||
<script class="jsrender-template" id="tmpl_query_manager-list_entry" type="text/html">
|
||||
<div class="entry">
|
||||
<div class="column column-username">{{>username}}</div>
|
||||
<div class="column column-unique-id">{{>unique_id}}</div>
|
||||
<div class="column column-bound-server">{{>bounded_server}}</div>
|
||||
</div>
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because it is too large
Load Diff
|
@ -11,6 +11,10 @@
|
|||
{
|
||||
"key": "tr_gt",
|
||||
"path": "tr_google_translate.translation"
|
||||
},
|
||||
{
|
||||
"key": "fr_gt",
|
||||
"path": "fr_google_translate.translation"
|
||||
}
|
||||
],
|
||||
"name": "Default TeaSpeak repository",
|
||||
|
|
|
@ -0,0 +1,156 @@
|
|||
namespace bookmarks {
|
||||
function guid() {
|
||||
function s4() {
|
||||
return Math.floor((1 + Math.random()) * 0x10000)
|
||||
.toString(16)
|
||||
.substring(1);
|
||||
}
|
||||
return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
|
||||
}
|
||||
|
||||
export interface ConnectIdentity {
|
||||
identity_type: IdentitifyType;
|
||||
}
|
||||
|
||||
export interface ForumConnectIdentity extends ConnectIdentity { }
|
||||
export interface NicknameConnectIdentity extends ConnectIdentity { }
|
||||
export interface TeamSpeakConnectIdentity extends ConnectIdentity { }
|
||||
|
||||
export interface ServerProperties {
|
||||
server_address: string;
|
||||
server_port: number;
|
||||
server_password_hash?: string;
|
||||
server_password?: string;
|
||||
}
|
||||
|
||||
export enum BookmarkType {
|
||||
ENTRY,
|
||||
DIRECTORY
|
||||
}
|
||||
|
||||
export interface Bookmark {
|
||||
type: /* BookmarkType.ENTRY */ BookmarkType;
|
||||
|
||||
/* readonly directory: DirectoryBookmark; */
|
||||
server_properties: ServerProperties;
|
||||
display_name: string;
|
||||
unique_id: string;
|
||||
|
||||
nickname: string;
|
||||
default_channel?: number | string;
|
||||
default_channel_password_hash?: string;
|
||||
default_channel_password?: string;
|
||||
|
||||
}
|
||||
|
||||
export interface DirectoryBookmark {
|
||||
type: /* BookmarkType.DIRECTORY */ BookmarkType;
|
||||
|
||||
readonly content: (Bookmark | DirectoryBookmark)[];
|
||||
unique_id: string;
|
||||
display_name: string;
|
||||
}
|
||||
|
||||
interface BookmarkConfig {
|
||||
root_bookmark?: DirectoryBookmark;
|
||||
default_added?: boolean;
|
||||
}
|
||||
|
||||
let _bookmark_config: BookmarkConfig;
|
||||
|
||||
function bookmark_config() : BookmarkConfig {
|
||||
if(_bookmark_config)
|
||||
return _bookmark_config;
|
||||
|
||||
let bookmark_json = localStorage.getItem("bookmarks");
|
||||
let bookmarks = JSON.parse(bookmark_json) || {} as BookmarkConfig;
|
||||
|
||||
_bookmark_config = bookmarks;
|
||||
_bookmark_config.root_bookmark = _bookmark_config.root_bookmark || { content: [], display_name: "root", type: BookmarkType.DIRECTORY} as DirectoryBookmark;
|
||||
|
||||
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()));
|
||||
}
|
||||
|
||||
export function bookmarks() : DirectoryBookmark {
|
||||
return bookmark_config().root_bookmark;
|
||||
}
|
||||
|
||||
function find_bookmark_recursive(parent: DirectoryBookmark, uuid: string) : Bookmark | DirectoryBookmark {
|
||||
for(const entry of parent.content) {
|
||||
if(entry.unique_id == uuid)
|
||||
return entry;
|
||||
if(entry.type == BookmarkType.DIRECTORY) {
|
||||
const result = find_bookmark_recursive(entry as DirectoryBookmark, uuid);
|
||||
if(result) return result;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function find_bookmark(uuid: string) : Bookmark | DirectoryBookmark | undefined {
|
||||
return find_bookmark_recursive(bookmarks(), uuid);
|
||||
}
|
||||
|
||||
export function create_bookmark(display_name: string, directory: DirectoryBookmark, server_properties: ServerProperties, nickname: string) : Bookmark {
|
||||
const bookmark = {
|
||||
display_name: display_name,
|
||||
server_properties: server_properties,
|
||||
nickname: nickname,
|
||||
type: BookmarkType.ENTRY,
|
||||
unique_id: guid()
|
||||
} as Bookmark;
|
||||
|
||||
directory.content.push(bookmark);
|
||||
return bookmark;
|
||||
}
|
||||
|
||||
export function create_bookmark_directory(parent: DirectoryBookmark, name: string) : DirectoryBookmark {
|
||||
const bookmark = {
|
||||
type: BookmarkType.DIRECTORY,
|
||||
|
||||
display_name: name,
|
||||
content: [],
|
||||
unique_id: guid()
|
||||
} as DirectoryBookmark;
|
||||
|
||||
parent.content.push(bookmark);
|
||||
return bookmark;
|
||||
}
|
||||
|
||||
//TODO test if the new parent is within the old bookmark
|
||||
export function change_directory(parent: DirectoryBookmark, bookmark: Bookmark | DirectoryBookmark) {
|
||||
delete_bookmark(bookmark)
|
||||
parent.content.push(bookmark)
|
||||
}
|
||||
|
||||
export function save_bookmark(bookmark?: Bookmark | DirectoryBookmark) {
|
||||
save_config(); /* nvm we dont give a fuck... saving everything */
|
||||
}
|
||||
|
||||
function delete_bookmark_recursive(parent: DirectoryBookmark, bookmark: Bookmark | DirectoryBookmark) {
|
||||
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 as DirectoryBookmark, bookmark)
|
||||
}
|
||||
|
||||
export function delete_bookmark(bookmark: Bookmark | DirectoryBookmark) {
|
||||
delete_bookmark_recursive(bookmarks(), bookmark)
|
||||
}
|
||||
}
|
|
@ -402,10 +402,24 @@ interface ClientNameFromUid {
|
|||
response: ClientNameInfo[]
|
||||
}
|
||||
|
||||
interface QueryListEntry {
|
||||
username: string;
|
||||
unique_id: string;
|
||||
bounded_server: number;
|
||||
}
|
||||
|
||||
interface QueryList {
|
||||
flag_own: boolean;
|
||||
flag_all: boolean;
|
||||
|
||||
queries: QueryListEntry[];
|
||||
}
|
||||
|
||||
class CommandHelper {
|
||||
readonly connection: ServerConnection;
|
||||
|
||||
private _callbacks_namefromuid: ClientNameFromUid[] = [];
|
||||
private _who_am_i: any;
|
||||
|
||||
constructor(connection) {
|
||||
this.connection = connection;
|
||||
|
@ -432,6 +446,63 @@ class CommandHelper {
|
|||
return req.promise;
|
||||
}
|
||||
|
||||
request_query_list(server_id: number = undefined) : Promise<QueryList> {
|
||||
return new Promise<QueryList>((resolve, reject) => {
|
||||
this.connection.commandHandler["notifyquerylist"] = json => {
|
||||
const result = {} as QueryList;
|
||||
|
||||
result.flag_all = json[0]["flag_all"];
|
||||
result.flag_own = json[0]["flag_own"];
|
||||
result.queries = [];
|
||||
|
||||
for(const entry of json) {
|
||||
const rentry = {} as QueryListEntry;
|
||||
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);
|
||||
this.connection.commandHandler["notifyquerylist"] = undefined;
|
||||
};
|
||||
|
||||
let data = {};
|
||||
if(server_id !== undefined)
|
||||
data["server_id"] = server_id;
|
||||
|
||||
this.connection.sendCommand("querylist", data).catch(error => {
|
||||
if(error instanceof CommandResult) {
|
||||
if(error.id == 0x0501) {
|
||||
resolve(undefined);
|
||||
return;
|
||||
}
|
||||
}
|
||||
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() : Promise<number> {
|
||||
if(this._who_am_i)
|
||||
return Promise.resolve(parseInt(this._who_am_i["virtualserver_id"]));
|
||||
|
||||
return new Promise<number>((resolve, reject) => {
|
||||
this.connection.commandHandler[""] = json => {
|
||||
this._who_am_i = json[0];
|
||||
resolve(parseInt(this._who_am_i["virtualserver_id"]));
|
||||
this.connection.commandHandler[""] = undefined;
|
||||
};
|
||||
this.connection.sendCommand("whoami");
|
||||
});
|
||||
}
|
||||
|
||||
private handle_notifyclientnamefromuid(json: any[]) {
|
||||
for(let entry of json) {
|
||||
let info: ClientNameInfo = {} as any;
|
||||
|
|
|
@ -180,6 +180,8 @@ function loadDebug() {
|
|||
"js/crypto/hex.js",
|
||||
|
||||
//Load UI
|
||||
"js/ui/modal/ModalQuery.js",
|
||||
"js/ui/modal/ModalQueryManage.js",
|
||||
"js/ui/modal/ModalConnect.js",
|
||||
"js/ui/modal/ModalSettings.js",
|
||||
"js/ui/modal/ModalCreateChannel.js",
|
||||
|
@ -219,6 +221,7 @@ function loadDebug() {
|
|||
|
||||
//Load general stuff
|
||||
"js/settings.js",
|
||||
"js/bookmarks.js",
|
||||
"js/contextMenu.js",
|
||||
"js/connection.js",
|
||||
"js/FileManager.js",
|
||||
|
|
|
@ -21,9 +21,9 @@ 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;
|
||||
if((navigator as any).mediaDevices && (navigator as any).mediaDevices.getUserMedia)
|
||||
return (settings, success, fail) => { (navigator as any).mediaDevices.getUserMedia(settings).then(success).catch(fail); };
|
||||
return (navigator as any).getUserMedia || (navigator as any).webkitGetUserMedia || (navigator as any).mozGetUserMedia;
|
||||
}
|
||||
|
||||
function setup_close() {
|
||||
|
|
|
@ -143,9 +143,9 @@ class GroupManager {
|
|||
group.updateProperty(key, groupData[key]);
|
||||
}
|
||||
|
||||
group.requiredMemberRemovePower = groupData["n_member_removep"];
|
||||
group.requiredMemberAddPower = groupData["n_member_addp"];
|
||||
group.requiredModifyPower = groupData["n_modifyp"];
|
||||
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);
|
||||
|
@ -154,6 +154,8 @@ class GroupManager {
|
|||
}
|
||||
|
||||
console.log("Got " + json.length + " new " + target + " groups:");
|
||||
for(const client of this.handle.channelTree.clients)
|
||||
client.update_displayed_client_groups();
|
||||
}
|
||||
|
||||
request_permissions(group: Group) : Promise<PermissionValue[]> { //database_empty_result
|
||||
|
|
|
@ -644,11 +644,12 @@ class PermissionManager {
|
|||
for(let perm of this.neededPermissions)
|
||||
if(perm.type.id == key || perm.type.name == key || perm.type == key)
|
||||
return perm;
|
||||
|
||||
log.debug(LogCategory.PERMISSIONS, 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, tr("Requested needed permission with invalid key! (%o)"), key);
|
||||
return undefined;
|
||||
return new NeededPermissionValue(undefined, -2);
|
||||
}
|
||||
let result = new NeededPermissionValue(info, -2);
|
||||
this.neededPermissions.push(result);
|
||||
|
|
|
@ -13,6 +13,7 @@ interface JSON {
|
|||
interface JQuery<TElement = HTMLElement> {
|
||||
render(values?: any) : string;
|
||||
renderTag(values?: any) : JQuery<TElement>;
|
||||
hasScrollBar() : boolean;
|
||||
}
|
||||
|
||||
interface JQueryStatic<TElement extends Node = HTMLElement> {
|
||||
|
@ -106,8 +107,8 @@ if(typeof ($) !== "undefined") {
|
|||
return $(document.createElement(tagName) as any);
|
||||
}
|
||||
}
|
||||
if(!$.prototype.renderTag) {
|
||||
$.prototype.renderTag = function (values?: any) : JQuery {
|
||||
if(!$.fn.renderTag) {
|
||||
$.fn.renderTag = function (values?: any) : JQuery {
|
||||
let result;
|
||||
if(this.render) {
|
||||
result = $(this.render(values));
|
||||
|
@ -126,6 +127,11 @@ if(typeof ($) !== "undefined") {
|
|||
return result;
|
||||
}
|
||||
}
|
||||
if(!$.fn.hasScrollBar)
|
||||
$.fn.hasScrollBar = function() {
|
||||
return this.get(0).scrollHeight > this.height();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!String.prototype.format) {
|
||||
|
|
|
@ -294,12 +294,14 @@ class ChannelEntry {
|
|||
|
||||
const sub = this.siblings(false);
|
||||
sub.forEach(function (e) {
|
||||
subSize += e.rootTag().outerHeight(true);
|
||||
if(e.rootTag().is(":visible"))
|
||||
subSize += e.rootTag().outerHeight(true);
|
||||
});
|
||||
|
||||
const clients = this.clients(false);
|
||||
clients.forEach(function (e) {
|
||||
clientSize += e.tag.outerHeight(true);
|
||||
if(e.tag.is(":visible"))
|
||||
clientSize += e.tag.outerHeight(true);
|
||||
});
|
||||
|
||||
this._tag_root.css({height: size + subSize + clientSize});
|
||||
|
|
|
@ -408,7 +408,9 @@ class ClientEntry {
|
|||
|
||||
tag.append($.spawn("div").addClass("icon_client_state").attr("title", "Client state"));
|
||||
|
||||
tag.append($.spawn("div").addClass("group_prefix").attr("title", "Server groups prefixes").hide());
|
||||
tag.append($.spawn("div").addClass("name").text(this.clientNickName()));
|
||||
tag.append($.spawn("div").addClass("group_suffix").attr("title", "Server groups suffix").hide());
|
||||
tag.append($.spawn("div").addClass("away").text(this.clientNickName()));
|
||||
|
||||
let clientIcons = $.spawn("span");
|
||||
|
@ -561,7 +563,7 @@ class ClientEntry {
|
|||
if(variable.key == "client_icon_id")
|
||||
this.updateClientIcon();
|
||||
if(variable.key =="client_channel_group_id" || variable.key == "client_servergroups")
|
||||
this.updateGroupIcons();
|
||||
this.update_displayed_client_groups();
|
||||
}
|
||||
|
||||
/* process updates after variables have been set */
|
||||
|
@ -577,11 +579,39 @@ class ClientEntry {
|
|||
group.end();
|
||||
}
|
||||
|
||||
updateGroupIcons() {
|
||||
update_displayed_client_groups() {
|
||||
this.tag.find("span .group_icons").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: string[] = [];
|
||||
let suffix_groups: string[] = [];
|
||||
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(){
|
||||
|
|
|
@ -13,11 +13,13 @@
|
|||
client_away_message Value: ''
|
||||
*/
|
||||
import openBanList = Modals.openBanList;
|
||||
import spawnConnectModal = Modals.spawnConnectModal;
|
||||
|
||||
class ControlBar {
|
||||
private _muteInput: boolean;
|
||||
private _muteOutput: boolean;
|
||||
private _away: boolean;
|
||||
private _query_visible: boolean;
|
||||
private _awayMessage: string;
|
||||
|
||||
private codec_supported: boolean = false;
|
||||
|
@ -64,10 +66,35 @@ class ControlBar {
|
|||
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");
|
||||
});
|
||||
|
||||
this.update_bookmarks()
|
||||
}
|
||||
{
|
||||
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.global("mute_input") == "1";
|
||||
this.muteOutput = settings.global("mute_output") == "1";
|
||||
this.query_visibility = settings.global("show_server_queries") == "1";
|
||||
}
|
||||
|
||||
|
||||
|
@ -269,6 +296,77 @@ class ControlBar {
|
|||
private onBanlist() {
|
||||
if(!this.handle.serverConnection) return;
|
||||
|
||||
openBanList(this.handle);
|
||||
if(this.handle.permissions.neededPermission(PermissionType.B_CLIENT_BAN_LIST).granted(1)) {
|
||||
openBanList(this.handle);
|
||||
} else {
|
||||
createErrorModal(tr("You dont have the permission"), tr("You dont have the permission to view the ban list")).open();
|
||||
sound.play(Sound.ERROR_INSUFFICIENT_PERMISSIONS);
|
||||
}
|
||||
}
|
||||
|
||||
update_bookmarks() {
|
||||
//<div class="btn_bookmark_connect" target="localhost"><a>Localhost</a></div>
|
||||
let tag_bookmark = this.htmlTag.find(".btn_bookmark .dropdown");
|
||||
tag_bookmark.find(".bookmark, .bookmark_directory").detach();
|
||||
|
||||
for(const bookmark of bookmarks.bookmarks().content) {
|
||||
if(bookmark.type == bookmarks.BookmarkType.ENTRY) {
|
||||
tag_bookmark.append(
|
||||
$.spawn("div")
|
||||
.addClass("bookmark")
|
||||
/* /.attr("bookmark-uuid", bookmark.unique_id) */
|
||||
.text(bookmark.display_name)
|
||||
.on('click', event => {
|
||||
spawnConnectModal()
|
||||
|
||||
})
|
||||
)
|
||||
}
|
||||
//TODO add bookmark directories here
|
||||
}
|
||||
}
|
||||
|
||||
get query_visibility() {
|
||||
return this._query_visible;
|
||||
}
|
||||
|
||||
set query_visibility(flag: boolean) {
|
||||
if(this._query_visible == flag) return;
|
||||
|
||||
this._query_visible = flag;
|
||||
settings.global("show_server_queries", flag);
|
||||
this.update_query_visibility_button();
|
||||
this.handle.channelTree.toggle_server_queries(flag);
|
||||
}
|
||||
|
||||
private on_query_visibility_toggle() {
|
||||
this.query_visibility = !this._query_visible;
|
||||
this.update_query_visibility_button();
|
||||
}
|
||||
|
||||
private update_query_visibility_button() {
|
||||
let tag = this.htmlTag.find(".btn_query_toggle");
|
||||
if(this._query_visible) {
|
||||
tag.addClass("activated");
|
||||
} else {
|
||||
tag.removeClass("activated");
|
||||
}
|
||||
}
|
||||
|
||||
private on_query_create() {
|
||||
if(this.handle.permissions.neededPermission(PermissionType.B_CLIENT_CREATE_MODIFY_SERVERQUERY_LOGIN).granted(1)) {
|
||||
Modals.spawnQueryCreate();
|
||||
} else {
|
||||
createErrorModal(tr("You dont have the permission"), tr("You dont have the permission to create a server query login")).open();
|
||||
sound.play(Sound.ERROR_INSUFFICIENT_PERMISSIONS);
|
||||
}
|
||||
}
|
||||
|
||||
private on_query_manage() {
|
||||
if(globalClient && globalClient.connected) {
|
||||
Modals.spawnQueryManage(globalClient);
|
||||
} else {
|
||||
createErrorModal(tr("You have to be connected"), tr("You have to be connected!")).open();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/// <reference path="../../utils/modal.ts" />
|
||||
/// <reference path="../../proto.ts" />
|
||||
/// <reference path="../../client.ts" />
|
||||
|
||||
namespace Modals {
|
||||
export function spawnQueryCreate(callback_created?: (user, pass) => any) {
|
||||
let modal;
|
||||
modal = createModal({
|
||||
header: 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() as string;
|
||||
if(name.length < 3 || name.length > 64) {
|
||||
createErrorModal(tr("Invalid username"), tr("Please enter a valid name!")).open();
|
||||
return;
|
||||
}
|
||||
|
||||
//client_login_password
|
||||
globalClient.serverConnection.commandHandler["notifyquerycreated"] = json => {
|
||||
json = json[0];
|
||||
|
||||
spawnQueryCreated({
|
||||
username: name,
|
||||
password: json.client_login_password
|
||||
}, true);
|
||||
|
||||
if(callback_created)
|
||||
callback_created(name, json.client_login_password);
|
||||
};
|
||||
|
||||
globalClient.serverConnection.sendCommand("querycreate", {
|
||||
client_login_name: name
|
||||
}).catch(error => {
|
||||
if(error instanceof CommandResult)
|
||||
error = error.extra_message || error.message;
|
||||
createErrorModal(tr("Unable to create account"), tr("Failed to create account<br>Message: ") + error).open();
|
||||
});
|
||||
|
||||
modal.close();
|
||||
//TODO create account
|
||||
});
|
||||
return template;
|
||||
},
|
||||
footer: undefined,
|
||||
width: 750
|
||||
});
|
||||
modal.open();
|
||||
}
|
||||
|
||||
export function spawnQueryCreated(credentials: {
|
||||
username: string,
|
||||
password: string
|
||||
}, yust_created: boolean) {
|
||||
let modal;
|
||||
modal = createModal({
|
||||
header: yust_created ? tr("Server query credentials") : 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();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,156 @@
|
|||
/// <reference path="../../utils/modal.ts" />
|
||||
/// <reference path="../../proto.ts" />
|
||||
/// <reference path="../../client.ts" />
|
||||
|
||||
namespace Modals {
|
||||
export function spawnQueryManage(client: TSClient) {
|
||||
let modal: Modal;
|
||||
let selected_query: QueryListEntry;
|
||||
|
||||
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.helper.current_virtual_server_id().then(server_id => {
|
||||
client.serverConnection.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: 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(tr("Change account name"), tr("Enter the new name for the login:<br>"), text => text.length >= 3, result => {
|
||||
if(result) {
|
||||
client.serverConnection.sendCommand("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(tr("Unable to rename account"), tr("Failed to rename account<br>Message: ") + error).open();
|
||||
}).then(() => {
|
||||
createInfoModal(tr("Account successfully renamed"), tr("The query account has been renamed!")).open();
|
||||
update_list();
|
||||
});
|
||||
}
|
||||
}).open();
|
||||
});
|
||||
template.find(".button-query-change-password").on('click', () => {
|
||||
if(!selected_query) return;
|
||||
|
||||
createInputModal(tr("Change account's password"), tr("Enter a new password (leave blank for auto generation):<br>"), text => true, result => {
|
||||
if(result !== false) {
|
||||
client.serverConnection.sendCommand("querychangepassword", {
|
||||
client_login_name: selected_query.username,
|
||||
client_login_password: result
|
||||
}).catch(error => {
|
||||
if(error instanceof CommandResult)
|
||||
error = error.extra_message || error.message;
|
||||
createErrorModal(tr("Unable to change password"), tr("Failed to change password<br>Message: ") + error).open();
|
||||
});
|
||||
|
||||
client.serverConnection.commandHandler["notifyquerypasswordchanges"] = json => {
|
||||
Modals.spawnQueryCreated({
|
||||
username: json[0]["client_login_name"],
|
||||
password: json[0]["client_login_password"]
|
||||
}, false);
|
||||
|
||||
client.serverConnection.commandHandler["notifyquerypasswordchanges"] = undefined;
|
||||
};
|
||||
}
|
||||
}).open();
|
||||
});
|
||||
template.find(".button-query-delete").on('click', () => {
|
||||
if(!selected_query) return;
|
||||
|
||||
Modals.spawnYesNo(tr("Are you sure?"), tr("Do you really want to delete this account?"), result => {
|
||||
if(result) {
|
||||
client.serverConnection.sendCommand("querydelete", {
|
||||
client_login_name: selected_query.username
|
||||
}).catch(error => {
|
||||
if(error instanceof CommandResult)
|
||||
error = error.extra_message || error.message;
|
||||
createErrorModal(tr("Unable to delete account"), tr("Failed to delete account<br>Message: ") + error).open();
|
||||
}).then(() => {
|
||||
createInfoModal(tr("Account successfully deleted"), 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() as string || "").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();
|
||||
}
|
||||
}
|
|
@ -18,6 +18,7 @@ class ChannelTree {
|
|||
currently_selected_context_callback: (event) => any = undefined;
|
||||
readonly client_mover: ClientMover;
|
||||
|
||||
private _show_queries: boolean;
|
||||
private channel_last?: ChannelEntry;
|
||||
private channel_first?: ChannelEntry;
|
||||
|
||||
|
@ -290,6 +291,10 @@ class ChannelTree {
|
|||
if(newClient) client = newClient; //Got new client :)
|
||||
else
|
||||
this.clients.push(client);
|
||||
|
||||
if(!this._show_queries && client.properties.client_type == ClientType.CLIENT_QUERY)
|
||||
client.tag.hide();
|
||||
|
||||
client.channelTree = this;
|
||||
client["_channel"] = channel;
|
||||
|
||||
|
@ -709,4 +714,23 @@ class ChannelTree {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
toggle_server_queries(flag: boolean) {
|
||||
if(this._show_queries == flag) return;
|
||||
this._show_queries = flag;
|
||||
|
||||
//FIXME resize channels
|
||||
const channels: ChannelEntry[] = []
|
||||
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());
|
||||
}
|
||||
for(const channel of channels)
|
||||
channel.adjustSize();
|
||||
}
|
||||
}
|
3
todo.md
3
todo.md
|
@ -1 +1,2 @@
|
|||
nan
|
||||
Add connect profiles for bookmarks, like TeaSpeak-Forum or multiple TeamSpeak Identities
|
||||
Fix server group management dialog for a lots of groups (May even add a search function?)
|
|
@ -321,11 +321,30 @@ generators[SyntaxKind.ClassDeclaration] = (settings, stack, node: ts.ClassDeclar
|
|||
return ts.createClassDeclaration(node.decorators, append_export(append_declare(node.modifiers, !stack.flag_declare), stack.flag_namespace), node.name, node.typeParameters, node.heritageClauses, members as any);
|
||||
};
|
||||
|
||||
generators[SyntaxKind.PropertySignature] = (settings, stack, node: ts.PropertySignature) => {
|
||||
console.log(SyntaxKind[node.type.kind]);
|
||||
let type: ts.TypeNode = node.type;
|
||||
switch (node.type.kind) {
|
||||
case SyntaxKind.LiteralType:
|
||||
type = ts.createIdentifier("any") as any;
|
||||
}
|
||||
|
||||
return ts.createPropertySignature(node.modifiers, node.name, node.questionToken, type, undefined);
|
||||
};
|
||||
|
||||
generators[SyntaxKind.InterfaceDeclaration] = (settings, stack, node: ts.InterfaceDeclaration) => {
|
||||
if(settings.remove_private.field && has_private(node.modifiers)) return;
|
||||
if(stack.flag_namespace && !has_modifier(node.modifiers, SyntaxKind.ExportKeyword)) return;
|
||||
|
||||
return node;
|
||||
const members: any[] = [];
|
||||
for(const member of node.members) {
|
||||
if(generators[member.kind])
|
||||
members.push(generators[member.kind](settings, stack, member));
|
||||
else
|
||||
members.push(member);
|
||||
}
|
||||
|
||||
return ts.createInterfaceDeclaration(undefined, append_export(append_declare(node.modifiers, !stack.flag_declare), stack.flag_namespace), node.name, node.typeParameters, node.heritageClauses, members);
|
||||
};
|
||||
|
||||
generators[SyntaxKind.VariableDeclaration] = (settings, stack, node: ts.VariableDeclaration) => {
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
enum YY {
|
||||
H = "C",
|
||||
B = "Y"
|
||||
}
|
||||
|
||||
interface X {
|
||||
type: "",
|
||||
c: YY.B
|
||||
}
|
|
@ -1 +1 @@
|
|||
Subproject commit 7b931ed61cf265937dc742579f9070e7c4e50775
|
||||
Subproject commit 0221bd137ef5bbc846018ff86deda0aca38aed26
|
Loading…
Reference in New Issue