diff --git a/client-web/index.html b/client-web/index.html
index 0d36af5..113f6e5 100644
--- a/client-web/index.html
+++ b/client-web/index.html
@@ -110,7 +110,7 @@
-
+
diff --git a/client-web/index.js b/client-web/index.js
index b7f7602..0c2de7a 100644
--- a/client-web/index.js
+++ b/client-web/index.js
@@ -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, '>');
+
+ // Code blocks (```...```)
+ html = html.replace(/```([^```]*)```/gs, (match, p1) =>
+ `
${p1.trim()}
`
+ );
+
+ // Inline code (`code`)
+ html = html.replace(/`([^`\n]+)`/g, (match, p1) => `
${p1}
`);
+
+ // 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, '
');
+
+ return html;
+}
+
+// Parse overlapping formatting using tokens
+function parseFormatting(text) {
+ // Define replacement tokens and their HTML
+ const formattingRules = [
+ { regex: /\*\*\*(.*?)\*\*\*/g, html: '
$1' }, // ***bold italic***
+ { regex: /___(.*?)___/g, html: '
$1' }, // ___underline italic___
+ { regex: /\*\*(.*?)\*\*/g, html: '
$1' }, // **bold**
+ { regex: /__(.*?)__/g, html: '
$1' }, // __underline__
+ { regex: /\*(.*?)\*/g, html: '
$1' }, // *italic*
+ { regex: /_(.*?)_/g, html: '
$1' }, // _italic_
+ { regex: /~~(.*?)~~/g, html: '
$1' } // ~~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 = "";
}
};
-}
\ No newline at end of file
+}
diff --git a/server/src/main/kotlin/Main.kt b/server/src/main/kotlin/Main.kt
index 70e7d7c..47c05da 100644
--- a/server/src/main/kotlin/Main.kt
+++ b/server/src/main/kotlin/Main.kt
@@ -798,6 +798,20 @@ fun main(args: Array
) {
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) {
val processedData2 = JSONObject().apply {
put("type", "file")
- put("username", "system")
+ put("username", username)
put("room", room)
put("content", "https://maxwellj.xyz/chookchat/uploads/$newFilename")
}