diff --git a/ChangeLog.md b/ChangeLog.md index 164f2b8f..a3067ff5 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,4 +1,11 @@ # Changelog: +* **15.02.21** + - Fixed critical bug within the event registry class + - Added a dropdown for the microphone control button to quickly change microphones + - Fixed the microphone settings microphone selection (The default device wasn't selected) + - Adding a hint whatever the device is the default device or not + - Fixed issue [#169](https://github.com/TeaSpeak/TeaWeb/issues/169) (Adding permissions dosn't work for TS3 server) + - Fixed issue [#166](https://github.com/TeaSpeak/TeaWeb/issues/166) (Private conversations are not accessible when IndexDB could not be opened) * **22.01.21** - Allowing the user to easily change the channel name mode - Fixed channel name mode parsing diff --git a/shared/js/settings.ts b/shared/js/settings.ts index df25b3ce..5288ff3c 100644 --- a/shared/js/settings.ts +++ b/shared/js/settings.ts @@ -495,6 +495,12 @@ export class Settings { valueType: "string", }; + static readonly KEY_CHAT_LAST_USED_EMOJI: ValuedRegistryKey = { + key: "chat_last_used_emoji", + defaultValue: ":joy:", + valueType: "string", + }; + static readonly KEY_SWITCH_INSTANT_CHAT: ValuedRegistryKey = { key: "switch_instant_chat", defaultValue: true, diff --git a/shared/js/text/bbcode/EmojiUtil.ts b/shared/js/text/bbcode/EmojiUtil.ts new file mode 100644 index 00000000..4a63bd68 --- /dev/null +++ b/shared/js/text/bbcode/EmojiUtil.ts @@ -0,0 +1,28 @@ +function toCodePoint(unicodeSurrogates) { + let r = [], + c = 0, + p = 0, + i = 0; + while (i < unicodeSurrogates.length) { + c = unicodeSurrogates.charCodeAt(i++); + if (p) { + r.push((0x10000 + ((p - 0xD800) << 10) + (c - 0xDC00)).toString(16)); + p = 0; + } else if (0xD800 <= c && c <= 0xDBFF) { + p = c; + } else { + r.push(c.toString(16)); + } + } + return r.join("-"); +} + +const U200D = String.fromCharCode(0x200D); +const UFE0Fg = /\uFE0F/g; +export function getTwenmojiHashFromNativeEmoji(emoji: string) : string { + // if variant is present as \uFE0F + return toCodePoint(emoji.indexOf(U200D) < 0 ? + emoji.replace(UFE0Fg, '') : + emoji + ); +} \ No newline at end of file diff --git a/shared/js/text/bbcode/emoji.tsx b/shared/js/text/bbcode/emoji.tsx index 52e5d3c5..e62029d7 100644 --- a/shared/js/text/bbcode/emoji.tsx +++ b/shared/js/text/bbcode/emoji.tsx @@ -7,6 +7,7 @@ import ReactRenderer from "vendor/xbbcode/renderer/react"; import {Settings, settings} from "tc-shared/settings"; import * as emojiRegex from "emoji-regex"; +import {getTwenmojiHashFromNativeEmoji} from "tc-shared/text/bbcode/EmojiUtil"; const emojiRegexInstance = (emojiRegex as any)() as RegExp; @@ -15,39 +16,11 @@ loader.register_task(loader.Stage.JAVASCRIPT_INITIALIZING, { function: async () => { let reactId = 0; - function toCodePoint(unicodeSurrogates) { - let r = [], - c = 0, - p = 0, - i = 0; - while (i < unicodeSurrogates.length) { - c = unicodeSurrogates.charCodeAt(i++); - if (p) { - r.push((0x10000 + ((p - 0xD800) << 10) + (c - 0xDC00)).toString(16)); - p = 0; - } else if (0xD800 <= c && c <= 0xDBFF) { - p = c; - } else { - r.push(c.toString(16)); - } - } - return r.join("-"); - } - - const U200D = String.fromCharCode(0x200D); - const UFE0Fg = /\uFE0F/g; - function grabTheRightIcon(rawText) { - // if variant is present as \uFE0F - return toCodePoint(rawText.indexOf(U200D) < 0 ? - rawText.replace(UFE0Fg, '') : - rawText - ); - } - rendererReact.setTextRenderer(new class extends ElementRenderer { render(element: TextElement, renderer: ReactRenderer): React.ReactNode { - if(!settings.getValue(Settings.KEY_CHAT_COLORED_EMOJIES)) + if(!settings.getValue(Settings.KEY_CHAT_COLORED_EMOJIES)) { return element.text(); + } let text = element.text(); emojiRegexInstance.lastIndex = 0; @@ -59,13 +32,15 @@ loader.register_task(loader.Stage.JAVASCRIPT_INITIALIZING, { let match = emojiRegexInstance.exec(text); const rawText = text.substring(lastIndex, match?.index); - if(rawText) + if(rawText) { result.push(renderer.renderAsText(rawText, false)); + } - if(!match) + if(!match) { break; + } - let hash = grabTheRightIcon(match[0]); + let hash = getTwenmojiHashFromNativeEmoji(match[0]); result.push({match[0]}); lastIndex = match.index + match[0].length; } diff --git a/shared/js/ui/react-elements/ChatBox.scss b/shared/js/ui/react-elements/ChatBox.scss index a1ce7dc0..be4607c6 100644 --- a/shared/js/ui/react-elements/ChatBox.scss +++ b/shared/js/ui/react-elements/ChatBox.scss @@ -75,6 +75,13 @@ html:root { > img { height: 100%; width: 100%; + + align-self: center; + + &.emoji { + width: 1.25em; + height: 1.25em; + } } } diff --git a/shared/js/ui/react-elements/ChatBox.tsx b/shared/js/ui/react-elements/ChatBox.tsx index 852cfe4c..8f3b2ec1 100644 --- a/shared/js/ui/react-elements/ChatBox.tsx +++ b/shared/js/ui/react-elements/ChatBox.tsx @@ -3,9 +3,12 @@ import {useEffect, useRef, useState} from "react"; import {Registry} from "tc-shared/events"; import '!style-loader!css-loader!emoji-mart/css/emoji-mart.css' -import {Picker} from 'emoji-mart' +import {Picker, emojiIndex} from 'emoji-mart' import {settings, Settings} from "tc-shared/settings"; import {Translatable} from "tc-shared/ui/react-elements/i18n"; +import {getTwenmojiHashFromNativeEmoji} from "tc-shared/text/bbcode/EmojiUtil"; +import {BaseEmoji} from "emoji-mart"; +import {useGlobalSetting} from "tc-shared/ui/react-elements/Helper"; const cssStyle = require("./ChatBox.scss"); @@ -24,6 +27,18 @@ interface ChatBoxEvents { notify_typing: {} } +const LastUsedEmoji = () => { + const settingValue = useGlobalSetting(Settings.KEY_CHAT_LAST_USED_EMOJI); + const lastEmoji: BaseEmoji = (emojiIndex.emojis[settingValue] || emojiIndex.emojis["joy"]) as any; + if(!lastEmoji?.native) { + return {""}; + } + + return ( + {lastEmoji.native} + ) +} + const EmojiButton = (props: { events: Registry }) => { const [ shown, setShown ] = useState(false); const [ enabled, setEnabled ] = useState(false); @@ -56,7 +71,7 @@ const EmojiButton = (props: { events: Registry }) => { return (
enabled && setShown(true)}> - {""} +
{!shown ? undefined : @@ -72,6 +87,7 @@ const EmojiButton = (props: { events: Registry }) => { onSelect={(emoji: any) => { if(enabled) { + settings.setValue(Settings.KEY_CHAT_LAST_USED_EMOJI, emoji.id as string); props.events.fire("action_insert_text", { text: emoji.native, focus: true }); } }} @@ -352,13 +368,15 @@ export class ChatBox extends React.Component { } render() { - return
-
- - + return ( +
+
+ + +
+
- -
+ ) } componentDidUpdate(prevProps: Readonly, prevState: Readonly, snapshot?: any): void { diff --git a/web/app/connection/ServerConnection.ts b/web/app/connection/ServerConnection.ts index 696b6b42..d959dfb0 100644 --- a/web/app/connection/ServerConnection.ts +++ b/web/app/connection/ServerConnection.ts @@ -536,4 +536,9 @@ export class ServerConnection extends AbstractServerConnection { getControlStatistics(): ConnectionStatistics { return this.socket?.getControlStatistics() || { bytesSend: 0, bytesReceived: 0 }; } + + getServerType(): "teaspeak" | "teamspeak" | "unknown" { + /* It's simple. Only TeaSpeak support web clients */ + return "teaspeak"; + } } \ No newline at end of file