Improved and fixed channel tree issues

This commit is contained in:
WolverinDEV 2019-02-17 12:17:17 +01:00
parent 050b34129b
commit d70667e309
13 changed files with 567 additions and 423 deletions

View file

@ -0,0 +1,231 @@
/* the channel tree */
.channel-tree {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
width: 100%;
display: -ms-flex;
display: flex;
flex-direction: column;
* {
font-family: sans-serif;
font-size: 12px;
white-space: pre;
line-height: 1;
}
.tree-entry {
display: flex;
flex-direction: row;
justify-content: stretch;
margin-left: 16px;
min-height: 16px;
flex-grow: 0;
flex-shrink: 0;
&.server {
display: flex;
flex-direction: row;
justify-content: stretch;
margin-left: 0;
.server_type {
flex-grow: 0;
flex-shrink: 0;
margin-right: 2px;
}
.name {
flex-grow: 1;
flex-shrink: 1;
align-self: center;
}
.icon_property {
flex-grow: 0;
flex-shrink: 0;
}
&.selected {
background-color: blue;
}
}
&.channel {
display: flex;
flex-direction: column;
.container-channel {
display: flex;
flex-direction: row;
justify-content: stretch;
width: 100%;
min-height: 16px;
align-items: center;
cursor: pointer;
&.selected {
background-color: blue;
}
.channel-type {
flex-grow: 0;
flex-shrink: 0;
margin-right: 2px;
}
.container-channel-name {
display: flex;
flex-direction: row;
flex-grow: 1;
flex-shrink: 1;
justify-content: left;
&.align-right {
justify-content: right;
}
&.align-center, &.align-repetitive {
justify-content: center;
}
}
.icons {
display: flex;
flex-direction: row;
flex-grow: 0;
flex-shrink: 0;
}
&.move-selected {
border-bottom: 1px solid black;
}
.show-channel-normal-only {
display: none;
&.channel-normal {
display: block;
}
}
}
.container-clients {
display: flex;
flex-direction: column;
}
}
&.client {
cursor: pointer;
position: relative;
display: flex;
flex-direction: row;
align-items: center;
> div {
margin-right: 2px;
}
.client-name {
&.client-name-own {
font-weight: bold;
}
}
.container-icons {
margin-right: 0; /* override from previous thing */
position: absolute;
right: 0;
display: flex;
flex-direction: row;
align-items: center;
.container-icons-group {
display: flex;
flex-direction: row;
.container-group-icon {
display: flex;
flex-direction: column;
justify-content: center;
}
}
}
&.selected {
background-color: blue;
}
}
}
}
/* all icons related to basic_icons */
.clicon {width:16px;height:16px;background:url('../../img/ts/basic_icons.png') no-repeat;background-size: 16px 608px;}
.host {background-position: 0 -448px}
.server_open {background-position: 0 -352px}
.server_full {background-position: 0 -128px}
.server_pass {background-position: 0 -432px}
/* Server group icon */
.group_0 {background-position: 0 -464px}
.group_100 {background-position: 0 -16px}
.group_200 {background-position: 0 -304px}
.group_300 {background-position: 0 -80px}
.group_400 {background-position: 0 -528px}
.group_500 {background-position: 0 -416px}
.group_600 {background-position: 0 -272px}
.group_server{background-position: 0 -496px}
.group_channel {background-position: 0 -400px}
/* Channel icons */
.channel_open {background-position: 0 -64px}
.channel_pass {background-position: 0 -112px}
.channel_full {background-position: 0 -256px}
.channel_flag_music {background-position: 0 -32px}
.channel_flag_default {background-position: 0 -48px}
.channel_flag_moderated {background-position: 0 -192px}
.channel_flag_password {background-position: 0 -480px}
/* Client icons */
.client_mic_muted {background-position: 0 -96px}
.client_talker {background-position: 0 -144px}
.client_idle {background-position: 0 -160px}
.client_talk {background-position: 0 -208px}
.client_snd_muted {background-position: 0 -176px}
.client_query {background-position: 0 -224px}
.client_talker_request {background-position: 0 -240px}
.client_snd_disabled {background-position: 0 -320px}
.client_priority {background-position: 0 -336px}
.client_away {background-position: 0 -368px}
.client_cc {background-position: 0 -384px}
.client_cc_talk {background-position: 0 -544px}
.client_cc_idle {background-position: 0 -288px}
.client_mic_disabled {background-position: 0 -512px}

View file

