diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 1bf62ecf..18714acb 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -6,6 +6,5 @@ "context": "..", "dockerfile": "./Dockerfile" }, - "forwardPorts": [8282], - "runArgs": ["--publish=8282:8282"] + "forwardPorts": [8282] } diff --git a/assets/chat/css/style.scss b/assets/chat/css/style.scss index 65b982ca..e157edc8 100644 --- a/assets/chat/css/style.scss +++ b/assets/chat/css/style.scss @@ -954,11 +954,6 @@ a.flair12:hover { background-color: $color-chat-highlight; } -.msg-highlight-reply { - color: #CCDCD1 !important; - background-color: #224E61 !important; -} - /* Focus or highlight a line */ .focus-user .msg-chat { opacity:0.3; @@ -1816,72 +1811,3 @@ button.btn { display: block; font-size: 10px; } - -.msg-reply-preview { - font-size: 0.85em; - color: #888; - margin-bottom: 2px; - - .reply-arrow { - margin-right: 4px; - color: #666; - } - - .reply-label { - margin-right: 2px; - color: #aaa; - } - - .reply-user { - font-weight: 600; - color: #ccc; - margin: 0 2px; - } - - .reply-text { - color: #bbb; - font-style: italic; - } -} - -#chat-reply-banner { - background: #030303; - border: 1px solid #321a10; - border-top-left-radius: 6px; - border-top-right-radius: 6px; - padding: $chat-gutter-sm; - display: flex; - align-items: center; - justify-content: space-between; - font-size: $text-size-sm; - color: $color-chat-text2; - position: relative; - z-index: 220; - box-shadow: 0px -1px 4px rgba(black, 0.3); - white-space: nowrap; - text-overflow: ellipsis; -} - -#chat-reply-container { - display: flex; -} - -#chat-reply-user { - color: $color-chat-text1; - font-weight: 500; - margin-left: 5px; -} - -.chat-reply-cancel { - cursor: pointer; - display: flex; - font-size: 20px; - align-items: center; - color: $color-chat-text3; - transition: color 0.2s ease; - - - &:hover { - color: $color-chat-text1; - } -} diff --git a/assets/chat/js/chat.js b/assets/chat/js/chat.js index d1b691c8..132f8515 100644 --- a/assets/chat/js/chat.js +++ b/assets/chat/js/chat.js @@ -188,7 +188,6 @@ const commandsinfo = new Map([ ], ["unhideemote", { desc: "Unhide a hidden emote." }], ["spoiler", { desc: "Wraps a message in the spoiler tags `||`." }], - ["reply", { desc: "Reply to a user's most recent message." }], ]); const banstruct = { id: 0, @@ -264,7 +263,6 @@ class Chat { this.source.on("NAMES", data => this.onNAMES(data)); this.source.on("QUIT", data => this.onQUIT(data)); this.source.on("MSG", data => this.onMSG(data)); - this.source.on("MSGREPLY", data => this.onREPLY(data)); this.source.on("MUTE", data => this.onMUTE(data)); this.source.on("UNMUTE", data => this.onUNMUTE(data)); this.source.on("BAN", data => this.onBAN(data)); @@ -319,7 +317,6 @@ class Chat { this.cmdHIDEEMOTE(data, "UNHIDEEMOTE") ); this.control.on("SPOILER", data => this.cmdSPOILER(data)) - this.control.on("REPLY", data => this.cmdREPLY(data)) notificationSound.loadConfig(); } @@ -444,25 +441,6 @@ class Chat { e.stopPropagation(); if (!this.authenticated) { this.loginscrn.show(); - return; - } - if (this.input.hasClass("invalid-msg-warning")) return; - - const text = this.input.val().toString().trim(); - if (!text) return; - - const prevMessageId = $("#chat-reply-banner").data("replyTo"); - const prevText = $("#chat-reply-banner").data("prevText"); - const targetUser = $("#chat-reply-banner").data("targetUser"); - - if (prevMessageId && prevText && targetUser) { - // Build the MSGREPLY payload - this.source.emit("MSGREPLY", { data: text, nick: this.user.nick, target: targetUser.nick, prev: prevText, prevMessageId: prevMessageId }); - - // Clear banner state - $("#chat-reply-banner").hide().removeData("replyTo").removeData("prevText").removeData("targetUser"); - $("#chat-reply-user").text(""); - this.input.val("").trigger("input"); } else { // don't do anything if the message is marked invalid client-side (currently only when the message is too long) if (!this.input.hasClass("invalid-msg-warning")) { @@ -563,33 +541,6 @@ class Chat { } }); - // Right click a reply to scroll to the orginal message - this.ui.on("contextmenu", ".msg-reply-preview", function (e) { - e.preventDefault(); - - const preview = $(this); // the reply preview div - const targetId = preview.data("reply-to"); // uses data-reply-to attr - - if (targetId) { - const original = $(`[data-msg-id="${targetId}"]`); - - if (original.length) { - original[0].scrollIntoView({ behavior: "smooth", block: "center" }); - - // temporary highlight - original.addClass("msg-highlight-reply"); - setTimeout(() => original.removeClass("msg-highlight-reply"), 1500); - } else { - console.log("Original message not found in DOM:", targetId); - } - } - }); - - // Cancel a reply to someone - this.ui.on("click", ".chat-reply-cancel", () => { - $("#chat-reply-banner").hide().removeData("replyTo").removeData("prevText").removeData("targetUser"); - }); - // Visibility document.addEventListener( "visibilitychange", @@ -1000,35 +951,21 @@ class Chat { win.lastmessage.user && win.lastmessage.user.username.toLowerCase() === message.user.username.toLowerCase(); - // Gets mentions from message and a reply mentions - message.mentioned = [ - ...Chat.extractNicks(message.message), - ...(message.prevMessage ? Chat.extractNicks(message.prevMessage) : []) - ].reduce((m, a) => { + // get mentions from message + message.mentioned = Chat.extractNicks(message.message).reduce((m, a) => { const user = this.users.get(a.toLowerCase()); - if (user && !m.includes(user.nick)) { - m.push(user.nick); - } - return m; + return user ? [...m, user.nick] : m; }, []); - // add replytarget nick if present - if (message.replytarget?.nick && !message.mentioned.includes(message.replytarget.nick)) { - message.mentioned.push(message.replytarget.nick); - } - // set tagged state message.tag = this.taggednicks.get(message.user.nick.toLowerCase()); // set highlighted state if this is not the current users message or a bot, as well as other highlight criteria message.highlighted = !message.isown && !message.user.hasFeature(UserFeatures.BOT) && - ( - // Highlight if the replytarget is the current user - (message.replytarget?.username === this.user.username) || - // Check current user nick against msg.message (if highlight setting is on) - (this.regexhighlightself && - this.settings.get("highlight") && - this.regexhighlightself.test(message.message)) || + // Check current user nick against msg.message (if highlight setting is on) + ((this.regexhighlightself && + this.settings.get("highlight") && + this.regexhighlightself.test(message.message)) || // Check /highlight nicks against msg.nick (this.regexhighlightnicks && this.regexhighlightnicks.test(message.user.username)) || @@ -1311,21 +1248,6 @@ class Chat { } } - onREPLY(data) { - const user = this.users.get(data.nick.toLowerCase()); - const target = this.users.get(data.target.toLowerCase()); - - MessageBuilder.reply( - data.data, // current message - user, // sender user object - target, // target user object - data.prev, // previoustext - data.prevMessageId, // previoustext - data.messageId, // optional message ID - data.timestamp // optional timestamp - ).into(this); - } - onMUTE(data) { // data.data is the nick which has been banned, no info about duration if (this.user.username.toLowerCase() === data.data.toLowerCase()) { @@ -2064,58 +1986,6 @@ class Chat { this.control.emit("SEND", `|| ${data.join(' ')} ||`) } - findLastMessageByUser({ nick, id }, win = this.getActiveWindow()) { - const children = win.getlines(); - - for (let i = children.length - 1; i >= 0; i--) { - const line = $(children[i]); - const msg = line.data("message"); - - if (!msg) continue; - - // Match by ID first - if (id && msg.id === id) { - return msg; - } - - // Match by nickname - if (nick && msg.user && msg.user.nick.toLowerCase() === nick.toLowerCase()) { - return msg; - } - } - - return null; - } - - - cmdREPLY(parts) { - if (!parts[0] || !nickregex.test(parts[0])) { - MessageBuilder.error("Usage: /reply ").into(this); - return; - } - - const targetNick = parts[0]; - const replyText = parts.slice(1).join(" "); - - if (!replyText) { - MessageBuilder.error("Reply message cannot be empty").into(this); - return; - } - - // Find the last message from that user in the active window - const prevMessage = this.findLastMessageByUser({ nick: targetNick }); - if (!prevMessage) { - MessageBuilder.error(`No recent message found from ${targetNick}`).into(this); - return; - } - - this.source.emit("MSGREPLY", { data: replyText, nick: this.user.nick, target: targetNick, prev: prevMessage.message, prevMessageId: prevMessage.msgid }); - - // Add to input history - this.inputhistory.add(`/reply ${targetNick} ${replyText}`); - } - - openConversation(nick) { const normalized = nick.toLowerCase(); diff --git a/assets/chat/js/menus.js b/assets/chat/js/menus.js index a691f639..886500b5 100644 --- a/assets/chat/js/menus.js +++ b/assets/chat/js/menus.js @@ -686,25 +686,6 @@ class ChatContextMenu { .focus() .val(`/whisper ${this.targetUsername} `) }) - - this.button.reply = this.addButton("contextmenu-reply", (id, e) => { - const msgChat = $(this.event.currentTarget).closest(".msg-chat"); - const msgObj = msgChat.data("message"); - const prevId = msgChat.attr("data-msg-id") || (msgObj && msgObj.id); - const targetUser = msgObj && msgObj.user; - const prevText = msgObj && msgObj.message; - - if (!prevId || !targetUser || !prevText) return; - - $("#chat-reply-user").text(targetUser.username ?? targetUser); - $("#chat-reply-banner") - .data("replyTo", prevId) - .data("prevText", prevText) - .data("targetUser", targetUser) - .show(); - - $("#chat-input-control").focus(); - }); if (this.chat.settings.get("highlightnicks").includes(this.targetUsername.toLowerCase())) { this.button.highlight = this.addButton("contextmenu-unhighlight", (id, e) => { diff --git a/assets/chat/js/messages.js b/assets/chat/js/messages.js index e616bac1..b9f38236 100644 --- a/assets/chat/js/messages.js +++ b/assets/chat/js/messages.js @@ -217,10 +217,6 @@ class MessageBuilder { return new ChatUserMessage(message, user, timestamp); } - static reply(message, user, target, prevMessage, prevMessageId, messageId = null, timestamp = null) { - return new ChatReplyMessage(message, user, target, prevMessage, prevMessageId, messageId, timestamp); - } - static emote(emote, timestamp, count = 1) { return new ChatEmoteMessage(emote, timestamp, count); } @@ -310,7 +306,6 @@ class ChatUserMessage extends ChatMessage { super(message, timestamp, MessageTypes.USER); this.user = user; this.id = null; - this.msgid = Date.now().toString() + Math.floor(Math.random() * 1000); this.isown = false; this.highlighted = false; this.historical = false; @@ -325,7 +320,6 @@ class ChatUserMessage extends ChatMessage { const classes = [], attr = {}; - if (this.msgid) attr["data-msg-id"] = this.msgid; if (this.id) attr["data-id"] = this.id; if (this.user && this.user.username) attr["data-username"] = this.user.username.toLowerCase(); @@ -370,56 +364,6 @@ class ChatUserMessage extends ChatMessage { } } -class ChatReplyMessage extends ChatUserMessage { - constructor(message, user, target, prevMessage, prevMessageId, messageId = null, timestamp = null) { - super(message, user, timestamp); - this.prevMessage = prevMessage; - this.prevMessageId = prevMessageId; - this.replytarget = target; - this.msgid = messageId ?? Date.now().toString() + Math.floor(Math.random() * 1000); - this.isown = false; - this.highlighted = false; - this.historical = false; - this.targetoutgoing = null; - this.tag = null; - this.slashme = false; - this.mentioned = []; - } - html(chat = null) { - const classes = [], - attr = {}; - if (this.msgid) attr["data-msg-id"] = this.msgid; - if (this.user && this.user.username) - attr["data-username"] = this.user.username.toLowerCase(); - if (this.mentioned && this.mentioned.length > 0) - attr["data-mentioned"] = this.mentioned.join(" ").toLowerCase(); - - if (this.isown) classes.push("msg-own"); - if (this.slashme && !this.target && !this.targetoutgoing) - classes.push("msg-me"); - if (this.historical) classes.push("msg-historical"); - if (this.highlighted) classes.push("msg-highlight"); - // Cuts the message limit into a quater - const prevPreview = this.prevMessage.length > 128 ? this.prevMessage.substring(0, 128) + "…" : this.prevMessage; - // Previous message block - // Possable problem getting the target username here - const replyBlock = ` -
- Replying to - ${this.replytarget.username ?? this.replytarget}: - ${prevPreview}
`; - - // Actual message - const background = generateViewerStateBackground(this.user.viewerState); - const viewerStateProps = `title="${this.user.viewerState.getTitle()}" style="background-image: url(${background});" data-viewer-state="${JSON.stringify( - this.user.viewerState).replace(/"/g, """)}")}"`; - const user = buildFeatures(this.user) + `${this.user.username}`; - const combined = ` ${user}: ` + buildMessageTxt(chat, this); - - return this.wrap(replyBlock + buildTime(this) + combined, classes, attr); - } -} - const vsScratchCanvas = document.createElement("canvas"); function generateViewerStateBackground(viewerState) { vsScratchCanvas.height = 20; diff --git a/assets/chat/js/window.js b/assets/chat/js/window.js index f6a3171b..71f93967 100644 --- a/assets/chat/js/window.js +++ b/assets/chat/js/window.js @@ -71,7 +71,6 @@ class ChatWindow extends EventEmitter { addMessage(chat, message) { message.ui = $(message.html(chat)); - message.ui.data("message", message); message.afterRender(chat); this.lastmessage = message; this.lines.append(message.ui); diff --git a/assets/dev/dev-chat/messages/MockStream.js b/assets/dev/dev-chat/messages/MockStream.js index f6b0ca5f..7efea9a6 100644 --- a/assets/dev/dev-chat/messages/MockStream.js +++ b/assets/dev/dev-chat/messages/MockStream.js @@ -69,10 +69,6 @@ export default class MockStream { data.nick = username; this.server.emit("message", `MSG ${JSON.stringify(data)}`); } - else if (eventname === "MSGREPLY") { - data.nick = username; - this.server.emit("MSGREPLY", `MSGREPLY ${JSON.stringify(data)}`); - } }); }); } @@ -115,18 +111,6 @@ export default class MockStream { }); } - sendReply(nick, target, message, prevMessage, prevmId, messageId) { - const messageObject = { - nick: nick, - target: target, - data: message, - prev: prevMessage, - prevMessageId: prevmId, - messageId: messageId - }; - this.server.emit("message", `MSGREPLY ${JSON.stringify(messageObject)}`); - } - sendMessage(nick, message, type = "MSG") { const messageObject = { nick, @@ -209,50 +193,4 @@ export default class MockStream { return this.sendMessages(messages, "combo"); } - conversation() { - const user1 = "Ghostface"; - const user2 = "FrostedJimmy"; - - // Fake convo between 2 people to display replies - this.sendMessage( - user1, - "Yall see the speed boost after DRS on Strims!?" - ); - - this.sendReply( - user2, - user1, - "Strims’ DRS was wild, like 10 km/h gain down the straight! But Memlabs’ DRS felt even quicker, no?", - "Yall see the speed boost after DRS on Strims!?", - "0001", - "0002" - ); - - this.sendReply( - user1, - user2, - "Memlabs’ DRS is nuts, prob hitting 12 km/h extra. Their rear wing flap opens wider, I bet. Strims still owns the corners though.", - "Strims’ DRS was wild, like 10 km/h gain down the straight! But Memlabs’ DRS felt even quicker, no?", - "0002", - "0003" - ); - - this.sendReply( - user2, - user1, - "True, Strims’ cornering is unreal—those high-downforce wings grip like glue in Turn 9. Memlabs slides a bit there.", - "Memlabs’ DRS is nuts, prob hitting 12 km/h extra. Their rear wing flap opens wider, I bet. Strims still owns the corners though.", - "0003", - "0004" - ); - - this.sendReply( - user1, - user2, - "Yeah, Strims nails corners with that downforce, but Memlabs’ DRS speed on the straight might clinch the win next time!", - "True, Strims’ cornering is unreal—those high-downforce wings grip like glue in Turn 9. Memlabs slides a bit there.", - "0004", - "0005" - ); - } } diff --git a/assets/index.html b/assets/index.html index bbde52f5..6d383b86 100644 --- a/assets/index.html +++ b/assets/index.html @@ -24,11 +24,6 @@ -
- -
-
@@ -89,7 +75,7 @@ -
+
Message too long!