Emojis, Markdown and better file uploading
This commit is contained in:
		| @@ -110,7 +110,7 @@ | ||||
|                         </button> | ||||
|                     </div> | ||||
|                     <div class="message-input-wrapper"> | ||||
|                         <input type="text" id="messageInput" placeholder="Send a message..." autofocus> | ||||
|                         <textarea style="font-family: sans-serif" id="messageInput" placeholder="Send a message..." autofocus></textarea> | ||||
|                         <button class="send-button" onclick="sendMessage()"> | ||||
|                             <i class="fa-solid fa-paper-plane"></i> | ||||
|                         </button> | ||||
|   | ||||
| @@ -24,10 +24,17 @@ document.addEventListener('DOMContentLoaded', function() { | ||||
|             chatHeader.insertBefore(menuToggle, chatHeader.firstChild); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     document.getElementById('messageInput').addEventListener('input', function () { | ||||
|         this.style.height = 'auto'; | ||||
|         this.style.height = (this.scrollHeight) + 'px'; | ||||
|     }); | ||||
|  | ||||
|      | ||||
|     // Add event listeners | ||||
|     document.getElementById('messageInput').addEventListener('keypress', (event) => { | ||||
|         if (event.key === 'Enter') { | ||||
|     document.getElementById('messageInput').addEventListener('keydown', function(event) { | ||||
|         if (event.key === 'Enter' && !event.shiftKey) { | ||||
|             event.preventDefault(); | ||||
|             sendMessage(); | ||||
|         } | ||||
|     }); | ||||
| @@ -264,6 +271,218 @@ function resetLoginButton() { | ||||
|     } | ||||
| } | ||||
|  | ||||
| function markdownToHtmlDiv(markdown) { | ||||
|   // Emoji mapping | ||||
|   const emojiMap = { | ||||
|       // 😀 Faces | ||||
|       smile: '😄', | ||||
|       happy: '😊', | ||||
|       grin: '😁', | ||||
|       laugh: '😂', | ||||
|       joy: '🤣', | ||||
|       wink: '😉', | ||||
|       blush: '☺️', | ||||
|       cool: '😎', | ||||
|       smirk: '😏', | ||||
|       thinking: '🤔', | ||||
|       neutral: '😐', | ||||
|       expressionless: '😑', | ||||
|       sleepy: '😴', | ||||
|       dizzy: '😵', | ||||
|       surprised: '😲', | ||||
|       scream: '😱', | ||||
|       cry: '😢', | ||||
|       sob: '😭', | ||||
|       angry: '😠', | ||||
|       rage: '😡', | ||||
|       yum: '😋', | ||||
|       relieved: '😌', | ||||
|       confused: '😕', | ||||
|       nerd: '🤓', | ||||
|       zany: '🤪', | ||||
|       shush: '🤫', | ||||
|       hush: '🤐', | ||||
|  | ||||
|       // ❤️ Emotions | ||||
|       heart: '❤️', | ||||
|       heartbroken: '💔', | ||||
|       love: '😍', | ||||
|       kiss: '😘', | ||||
|       hug: '🤗', | ||||
|       clap: '👏', | ||||
|       pray: '🙏', | ||||
|       ok: '👌', | ||||
|       fingerscrossed: '🤞', | ||||
|       thumbsup: '👍', | ||||
|       thumbsdown: '👎', | ||||
|       eyes: '👀', | ||||
|  | ||||
|       // 🔥 Reactions | ||||
|       fire: '🔥', | ||||
|       100: '💯', | ||||
|       poop: '💩', | ||||
|       poo: '💩', | ||||
|       skull: '💀', | ||||
|       explosion: '💥', | ||||
|       mindblown: '🤯', | ||||
|       party: '🥳', | ||||
|       tada: '🎉', | ||||
|       balloon: '🎈', | ||||
|  | ||||
|       // 🐶 Animals | ||||
|       chicken: '🐔', | ||||
|       dog: '🐶', | ||||
|       cat: '🐱', | ||||
|       fox: '🦊', | ||||
|       panda: '🐼', | ||||
|       pig: '🐷', | ||||
|       cow: '🐮', | ||||
|       rabbit: '🐰', | ||||
|       bear: '🐻', | ||||
|       unicorn: '🦄', | ||||
|       monkey: '🐒', | ||||
|       dragon: '🐉', | ||||
|       snake: '🐍', | ||||
|  | ||||
|       // 🍔 Food & Drink | ||||
|       pizza: '🍕', | ||||
|       burger: '🍔', | ||||
|       fries: '🍟', | ||||
|       hotdog: '🌭', | ||||
|       taco: '🌮', | ||||
|       ramen: '🍜', | ||||
|       sushi: '🍣', | ||||
|       icecream: '🍨', | ||||
|       cake: '🎂', | ||||
|       coffee: '☕', | ||||
|       tea: '🍵', | ||||
|       beer: '🍺', | ||||
|  | ||||
|       // 🌍 Nature & Weather | ||||
|       sun: '☀️', | ||||
|       moon: '🌙', | ||||
|       star: '⭐', | ||||
|       cloud: '☁️', | ||||
|       rain: '🌧️', | ||||
|       snow: '❄️', | ||||
|       lightning: '⚡', | ||||
|       rainbow: '🌈', | ||||
|       tree: '🌳', | ||||
|       flower: '🌸', | ||||
|  | ||||
|       // ⚽ Activities | ||||
|       soccer: '⚽', | ||||
|       basketball: '🏀', | ||||
|       football: '🏈', | ||||
|       baseball: '⚾', | ||||
|       tennis: '🎾', | ||||
|       bowling: '🎳', | ||||
|       video_game: '🎮', | ||||
|       chess: '♟️', | ||||
|       music: '🎵', | ||||
|       guitar: '🎸', | ||||
|       mic: '🎤', | ||||
|  | ||||
|       // 💡 Objects & Symbols | ||||
|       lightbulb: '💡', | ||||
|       phone: '📱', | ||||
|       laptop: '💻', | ||||
|       bomb: '💣', | ||||
|       money: '💰', | ||||
|       star2: '🌟', | ||||
|       warning: '⚠️', | ||||
|       check: '✅', | ||||
|       x: '❌', | ||||
|       question: '❓', | ||||
|       exclamation: '❗', | ||||
|       infinity: '♾️', | ||||
|       hourglass: '⏳', | ||||
|       clock: '🕒', | ||||
|  | ||||
|       pepe: '🐸', | ||||
|       troll: '😈', | ||||
|       sus: '🧐', | ||||
|       amongus: '🟥', | ||||
|       monke: '🐵', | ||||
|       chad: '🦍', | ||||
|       gigachad: '💪', | ||||
|       wojak: '😔', | ||||
|       feelsbadman: '😞', | ||||
|       feelsgoodman: '😌', | ||||
|       yikes: '😬', | ||||
|       clown: '🤡', | ||||
|       clownworld: '🌎🤡', | ||||
|       triggered: '😡', | ||||
|       pog: '😲', | ||||
|       kek: '🤣', | ||||
|       based: '😎', | ||||
|       cringe: '😖', | ||||
|       dab: '🕺', | ||||
|       sigma: '🧠', | ||||
|       npc: '🤖', | ||||
|       doomer: '🌑', | ||||
|       zoomer: '⚡', | ||||
|       boomer: '👴', | ||||
|       sheesh: '😤', | ||||
|       rickroll: '🕺🎶', | ||||
|       trolled: '🧌', | ||||
|       rekt: '💀', | ||||
|       skillissue: '📉', | ||||
|       bro: '🙄', | ||||
|       cope: '😢', | ||||
|       ratio: '➗', | ||||
|       amogus: '👁️👄👁️', | ||||
|  | ||||
| }; | ||||
|  | ||||
|   // Escape HTML first | ||||
|   let html = markdown | ||||
|     .replace(/&/g, '&') | ||||
|     .replace(/</g, '<') | ||||
|     .replace(/>/g, '>'); | ||||
|  | ||||
|   // Code blocks (```...```) | ||||
|   html = html.replace(/```([^```]*)```/gs, (match, p1) => | ||||
|     `<pre><code>${p1.trim()}</code></pre>` | ||||
|   ); | ||||
|  | ||||
|   // Inline code (`code`) | ||||
|   html = html.replace(/`([^`\n]+)`/g, (match, p1) => `<code>${p1}</code>`); | ||||
|  | ||||
|   // Emojis :emoji_name: | ||||
|   html = html.replace(/:([a-z0-9_]+):/gi, (match, p1) => emojiMap[p1] || match); | ||||
|  | ||||
|   // Process overlapping formatting in order: Bold+Underline+Italic | ||||
|   html = parseFormatting(html); | ||||
|  | ||||
|   // Replace line breaks | ||||
|   html = html.replace(/\n/g, '<br>'); | ||||
|  | ||||
|   return html; | ||||
| } | ||||
|  | ||||
| // Parse overlapping formatting using tokens | ||||
| function parseFormatting(text) { | ||||
|   // Define replacement tokens and their HTML | ||||
|   const formattingRules = [ | ||||
|     { regex: /\*\*\*(.*?)\*\*\*/g, html: '<strong><em>$1</em></strong>' }, // ***bold italic*** | ||||
|     { regex: /___(.*?)___/g, html: '<u><em>$1</em></u>' },                 // ___underline italic___ | ||||
|     { regex: /\*\*(.*?)\*\*/g, html: '<strong>$1</strong>' },             // **bold** | ||||
|     { regex: /__(.*?)__/g, html: '<u>$1</u>' },                           // __underline__ | ||||
|     { regex: /\*(.*?)\*/g, html: '<em>$1</em>' },                         // *italic* | ||||
|     { regex: /_(.*?)_/g, html: '<em>$1</em>' },                           // _italic_ | ||||
|     { regex: /~~(.*?)~~/g, html: '<s>$1</s>' }                            // ~~strike~~ | ||||
|   ]; | ||||
|  | ||||
|   // Apply formatting in order | ||||
|   for (const rule of formattingRules) { | ||||
|     text = text.replace(rule.regex, rule.html); | ||||
|   } | ||||
|  | ||||
|   return text; | ||||
| } | ||||
|  | ||||
|  | ||||
| // Handle incoming messages | ||||
| function handleMessage(event) { | ||||
|     if (event.data === "ping") { | ||||
| @@ -618,7 +837,7 @@ function addChatMessage(author, content, isHistory = false) { | ||||
|     // Add message text | ||||
|     const textDiv = document.createElement('div'); | ||||
|     textDiv.className = 'message-text'; | ||||
|     textDiv.textContent = content; | ||||
|     textDiv.innerHTML = markdownToHtmlDiv(content); | ||||
|     contentDiv.appendChild(textDiv); | ||||
|      | ||||
|     messageWrapper.appendChild(avatar); | ||||
| @@ -797,6 +1016,8 @@ async function uploadFile() { | ||||
|     const formData = new FormData(); | ||||
|     formData.append("file", fileInput.files[0]); | ||||
|     formData.append("room", currentRoom);  | ||||
|     formData.append("username", username); | ||||
|     formData.append("token", md5(password)); | ||||
|      | ||||
|     try { | ||||
|         const response = await fetch(getUploadUrl(), { | ||||
| @@ -807,17 +1028,6 @@ async function uploadFile() { | ||||
|          | ||||
|         if (response.ok) { | ||||
|             hideFileUpload(); | ||||
|              | ||||
|             const processedMessage = { | ||||
|                 "type": "message", | ||||
|                 "username": username, | ||||
|                 "token": md5(password), | ||||
|                 "room": currentRoom, | ||||
|                 "content": `Sent a file` | ||||
|             } | ||||
|             if (ws && ws.readyState === WebSocket.OPEN) { | ||||
|                 ws.send(JSON.stringify(processedMessage)); | ||||
|             } | ||||
|         } else { | ||||
|             alert("Failed to upload file. Please try again."); | ||||
|         } | ||||
| @@ -1143,4 +1353,4 @@ if (uploadField) { | ||||
|             this.value = ""; | ||||
|         } | ||||
|     }; | ||||
| } | ||||
| } | ||||
|   | ||||
| @@ -798,6 +798,20 @@ fun main(args: Array<String>) { | ||||
|             Files.copy(uploadedFile.content(), filePath) | ||||
|              | ||||
|             val room = if (ctx.formParam("room") != null) ctx.formParam("room") else "general" | ||||
|             var username: String = "" | ||||
|             var token: String = "" | ||||
|  | ||||
|             if (ctx.formParam("username") != null) { | ||||
|                 username = ctx.formParam("username").toString() | ||||
|             } else { | ||||
|                 // do error | ||||
|             } | ||||
|  | ||||
|             if (ctx.formParam("token") != null) { | ||||
|                 token = ctx.formParam("token").toString() | ||||
|             } else { | ||||
|                 // do error | ||||
|             } | ||||
|              | ||||
|             val processedData = JSONObject().apply { | ||||
|                 put("type", "fileStatus") | ||||
| @@ -808,7 +822,7 @@ fun main(args: Array<String>) { | ||||
|              | ||||
|             val processedData2 = JSONObject().apply { | ||||
|                 put("type", "file") | ||||
|                 put("username", "system") | ||||
|                 put("username", username) | ||||
|                 put("room", room) | ||||
|                 put("content", "https://maxwellj.xyz/chookchat/uploads/$newFilename") | ||||
|             } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user