@ -262,7 +262,7 @@ $separator_thickness: 4px;
flex-direction: column;
justify-content: stretch;
.container-channel {
.container-channel-tree {
background: white;
display: flex;

View file

@ -1,210 +0,0 @@
.channelTree {
width: 100%; max-width: 100%;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
vertical-align: center;
outline: none;
}
.channelTree * {
font-family: Arial;
font-size: 12px;
white-space: pre;
line-height: 1;
}
.channelTree div {
max-width: 100%;
height: 16px;
position: relative;
}
.channelTree .channel_type {
margin-right: 4px;
}
.channelTree .icon_client_state {
margin-right: 4px;
}
.channelTree .server_type {
margin-right: 4px;
}
.channelTree .icons .icon_entry {
margin-left: 2px;
}
.channelTree img.loading {width: 50px;height: 50px;-webkit-animation:spin 2s linear infinite;-moz-animation:spin 2s linear infinite;animation:spin 2s linear infinite;}
@-moz-keyframes spin { 100% { -moz-transform: rotate(360deg); } }
@-webkit-keyframes spin { 100% { -webkit-transform: rotate(360deg); } }
@keyframes spin { 100% { -webkit-transform: rotate(360deg); transform:rotate(360deg); } }
.channelTree div.l {justify-content: flex-start; }
.channelTree div.c {justify-content: center;}
.channelTree div.r {justify-content: flex-end;}
.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, .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;
display: inline;
}
.channelTree .channel_name {
display: flex;
align-items: center;
}
.channelTree .channel_name_container {
display: inline-flex;
width: 100%;
overflow-x: hidden;
}
.channelTree .country {width:16px;height:11px;}
.channelTree .siblings {
position: absolute;
margin-top: 16px;
margin-bottom: -2px;
display: grid;
width: 100%;
left: 16px;
}
.channelTree .channel {
cursor: pointer;
margin-top: 1px;
}
.channelTree .clients {
position: absolute;
margin-top: 16px;
margin-bottom: -2px;
display: grid;
width: 100%;
left: 16px;
}
.channelTree .client {
cursor: pointer;
margin-top: 1px;
width: calc(100%);
}
.channelTree .client span > div {
margin-left: 3px;
}
.channelTree .server {
cursor: pointer;
margin-top: 0px;
width: calc(100%);
}
.channelTree .channelLine {
position: absolute;
width: calc(100% - 16px);
display: flex;
flex-direction: row;
top: 0px;
left: 16px;
&.move-selected {
border: 1px black solid;
}
}
.channelTree .selected {
background: #005cbf;
}
.clicon {width:16px;height:16px;background:url('../../../img/ts/basic_icons.png') no-repeat;background-size: 16px 608px;}
.host {background-position: 0 -448px}
.server_open {background-position: 0 -352px}
.server_full {background-position: 0 -128px}
.server_pass {background-position: 0 -432px}
/* Server group icon
.group_0 {background-position: 0 -464px}
.group_100 {background-position: 0 -16px}
.group_200 {background-position: 0 -304px}
.group_300 {background-position: 0 -80px}
.group_400 {background-position: 0 -528px}
.group_500 {background-position: 0 -416px}
.group_600 {background-position: 0 -272px}
.group_server{background-position: 0 -496px}
.group_channel {background-position: 0 -400px}
/* Channel icons
.channel_open {background-position: 0 -64px}
.channel_pass {background-position: 0 -112px}
.channel_full {background-position: 0 -256px}
.channel_flag_music {background-position: 0 -32px}
.channel_flag_default {background-position: 0 -48px}
.channel_flag_moderated {background-position: 0 -192px}
.channel_flag_password {background-position: 0 -480px}
/* Client icons */
.client_mic_muted {background-position: 0 -96px}
.client_talker {background-position: 0 -144px}
.client_idle {background-position: 0 -160px}
.client_talk {background-position: 0 -208px}
.client_snd_muted {background-position: 0 -176px}
.client_query {background-position: 0 -224px}
.client_talker_request {background-position: 0 -240px}
.client_snd_disabled {background-position: 0 -320px}
.client_priority {background-position: 0 -336px}
.client_away {background-position: 0 -368px}
.client_cc {background-position: 0 -384px}
.client_cc_talk {background-position: 0 -544px}
.client_cc_idle {background-position: 0 -288px}
.client_mic_disabled {background-position: 0 -512px}
/* Channel tree icons
.tree_line {background-position: 0 -560px}
.tree_mid {background-position: 0 -576px}
.tree_end {background-position: 0 -592px}
.badges {width:16px;height:16px;background-size: 16px !important;}
.badges.overwolf {background:url('../images/viewer/client_overwolf.png') no-repeat;}
*/
/* menu header via data attribute */
.data-title:before {
content: attr(data-menutitle);
display: block;
position: absolute;
top: 0;
right: 0;
left: 0;
background: #DDD;
padding: 2px;
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 11px;
font-weight: bold;
}
.data-title :first-child {
margin-top: 50px;
}

View file

@ -106,8 +106,8 @@
<div class="container-app-main">
<div class="container-channel-chat">
<!-- Channel tree -->
<div class="container-channel main_container">
<div class="channelTree" id="channelTree"></div>
<div class="container-channel-tree main_container">
<div class="channel-tree" id="channelTree"></div>
</div>
<div class="container-seperator horizontal" seperator-id="seperator-channel-chat"></div>

View file

@ -368,9 +368,9 @@ class IconManager {
//$("<img width=\"16\" height=\"16\" alt=\"tick\" src=\"data:image/png;base64," + value.base64 + "\">")
generateTag(id: number) : JQuery<HTMLDivElement> {
if(id == 0)
return $("<div class='icon_empty'></div>");
return $.spawn("div").addClass("icon_empty");
else if(id < 1000)
return $("<div class='icon client-group_" + id + "'></div>");
return $.spawn("div").addClass("icon client-group_" + id);
let tag = $.spawn("div");
tag.addClass("icon_empty");
@ -384,7 +384,7 @@ class IconManager {
const media = media_image_type(type);
console.debug(tr("Icon has an image type of %o (media: %o)"), type, media);
img.attr("src", "data:image/" + media + ";base64," + icon.base64);
tag.append(img);
tag.append(img).removeClass("icon_empty");
} else {
img.attr("src", "file://null");
@ -400,7 +400,7 @@ class IconManager {
console.debug(tr("Icon %o loaded :)"), id);
img.css("opacity", 0);
tag.append(img);
tag.append(img).removeClass("icon_empty");
loader.animate({opacity: 0}, 50, function () {
$(this).detach();
img.animate({opacity: 1}, 150);

View file

@ -710,6 +710,7 @@ class ConnectionCommandHandler {
this.connection = 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;
@ -843,11 +844,17 @@ class ConnectionCommandHandler {
}
handleCommandChannelList(json) {
this.connection._client.channelTree.hide_channel_tree(); /* dont perform channel inserts on the dom to prevent style recalculations */
console.log(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]);
}

View file

@ -615,9 +615,9 @@ const loader_style = {
"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/client.css",
"css/static/ts/icons.css",
"css/static/general.css",
"css/static/modals.css",

View file

@ -1,5 +1,6 @@
enum LogCategory {
CHANNEL,
CHANNEL_PROPERTIES, /* separating channel and channel properties because on channel init logging is a big bottleneck */
CLIENT,
SERVER,
PERMISSIONS,
@ -20,7 +21,8 @@ namespace log {
let category_mapping = new Map<number, string>([
[LogCategory.CHANNEL, "Channel "],
[LogCategory.CLIENT, "Client "],
[LogCategory.CLIENT, "Channel "],
[LogCategory.CHANNEL_PROPERTIES, "Client "],
[LogCategory.SERVER, "Server "],
[LogCategory.PERMISSIONS, "Permission "],
[LogCategory.GENERAL, "General "],
@ -29,8 +31,9 @@ namespace log {
[LogCategory.I18N, "I18N "]
]);
let enabled_mapping = new Map<number, boolean>([
export let enabled_mapping = new Map<number, boolean>([
[LogCategory.CHANNEL, true],
[LogCategory.CHANNEL_PROPERTIES, false],
[LogCategory.CLIENT, true],
[LogCategory.SERVER, true],
[LogCategory.PERMISSIONS, true],
@ -51,7 +54,7 @@ namespace log {
for(const category of Object.keys(LogCategory).map(e => parseInt(e))) {
if(isNaN(category)) continue;
const category_name = LogCategory[category];
enabled_mapping[category] = settings.static_global("log." + category_name.toLowerCase() + ".enabled", true);
enabled_mapping[category] = settings.static_global<boolean>("log." + category_name.toLowerCase() + ".enabled", enabled_mapping.get(category));
}
}
@ -112,6 +115,8 @@ namespace log {
export class Group {
readonly level: LogType;
readonly category: LogCategory;
readonly enabled: boolean;
owner: Group = undefined;
private readonly name: string;
@ -124,6 +129,7 @@ namespace log {
this.category = category;
this.name = name;
this.optionalParams = optionalParams;
this.enabled = enabled_mapping[category];
}
group(level: LogType, name: string, ...optionalParams: any[]) : Group {
@ -136,6 +142,9 @@ namespace log {
}
log(message: string, ...optionalParams: any[]) : this {
if(!this.enabled)
return this;
if(!this.initialized) {
if(this._collapsed && console.groupCollapsed)
console.groupCollapsed(this.name, ...this.optionalParams);

View file

@ -51,20 +51,19 @@ class ChannelEntry {
channelId: number;
parent?: ChannelEntry;
properties: ChannelProperties = new ChannelProperties();
originalHeight: number;
channel_previous?: ChannelEntry;
channel_next?: ChannelEntry;
private _channelAlign: string;
private _formatedChannelName: string;
private _channel_name_alignment: string = undefined;
private _channel_name_formatted: string = undefined;
private _family_index: number = 0;
//HTML DOM elements
private _tag_root: JQuery<HTMLElement>;
private _tag_siblings: JQuery<HTMLElement>;
private _tag_clients: JQuery<HTMLElement>;
private _tag_channel: JQuery<HTMLElement>;
private _tag_root: JQuery<HTMLElement>; /* container for the channel, client and children tag */
private _tag_siblings: JQuery<HTMLElement>; /* container for all sub channels */
private _tag_clients: JQuery<HTMLElement>; /* container for all clients */
private _tag_channel: JQuery<HTMLElement>; /* container for the channel info itself */
private _cachedPassword: string;
private _cached_channel_description: string = undefined;
@ -75,7 +74,7 @@ class ChannelEntry {
constructor(channelId, channelName, parent = null) {
this.properties = new ChannelProperties();
this.channelId = channelId;
this._formatedChannelName = channelName;
this.properties.channel_name = channelName;
this.parent = parent;
this.channelTree = null;
@ -87,8 +86,8 @@ class ChannelEntry {
return this.properties.channel_name;
}
formatedChannelName() {
return this._formatedChannelName !== undefined ? this._formatedChannelName : this.properties.channel_name;
formattedChannelName() {
return this._channel_name_formatted || this.properties.channel_name;
}
getChannelDescription() : Promise<string> {
@ -108,7 +107,6 @@ class ChannelEntry {
parent_channel() { return this.parent; }
hasParent(){ return this.parent != null; }
getChannelId(){ return this.channelId; }
channelClass() { return "channel_full"; }
children(deep = false) : ChannelEntry[] {
const result: ChannelEntry[] = [];
@ -173,54 +171,139 @@ class ChannelEntry {
return clients;
}
update_family_index() {
const current_index = this._family_index;
const new_index = this.calculate_family_index(true);
if(current_index == new_index) return;
this._tag_channel.css("z-index", this._family_index);
}
private calculate_family_index(enforce_recalculate: boolean = false) : number {
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;
}
private initializeTag() {
let rootTag = $.spawn("div");
const tag_channel = $.spawn("div").addClass("tree-entry channel");
rootTag.attr("id", "channel_" + this.getChannelId());
rootTag.addClass("channel");
//rootTag.append($.spawn("div").addClass("icon_empty"));
{
const container_entry = $.spawn("div").addClass("container-channel");
//Tag channel
this._tag_channel = $.spawn("div");
this._tag_channel.attr('channel-id', this.channelId);
this._tag_channel.addClass("channelLine");
this._tag_channel.addClass(this._channelAlign); //For left
this._tag_channel.css('z-index', this._family_index);
container_entry.attr("channel-id", this.channelId);
container_entry.addClass(this._channel_name_alignment);
container_entry.css('z-index', this.calculate_family_index()); //TODO Calculate!
let channelType = $.spawn("div");
channelType.addClass("channel_only_normal channel_type icon client-channel_green_subscribed");
this._tag_channel.append(channelType);
/* channel icon (type) */
{
container_entry.append(
$.spawn("div")
.addClass("show-channel-normal-only channel-type icon client-channel_green_subscribed")
);
}
this._tag_channel.append($.spawn("div").addClass("channel_name_container").append($.spawn("a").addClass("channel_name").text(this.channelName())));
/* 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 iconTag = $.spawn("span").addClass("icons");
iconTag.appendTo(this._tag_channel);
let container_icons = $.spawn("span").addClass("icons");
//Default icon (5)
iconTag.append($.spawn("div").addClass("channel_only_normal").append($.spawn("div").addClass("icon_entry icon_default icon client-channel_default").attr("title", "Default channel")));
container_icons.append(
$.spawn("div")
.addClass("show-channel-normal-only icon_entry icon_default icon client-channel_default")
.attr("title", tr("Default channel"))
);
//Password icon (4)
iconTag.append($.spawn("div").addClass("channel_only_normal").append($.spawn("div").addClass("icon_entry icon_password icon client-register").attr("title", "The channel is password protected")));
container_icons.append(
$.spawn("div")
.addClass("show-channel-normal-only icon_entry icon_password icon client-register")
.attr("title", tr("The channel is password protected"))
);
//Music icon (3)
iconTag.append($.spawn("div").addClass("channel_only_normal").append($.spawn("div").addClass("icon_entry icon_music icon client-music").attr("title", "Music quality")));
container_icons.append(
$.spawn("div")
.addClass("show-channel-normal-only icon_entry icon_music icon client-music")
.attr("title", tr("Music quality"))
);
//Channel moderated (2)
iconTag.append($.spawn("div").addClass("channel_only_normal").append($.spawn("div").addClass("icon_entry icon_moderated icon client-moderated").attr("title", "Channel is moderated")));
container_icons.append(
$.spawn("div")
.addClass("show-channel-normal-only icon_entry icon_moderated icon client-moderated")
.attr("title", tr("Channel is moderated"))
);
//Channel Icon (1)
//iconTag.append($.spawn("div").addClass("channel_only_normal").addClass("icon_entry channel_icon").attr("title", "Channel icon"));
iconTag.append($.spawn("div").addClass("channel_only_normal").append($.spawn("div").addClass("icon_entry channel_icon").attr("title", "Channel icon")));
container_icons.append(
$.spawn("div")
.addClass("show-channel-normal-only icon_entry channel_icon")
.attr("title", tr("Channel icon"))
);
//Default no sound (0)
let container = $.spawn("div");
let noSound = $.spawn("div").addClass("icon_entry icon_no_sound icon client-conflict-icon").attr("title", "You don't support the channel codec");
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("left", "3px")
.css("z-index", "-1");
bg.appendTo(container);
noSound.appendTo(container);
iconTag.append(container);
container_icons.append(container);
container_icons.appendTo(container_entry);
}
tag_channel.append(this._tag_channel = container_entry);
}
{
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);
@ -228,20 +311,7 @@ class ChannelEntry {
}, 150);
*/
//Build siblings
this._tag_siblings = $.spawn("div").addClass("siblings");
let tag_siblings_box = $.spawn("div").css("position", "absolute").css("width", "calc(100% - 16px)").css("margin", "0px");
this._tag_siblings.appendTo(tag_siblings_box);
//Build clients
this._tag_clients = $.spawn("div").addClass("clients");
let tag_clients_box = $.spawn("div").css("position", "absolute").css("width", "calc(100% - 16px)").css("margin", "0px");
this._tag_clients.appendTo(tag_clients_box);
this._tag_root = rootTag;
tag_clients_box.appendTo(this._tag_root);
tag_siblings_box.appendTo(this._tag_root);
this._tag_channel.appendTo(this._tag_root);
this._tag_root = tag_channel;
}
rootTag() : JQuery<HTMLElement> {
@ -287,29 +357,6 @@ class ChannelEntry {
}
}
adjustSize(parent = true) {
const size = this.originalHeight;
let subSize = 0;
let clientSize = 0;
const sub = this.children(false);
sub.forEach(function (e) {
if(e.rootTag().is(":visible"))
subSize += e.rootTag().outerHeight(true);
});
const clients = this.clients(false);
clients.forEach(function (e) {
if(e.tag.is(":visible"))
clientSize += e.tag.outerHeight(true);
});
this._tag_root.css({height: size + subSize + clientSize});
this._tag_siblings.css("margin-top", (clientSize + 16) + "px");
this._tag_clients.css({height: clientSize});
if(parent && this.parent_channel()) this.parent_channel().adjustSize(parent);
}
initializeListener() {
const _this = this;
this.channelTag().click(function () {
@ -465,8 +512,10 @@ class ChannelEntry {
this.__updateChannelName();
}
private static NAME_ALIGNMENTS: string[] = ["align-left", "align-center", "align-right", "align-repetitive"];
private __updateChannelName() {
this._formatedChannelName = undefined;
this._channel_name_formatted = undefined;
parseType:
if(this.parent_channel() == null && this.properties.channel_name.charAt(0) == '[') {
let end = this.properties.channel_name.indexOf(']');
@ -477,49 +526,64 @@ class ChannelEntry {
options = options.substr(0, options.indexOf("spacer"));
console.log(tr("Channel options: '%o'"), options);
if(options.length == 0) options = "l";
if(options.length == 0) options = "align-left";
else if(options.length > 1) options = options[0];
if(options == "r" || options == "l" || options == "c" || options == "*")
this._channelAlign = options;
else break parseType;
this._formatedChannelName = this.properties.channel_name.substr(end + 1);
console.log(tr("Got channel name: %o"), this._formatedChannelName);
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;
}
let self = this.channelTag();
let channelName = self.find(".channel_name");
channelName.text(this.formatedChannelName());
channelName.parent().removeClass("l r c *"); //Alignments
(this._formatedChannelName !== undefined ? $.fn.hide : $.fn.show).apply(self.find(".channel_only_normal"));
this._channel_name_formatted = this.properties.channel_name.substr(end + 1);
console.log(tr("Got formated channel name: %o"), this._channel_name_formatted);
}
if(this._formatedChannelName !== undefined) {
channelName.parent().addClass(this._channelAlign);
this._tag_channel.find(".show-channel-normal-only").toggleClass("channel-normal", this._channel_name_formatted === undefined);
if(this._channelAlign == "*") {
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 || this.properties.channel_name);
if(this._channel_name_formatted !== undefined) {
tag_container_name.addClass(this._channel_name_alignment);
if(this._channel_name_alignment == "*") {
let lastSuccess = "";
let index = 6;
let name = this.formatedChannelName();
let name = this.formattedChannelName();
while(index-- > 0)
name = name + name;
channelName.text(name);
tag_name.text(name);
do {
channelName.text(name = name + name);
} while (channelName.parent().width() >= channelName.width() && ++index < 64);
tag_name.text(name = name + name);
} while (tag_name.parent().width() >= tag_name.width() && ++index < 64);
if(index == 64) console.warn(LogCategory.CHANNEL, tr("Repeating spacer took too much repeats!"));
if(lastSuccess.length > 0) {
channelName.text(lastSuccess);
self.addClass("c");
tag_name.text(lastSuccess);
}
}
}
console.log(tr("Align: %s"), this._channelAlign);
console.log(tr("Align: %s"), this._channel_name_alignment);
}
updateVariables(...variables: {key: string, value: string}[]) {
let group = log.group(log.LogType.DEBUG, LogCategory.CHANNEL, tr("Update properties (%i) of %s (%i)"), variables.length, this.channelName(), this.getChannelId());
let group = log.group(log.LogType.DEBUG, LogCategory.CHANNEL_PROPERTIES, tr("Update properties (%i) of %s (%i)"), variables.length, this.channelName(), this.getChannelId());
for(let variable of variables) {
let key = variable.key;
@ -564,9 +628,11 @@ class ChannelEntry {
}
updateChannelTypeIcon() {
let tag = this.channelTag().find(".channel_type");
let tag = this.channelTag().find(".channel-type");
tag.removeAttr('class');
tag.addClass("channel_only_normal channel_type icon");
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)
@ -583,7 +649,7 @@ class ChannelEntry {
}
generate_bbcode() {
return "[url=channel://" + this.channelId + "/" + encodeURIComponent(this.properties.channel_name) + "]" + this.formatedChannelName() + "[/url]";
return "[url=channel://" + this.channelId + "/" + encodeURIComponent(this.properties.channel_name) + "]" + this.formattedChannelName() + "[/url]";
}
generate_tag(braces: boolean = false) : JQuery {

View file

@ -416,26 +416,58 @@ class ClientEntry {
get tag() : JQuery<HTMLElement> {
if(this._tag) return this._tag;
let tag = $.spawn("div");
let container_client = $.spawn("div")
.addClass("tree-entry client")
.attr("client-id", this.clientId());
tag.attr("id", "client_" + this.clientId());
tag.addClass("client");
tag.append($.spawn("div").addClass("icon_empty"));
tag.append($.spawn("div").addClass("icon_client_state").attr("title", "Client state"));
container_client.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()));
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 clientIcons = $.spawn("span");
clientIcons.append($.spawn("div").addClass("icon icon_talk_power client-input_muted").hide());
clientIcons.append($.spawn("span").addClass("group_icons"));
clientIcons.append($.spawn("span").addClass("client_icon"));
tag.append(clientIcons);
let container_icons = $.spawn("div").addClass("container-icons");
this._tag = tag;
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;
}
@ -470,9 +502,9 @@ class ClientEntry {
updateClientStatusIcons() {
let talk_power = this.properties.client_talk_power >= this._channel.properties.channel_needed_talk_power;
if(talk_power)
this.tag.find("span").find(".icon_talk_power").hide();
this.tag.find(".icon_talk_power").hide();
else
this.tag.find("span").find(".icon_talk_power").show();
this.tag.find(".icon_talk_power").show();
}
updateClientSpeakIcon() {
@ -519,7 +551,7 @@ class ClientEntry {
}
updateAwayMessage() {
let tag = this.tag.find(".away");
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();
@ -542,7 +574,7 @@ class ClientEntry {
//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(".name").text(variable.value);
this.tag.find(".client-name").text(variable.value);
let chat = this.chat(false);
if(chat) chat.name = variable.value;
@ -584,7 +616,7 @@ class ClientEntry {
}
update_displayed_client_groups() {
this.tag.find("span .group_icons").children().detach();
this.tag.find(".container-icons-group").children().detach();
for(let id of this.assignedServerGroupIds())
this.updateGroupIcon(this.channelTree.client.groups.serverGroup(id));
@ -603,8 +635,8 @@ class ClientEntry {
suffix_groups.push(group.name);
}
const tag_group_prefix = this.tag.find(".group_prefix");
const tag_group_suffix = this.tag.find(".group_suffix");
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 {
@ -648,21 +680,23 @@ class ClientEntry {
}
updateClientIcon() {
this.tag.find("span .client_icon").children().detach();
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("span .client_icon"));
.appendTo(this.tag.find(".container-icon-client"));
}
}
updateGroupIcon(group: Group) {
if(!group) return;
//TODO group icon order
this.tag.find(".group_icons .icon_group_" + group.id).detach();
this.tag.find(".container-icons-group .icon_group_" + group.id).detach();
if (group.properties.iconid > 0) {
this.tag.find("span .group_icons").append(
$.spawn("div").addClass("icon_group_" + group.id).append(this.channelTree.client.fileManager.icons.generateTag(group.properties.iconid)).attr("title", group.name)
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)
);
}
}
@ -774,7 +808,7 @@ class LocalClientEntry extends ClientEntry {
initializeListener(): void {
super.initializeListener();
this.tag.find(".name").addClass("own_name");
this.tag.find(".client-name").addClass("client-name-own");
this.tag.dblclick(() => {
if($.isArray(this.channelTree.currently_selected)) { //Multiselect
@ -787,9 +821,9 @@ class LocalClientEntry extends ClientEntry {
openRename() : void {
const _self = this;
const elm = this.tag.find(".name");
const elm = this.tag.find(".client-name");
elm.attr("contenteditable", "true");
elm.removeClass("own_name");
elm.removeClass("client-name-own");
elm.css("background-color", "white");
elm.focus();
_self.renaming = true;
@ -807,7 +841,7 @@ class LocalClientEntry extends ClientEntry {
elm.css("background-color", "");
elm.removeAttr("contenteditable");
elm.addClass("own_name");
elm.addClass("client-name-own");
let text = elm.text().toString();
if(_self.clientNickName() == text) return;

View file

@ -88,7 +88,7 @@ class ClientMover {
const elements = document.elementsFromPoint(event.pageX, event.pageY);
while(elements.length > 0) {
if(elements[0].classList.contains("channelLine")) break;
if(elements[0].classList.contains("container-channel")) break;
elements.pop_front();
}

View file

@ -94,17 +94,23 @@ class ServerEntry {
get htmlTag() {
if(this._htmlTag) return this._htmlTag;
let tag = $.spawn("div");
let tag = $.spawn("div").addClass("tree-entry server");
tag.attr("id", "server");
tag.addClass("server");
tag.append($.spawn("div").addClass("server_type icon client-server_green"));
tag.append($.spawn("a").addClass("name").text(this.properties.virtualserver_name));
tag.append(
$.spawn("div")
.addClass("server_type icon client-server_green")
);
const serverIcon = $("<span/>");
//we cant spawn an icon on creation :)
serverIcon.append($.spawn("div").addClass("icon_property icon_empty"));
tag.append(serverIcon);
tag.append(
$.spawn("div")
.addClass("name")
.text(this.properties.virtualserver_name)
);
tag.append(
$.spawn("div")
.addClass("icon_property icon_empty")
);
return this._htmlTag = tag;
}

View file

@ -10,6 +10,7 @@
class ChannelTree {
client: TSClient;
htmlTree: JQuery;
htmlTree_parent: JQuery;
server: ServerEntry;
channels: ChannelEntry[];
clients: ClientEntry[];
@ -29,6 +30,8 @@ class ChannelTree {
this.client = client;
this.htmlTree = htmlTree;
this.htmlTree_parent = this.htmlTree.parent();
this.client_mover = new ClientMover(this);
this.reset();
@ -63,6 +66,22 @@ class ChannelTree {
}});
}
hide_channel_tree() {
this.htmlTree.detach();
}
show_channel_tree() {
this.htmlTree.appendTo(this.htmlTree_parent);
/* TODO fixup the children (in general the order method) */
const channel_resize: ChannelEntry[] = [];
const enqueue_resize = (entry: ChannelEntry) => {
channel_resize.push(entry);
entry.children().forEach(e => enqueue_resize(e));
};
this.rootChannel().forEach(e => enqueue_resize(e));
}
showContextMenu(x: number, y: number, on_close: () => void = undefined) {
let channelCreate =
this.client.permissions.neededPermission(PermissionType.B_CHANNEL_CREATE_TEMPORARY).granted(1) ||
@ -91,12 +110,6 @@ class ChannelTree {
let tag = element instanceof ChannelEntry ? element.rootTag() : element.tag;
this.htmlTree.find(tag).fadeOut("slow", () => {
tag.remove();
if(element instanceof ChannelEntry) {
if(element.parent_channel())
element.parent_channel().adjustSize(true);
} else if(element instanceof ClientEntry) {
element.currentChannel().adjustSize(true);
}
});
}
@ -180,7 +193,6 @@ class ChannelTree {
let entry = channel.rootTag().css({display: "none"}).fadeIn("slow");
entry.appendTo(tag);
channel.originalHeight = entry.outerHeight(false);
if(elm != undefined)
elm.after(entry);
@ -189,8 +201,8 @@ class ChannelTree {
if(channel.channel_next == channel) /* shall never happen */
channel.channel_next = undefined;
channel.adjustSize(true);
channel.initializeListener();
channel.update_family_index();
}
findChannel(channelId: number) : ChannelEntry | undefined {
@ -206,9 +218,9 @@ class ChannelTree {
return undefined;
}
moveChannel(channel: ChannelEntry, channel_previus: ChannelEntry, parent: ChannelEntry) {
if(channel_previus != null && channel_previus.parent != parent) {
console.error(tr("Invalid channel move (different parents! (%o|%o)"), channel_previus.parent, parent);
moveChannel(channel: ChannelEntry, channel_previous: ChannelEntry, parent: ChannelEntry) {
if(channel_previous != null && channel_previous.parent != parent) {
console.error(tr("Invalid channel move (different parents! (%o|%o)"), channel_previous.parent, parent);
return;
}
@ -227,16 +239,16 @@ class ChannelTree {
let oldParent = channel.parent_channel();
channel.channel_next = undefined;
channel.channel_previous = channel_previus;
channel.channel_previous = channel_previous;
channel.parent = parent;
if(channel_previus) {
if(channel_previus == this.channel_last)
if(channel_previous) {
if(channel_previous == this.channel_last)
this.channel_last = channel;
channel.channel_next = channel_previus.channel_next;
channel_previus.channel_next = channel;
channel_previus.rootTag().after(channel.rootTag());
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;
@ -267,17 +279,11 @@ class ChannelTree {
}
}
channel.update_family_index();
if(channel.channel_previous == channel) /* shall never happen */
channel.channel_previous = undefined;
if(channel.channel_next == channel) /* shall never happen */
channel.channel_next = undefined;
if(oldParent) {
oldParent.adjustSize();
}
if(channel) {
channel.adjustSize();
}
}
deleteClient(client: ClientEntry) {
@ -300,7 +306,6 @@ class ChannelTree {
let tag = client.tag.css({display: "none"}).fadeIn("slow");
tag.appendTo(channel.clientTag());
channel.adjustSize(true);
client.currentChannel().reorderClients();
channel.updateChannelTypeIcon();
@ -325,11 +330,9 @@ class ChannelTree {
tag.detach();
tag.appendTo(client.currentChannel().clientTag());
if(oldChannel) {
oldChannel.adjustSize();
oldChannel.updateChannelTypeIcon();
}
if(client.currentChannel()) {
client.currentChannel().adjustSize();
client.currentChannel().reorderClients();
client.currentChannel().updateChannelTypeIcon();
}
@ -397,7 +400,7 @@ class ChannelTree {
if(e == entry) {
this.currently_selected.remove(e);
if(entry instanceof ChannelEntry)
(entry as ChannelEntry).rootTag().find("> .channelLine").removeClass("selected");
(entry as ChannelEntry).channelTag().removeClass("selected");
else if(entry instanceof ClientEntry)
(entry as ClientEntry).tag.removeClass("selected");
else if(entry instanceof ServerEntry)
@ -413,7 +416,7 @@ class ChannelTree {
}
if(entry instanceof ChannelEntry)
(entry as ChannelEntry).rootTag().find("> .channelLine").addClass("selected");
(entry as ChannelEntry).channelTag().addClass("selected");
else if(entry instanceof ClientEntry)
(entry as ClientEntry).tag.addClass("selected");
else if(entry instanceof ServerEntry)
@ -739,8 +742,6 @@ class ChannelTree {
if(channels.indexOf(client.currentChannel()) == -1)
channels.push(client.currentChannel());
}
for(const channel of channels)
channel.adjustSize();
}
get_first_channel?() : ChannelEntry {