Some minor bugfixing and enabled context menus for every clickable client tag
parent
c8aab5fa6d
commit
0035e73179
|
@ -4,6 +4,7 @@
|
|||
- Properly updating the private message unread count
|
||||
- Improved channel conversation mode detection support
|
||||
- Added support for HTML encoded links (Example would be when copying from Edge the URL)
|
||||
- Enabled context menus for all clickable client tags
|
||||
|
||||
* **08.12.20**
|
||||
- Fixed the permission editor not resolving unique ids
|
||||
|
|
|
@ -398,7 +398,7 @@ export class ChannelConversationManager extends AbstractChatManager<ChannelConve
|
|||
}
|
||||
|
||||
findConversation(channelId: number) : ChannelConversation {
|
||||
return this.findConversationById(channelId.toString());
|
||||
return this.findConversationById(channelId?.toString());
|
||||
}
|
||||
|
||||
findOrCreateConversation(channelId: number) {
|
||||
|
|
|
@ -352,7 +352,7 @@ class LocalAvatarManagerFactory extends AbstractAvatarManagerFactory {
|
|||
constructor() {
|
||||
super();
|
||||
|
||||
this.ipcChannel = ipc.getInstance().createChannel(undefined, kIPCAvatarChannel);
|
||||
this.ipcChannel = ipc.getIpcInstance().createChannel(undefined, kIPCAvatarChannel);
|
||||
this.ipcChannel.messageHandler = this.handleIpcMessage.bind(this);
|
||||
|
||||
server_connections.events().on("notify_handler_created", event => this.handleHandlerCreated(event.handler));
|
||||
|
|
|
@ -69,7 +69,7 @@ class IconManager extends AbstractIconManager {
|
|||
constructor() {
|
||||
super();
|
||||
|
||||
this.ipcChannel = ipc.getInstance().createChannel(undefined, kIPCIconChannel);
|
||||
this.ipcChannel = ipc.getIpcInstance().createChannel(undefined, kIPCIconChannel);
|
||||
this.ipcChannel.messageHandler = this.handleIpcMessage.bind(this);
|
||||
|
||||
server_connections.events().on("notify_handler_created", event => {
|
||||
|
|
|
@ -159,7 +159,7 @@ class RemoteAvatarManagerFactory extends AbstractAvatarManagerFactory {
|
|||
constructor() {
|
||||
super();
|
||||
|
||||
this.ipcChannel = ipc.getInstance().createChannel(Settings.instance.static(Settings.KEY_IPC_REMOTE_ADDRESS, "invalid"), kIPCAvatarChannel);
|
||||
this.ipcChannel = ipc.getIpcInstance().createChannel(Settings.instance.static(Settings.KEY_IPC_REMOTE_ADDRESS, "invalid"), kIPCAvatarChannel);
|
||||
this.ipcChannel.messageHandler = this.handleIpcMessage.bind(this);
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ class RemoteIconManager extends AbstractIconManager {
|
|||
constructor() {
|
||||
super();
|
||||
|
||||
this.ipcChannel = ipc.getInstance().createChannel(Settings.instance.static(Settings.KEY_IPC_REMOTE_ADDRESS, "invalid"), kIPCIconChannel);
|
||||
this.ipcChannel = ipc.getIpcInstance().createChannel(Settings.instance.static(Settings.KEY_IPC_REMOTE_ADDRESS, "invalid"), kIPCIconChannel);
|
||||
this.ipcChannel.messageHandler = this.handleIpcMessage.bind(this);
|
||||
}
|
||||
|
||||
|
|
|
@ -49,16 +49,16 @@ export abstract class BasicIPCHandler {
|
|||
protected static readonly BROADCAST_UNIQUE_ID = "00000000-0000-4000-0000-000000000000";
|
||||
protected static readonly PROTOCOL_VERSION = 1;
|
||||
|
||||
protected _channels: IPCChannel[] = [];
|
||||
protected unique_id;
|
||||
protected registeredChannels: IPCChannel[] = [];
|
||||
protected localUniqueId: string;
|
||||
|
||||
protected constructor() { }
|
||||
|
||||
setup() {
|
||||
this.unique_id = uuidv4(); /* lets get an unique identifier */
|
||||
this.localUniqueId = uuidv4();
|
||||
}
|
||||
|
||||
getLocalAddress() { return this.unique_id; }
|
||||
getLocalAddress() : string { return this.localUniqueId; }
|
||||
|
||||
abstract sendMessage(type: string, data: any, target?: string);
|
||||
|
||||
|
@ -72,12 +72,12 @@ export abstract class BasicIPCHandler {
|
|||
request_query_id: (<ProcessQuery>message.data).query_id,
|
||||
request_timestamp: (<ProcessQuery>message.data).timestamp,
|
||||
|
||||
device_id: this.unique_id,
|
||||
device_id: this.localUniqueId,
|
||||
protocol: BasicIPCHandler.PROTOCOL_VERSION
|
||||
} as ProcessQueryResponse, message.sender);
|
||||
return;
|
||||
}
|
||||
} else if(message.receiver === this.unique_id) {
|
||||
} else if(message.receiver === this.localUniqueId) {
|
||||
if(message.type == "process-query-response") {
|
||||
const response: ProcessQueryResponse = message.data;
|
||||
if(this._query_results[response.request_query_id])
|
||||
|
@ -114,7 +114,7 @@ export abstract class BasicIPCHandler {
|
|||
const data: ChannelMessage = message.data;
|
||||
|
||||
let channel_invoked = false;
|
||||
for(const channel of this._channels) {
|
||||
for(const channel of this.registeredChannels) {
|
||||
if(channel.channelId === data.channel_id && (typeof(channel.targetClientId) === "undefined" || channel.targetClientId === message.sender)) {
|
||||
if(channel.messageHandler)
|
||||
channel.messageHandler(message.sender, message.receiver === BasicIPCHandler.BROADCAST_UNIQUE_ID, data);
|
||||
|
@ -136,8 +136,9 @@ export abstract class BasicIPCHandler {
|
|||
messageHandler: undefined,
|
||||
sendMessage: (type: string, data: any, target?: string) => {
|
||||
if(typeof target !== "undefined") {
|
||||
if(typeof channel.targetClientId === "string" && target != channel.targetClientId)
|
||||
if(typeof channel.targetClientId === "string" && target != channel.targetClientId) {
|
||||
throw "target id does not match channel target";
|
||||
}
|
||||
}
|
||||
|
||||
this.sendMessage("channel", {
|
||||
|
@ -148,14 +149,14 @@ export abstract class BasicIPCHandler {
|
|||
}
|
||||
};
|
||||
|
||||
this._channels.push(channel);
|
||||
this.registeredChannels.push(channel);
|
||||
return channel;
|
||||
}
|
||||
|
||||
channels() : IPCChannel[] { return this._channels; }
|
||||
channels() : IPCChannel[] { return this.registeredChannels; }
|
||||
|
||||
deleteChannel(channel: IPCChannel) {
|
||||
this._channels = this._channels.filter(e => e !== channel);
|
||||
this.registeredChannels = this.registeredChannels.filter(e => e !== channel);
|
||||
}
|
||||
|
||||
private _query_results: {[key: string]:ProcessQueryResponse[]} = {};
|
||||
|
@ -178,7 +179,7 @@ export abstract class BasicIPCHandler {
|
|||
register_certificate_accept_callback(callback: () => any) : string {
|
||||
const id = uuidv4();
|
||||
this._cert_accept_callbacks[id] = callback;
|
||||
return this.unique_id + ":" + id;
|
||||
return this.localUniqueId + ":" + id;
|
||||
}
|
||||
|
||||
private _cert_accept_succeeded: {[sender: string]:(() => any)} = {};
|
||||
|
@ -250,13 +251,17 @@ class BroadcastChannelIPC extends BasicIPCHandler {
|
|||
sendMessage(type: string, data: any, target?: string) {
|
||||
const message: BroadcastMessage = {} as any;
|
||||
|
||||
message.sender = this.unique_id;
|
||||
message.sender = this.localUniqueId;
|
||||
message.receiver = target ? target : BasicIPCHandler.BROADCAST_UNIQUE_ID;
|
||||
message.timestamp = Date.now();
|
||||
message.type = type;
|
||||
message.data = data;
|
||||
|
||||
this.channel.postMessage(JSON.stringify(message));
|
||||
if(message.receiver === this.localUniqueId) {
|
||||
this.handleMessage(message);
|
||||
} else {
|
||||
this.channel.postMessage(JSON.stringify(message));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -277,7 +282,7 @@ export function setup() {
|
|||
connect_handler.setup();
|
||||
}
|
||||
|
||||
export function getInstance() {
|
||||
export function getIpcInstance() {
|
||||
return handler;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@ import {
|
|||
TextToken,
|
||||
Token
|
||||
} from "remarkable/lib";
|
||||
import {escapeBBCode} from "../text/bbcode";
|
||||
import {tr} from "tc-shared/i18n/localize";
|
||||
|
||||
const { Remarkable } = require("remarkable");
|
||||
|
@ -29,7 +28,7 @@ export class MD2BBCodeRenderer {
|
|||
"hardbreak": () => "\n",
|
||||
|
||||
"paragraph_open": () => "",
|
||||
"paragraph_close": (_, token: ParagraphCloseToken) => token.tight ? "" : "[br]",
|
||||
"paragraph_close": (_, token: ParagraphCloseToken) => token.tight ? "" : "\n",
|
||||
|
||||
"strong_open": () => "[b]",
|
||||
"strong_close": () => "[/b]",
|
||||
|
@ -119,7 +118,7 @@ export class MD2BBCodeRenderer {
|
|||
if(tokens[index].lines?.length) {
|
||||
while(this.currentLineCount < tokens[index].lines[0]) {
|
||||
this.currentLineCount += 1;
|
||||
result += "[br]";
|
||||
result += "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,8 @@ import {ChannelTreePopoutController} from "tc-shared/ui/tree/popout/Controller";
|
|||
import {Settings, settings} from "tc-shared/settings";
|
||||
import {ClientIcon} from "svg-sprites/client-icons";
|
||||
|
||||
import "./EntryTagsHandler";
|
||||
|
||||
export interface ChannelTreeEvents {
|
||||
/* general tree notified */
|
||||
notify_tree_reset: {},
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
import * as loader from "tc-loader";
|
||||
import {Stage} from "tc-loader";
|
||||
import {getIpcInstance} from "tc-shared/ipc/BrowserIPC";
|
||||
import {LogCategory, logWarn} from "tc-shared/log";
|
||||
import {server_connections} from "tc-shared/ConnectionManager";
|
||||
|
||||
const kIpcChannel = "entry-tags";
|
||||
|
||||
function handleIpcMessage(type: string, payload: any) {
|
||||
switch (type) {
|
||||
case "contextmenu-client": {
|
||||
const {
|
||||
handlerId,
|
||||
|
||||
clientUniqueId,
|
||||
clientId,
|
||||
clientDatabaseId,
|
||||
|
||||
pageX,
|
||||
pageY
|
||||
} = payload;
|
||||
|
||||
if(typeof pageX !== "number" || typeof pageY !== "number") {
|
||||
logWarn(LogCategory.IPC, tr("Received client context menu action with an invalid page coordinated: %ox%o."), pageX, pageY);
|
||||
return;
|
||||
}
|
||||
|
||||
if(typeof handlerId !== "string") {
|
||||
logWarn(LogCategory.IPC, tr("Received client context menu action with an invalid handler id: %o."), handlerId);
|
||||
return;
|
||||
}
|
||||
|
||||
if(typeof clientUniqueId !== "string") {
|
||||
logWarn(LogCategory.IPC, tr("Received client context menu action with an invalid client unique id: %o."), clientUniqueId);
|
||||
return;
|
||||
}
|
||||
|
||||
if(clientId !== undefined && typeof clientId !== "number") {
|
||||
logWarn(LogCategory.IPC, tr("Received client context menu action with an invalid client id: %o."), clientId);
|
||||
return;
|
||||
}
|
||||
|
||||
if(clientDatabaseId !== undefined && typeof clientDatabaseId !== "number") {
|
||||
logWarn(LogCategory.IPC, tr("Received client context menu action with an invalid client database id: %o."), clientDatabaseId);
|
||||
return;
|
||||
}
|
||||
|
||||
const handler = server_connections.findConnection(handlerId);
|
||||
if(!handler) { return; }
|
||||
|
||||
let clients = handler.channelTree.clients.filter(client => client.properties.client_unique_identifier === clientUniqueId);
|
||||
if(clientId) {
|
||||
clients = clients.filter(client => client.clientId() === clientId);
|
||||
}
|
||||
if(clientDatabaseId) {
|
||||
clients = clients.filter(client => client.properties.client_database_id === clientDatabaseId);
|
||||
}
|
||||
|
||||
clients[0]?.showContextMenu(pageX, pageY);
|
||||
break;
|
||||
}
|
||||
case "contextmenu-channel": {
|
||||
const {
|
||||
handlerId,
|
||||
channelId,
|
||||
|
||||
pageX,
|
||||
pageY
|
||||
} = payload;
|
||||
|
||||
if(typeof pageX !== "number" || typeof pageY !== "number") {
|
||||
logWarn(LogCategory.IPC, tr("Received channel context menu action with an invalid page coordinated: %ox%o."), pageX, pageY);
|
||||
return;
|
||||
}
|
||||
|
||||
if(typeof handlerId !== "string") {
|
||||
logWarn(LogCategory.IPC, tr("Received channel context menu action with an invalid handler id: %o."), handlerId);
|
||||
return;
|
||||
}
|
||||
|
||||
if(typeof channelId !== "number") {
|
||||
logWarn(LogCategory.IPC, tr("Received channel context menu action with an invalid channel id: %o."), channelId);
|
||||
return;
|
||||
}
|
||||
|
||||
const handler = server_connections.findConnection(handlerId);
|
||||
const channel = handler?.channelTree.findChannel(channelId);
|
||||
channel?.showContextMenu(pageX, pageY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loader.register_task(Stage.JAVASCRIPT_INITIALIZING, {
|
||||
name: "entry tags",
|
||||
priority: 10,
|
||||
function: async () => {
|
||||
const channel = getIpcInstance().createChannel(undefined, kIpcChannel);
|
||||
channel.messageHandler = (_remoteId, _broadcast, message) => handleIpcMessage(message.type, message.data);
|
||||
}
|
||||
});
|
|
@ -29,7 +29,7 @@ export abstract class AbstractExternalModalController extends EventControllerBas
|
|||
this.modalType = modal;
|
||||
this.userData = userData;
|
||||
|
||||
this.ipcChannel = ipc.getInstance().createChannel();
|
||||
this.ipcChannel = ipc.getIpcInstance().createChannel();
|
||||
this.ipcChannel.messageHandler = this.handleIPCMessage.bind(this);
|
||||
|
||||
this.documentUnloadListener = () => this.destroy();
|
||||
|
@ -109,7 +109,7 @@ export abstract class AbstractExternalModalController extends EventControllerBas
|
|||
|
||||
this.doDestroyWindow();
|
||||
if(this.ipcChannel) {
|
||||
ipc.getInstance().deleteChannel(this.ipcChannel);
|
||||
ipc.getIpcInstance().deleteChannel(this.ipcChannel);
|
||||
}
|
||||
|
||||
this.destroyIPC();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {getInstance as getIPCInstance} from "../../../ipc/BrowserIPC";
|
||||
import {getIpcInstance as getIPCInstance} from "../../../ipc/BrowserIPC";
|
||||
import {Settings, SettingsKey} from "../../../settings";
|
||||
import {
|
||||
Controller2PopoutMessages, EventControllerBase,
|
||||
|
|
|
@ -1,23 +1,59 @@
|
|||
import * as React from "react";
|
||||
import * as loader from "tc-loader";
|
||||
import {Stage} from "tc-loader";
|
||||
import {getIpcInstance, IPCChannel} from "tc-shared/ipc/BrowserIPC";
|
||||
import {Settings} from "tc-shared/settings";
|
||||
|
||||
const kIpcChannel = "entry-tags";
|
||||
const cssStyle = require("./EntryTags.scss");
|
||||
|
||||
export const ClientTag = (props: { clientName: string, clientUniqueId: string, handlerId: string, clientId?: number, clientDatabaseId?: number, className?: string }) => {
|
||||
let ipcChannel: IPCChannel;
|
||||
|
||||
return (
|
||||
<div className={cssStyle.client + (props.className ? ` ${props.className}` : ``)}
|
||||
onContextMenu={event => {
|
||||
event.preventDefault();
|
||||
export const ClientTag = (props: { clientName: string, clientUniqueId: string, handlerId: string, clientId?: number, clientDatabaseId?: number, className?: string }) => (
|
||||
<div className={cssStyle.client + (props.className ? ` ${props.className}` : ``)}
|
||||
onContextMenu={event => {
|
||||
event.preventDefault();
|
||||
|
||||
/* TODO: Enable context menus */
|
||||
}}
|
||||
>
|
||||
{props.clientName}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
ipcChannel.sendMessage("contextmenu-client", {
|
||||
clientUniqueId: props.clientUniqueId,
|
||||
handlerId: props.handlerId,
|
||||
clientId: props.clientId,
|
||||
clientDatabaseId: props.clientDatabaseId,
|
||||
|
||||
export const ChannelTag = (props: { channelName: string, channelId: number, handlerId: string, className?: string }) => {
|
||||
pageX: event.pageX,
|
||||
pageY: event.pageY
|
||||
});
|
||||
}}
|
||||
>
|
||||
{props.clientName}
|
||||
</div>
|
||||
);
|
||||
|
||||
return <div className={cssStyle.client + (props.className ? ` ${props.className}` : ``)}>{props.channelName}</div>;
|
||||
};
|
||||
export const ChannelTag = (props: { channelName: string, channelId: number, handlerId: string, className?: string }) => (
|
||||
<div
|
||||
className={cssStyle.client + (props.className ? ` ${props.className}` : ``)}
|
||||
onContextMenu={event => {
|
||||
event.preventDefault();
|
||||
|
||||
ipcChannel.sendMessage("contextmenu-channel", {
|
||||
handlerId: props.handlerId,
|
||||
channelId: props.channelId,
|
||||
|
||||
pageX: event.pageX,
|
||||
pageY: event.pageY
|
||||
});
|
||||
}}
|
||||
>
|
||||
{props.channelName}
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
loader.register_task(Stage.JAVASCRIPT_INITIALIZING, {
|
||||
name: "entry tags",
|
||||
priority: 10,
|
||||
function: async () => {
|
||||
const ipc = getIpcInstance();
|
||||
ipcChannel = ipc.createChannel(Settings.instance.static(Settings.KEY_IPC_REMOTE_ADDRESS, ipc.getLocalAddress()), kIpcChannel);
|
||||
}
|
||||
});
|
|
@ -87,7 +87,7 @@ export class ExternalModalController extends AbstractExternalModalController {
|
|||
"chunk": "modal-external",
|
||||
"modal-target": this.modalType,
|
||||
"ipc-channel": this.ipcChannel.channelId,
|
||||
"ipc-address": ipc.getInstance().getLocalAddress(),
|
||||
"ipc-address": ipc.getIpcInstance().getLocalAddress(),
|
||||
"disableGlobalContextMenu": __build.mode === "debug" ? 1 : 0,
|
||||
"loader-abort": __build.mode === "debug" ? 1 : 0,
|
||||
};
|
||||
|
|
|
@ -26,7 +26,7 @@ class IPCContextMenu implements ContextMenuFactory {
|
|||
private closeCallback: () => void;
|
||||
|
||||
constructor() {
|
||||
this.ipcChannel = ipc.getInstance().createChannel(undefined, kIPCContextMenuChannel);
|
||||
this.ipcChannel = ipc.getIpcInstance().createChannel(undefined, kIPCContextMenuChannel);
|
||||
this.ipcChannel.messageHandler = this.handleIpcMessage.bind(this);
|
||||
|
||||
/* if we're just created we're the focused window ;) */
|
||||
|
|
Loading…
Reference in New Issue