Emojis, Markdown and better file uploading
This commit is contained in:
parent
7eba84b6ec
commit
82d18ac74d
|
@ -110,7 +110,7 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="message-input-wrapper">
|
<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()">
|
<button class="send-button" onclick="sendMessage()">
|
||||||
<i class="fa-solid fa-paper-plane"></i>
|
<i class="fa-solid fa-paper-plane"></i>
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -24,10 +24,17 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||||
chatHeader.insertBefore(menuToggle, chatHeader.firstChild);
|
chatHeader.insertBefore(menuToggle, chatHeader.firstChild);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
document.getElementById('messageInput').addEventListener('input', function () {
|
||||||
|
this.style.height = 'auto';
|
||||||
|
this.style.height = (this.scrollHeight) + 'px';
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
// Add event listeners
|
// Add event listeners
|
||||||
document.getElementById('messageInput').addEventListener('keypress', (event) => {
|
document.getElementById('messageInput').addEventListener('keydown', function(event) {
|
||||||
if (event.key === 'Enter') {
|
if (event.key === 'Enter' && !event.shiftKey) {
|
||||||
|
event.preventDefault();
|
||||||
sendMessage();
|
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
|
// Handle incoming messages
|
||||||
function handleMessage(event) {
|
function handleMessage(event) {
|
||||||
if (event.data === "ping") {
|
if (event.data === "ping") {
|
||||||
|
@ -618,7 +837,7 @@ function addChatMessage(author, content, isHistory = false) {
|
||||||
// Add message text
|
// Add message text
|
||||||
const textDiv = document.createElement('div');
|
const textDiv = document.createElement('div');
|
||||||
textDiv.className = 'message-text';
|
textDiv.className = 'message-text';
|
||||||
textDiv.textContent = content;
|
textDiv.innerHTML = markdownToHtmlDiv(content);
|
||||||
contentDiv.appendChild(textDiv);
|
contentDiv.appendChild(textDiv);
|
||||||
|
|
||||||
messageWrapper.appendChild(avatar);
|
messageWrapper.appendChild(avatar);
|
||||||
|
@ -797,6 +1016,8 @@ async function uploadFile() {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append("file", fileInput.files[0]);
|
formData.append("file", fileInput.files[0]);
|
||||||
formData.append("room", currentRoom);
|
formData.append("room", currentRoom);
|
||||||
|
formData.append("username", username);
|
||||||
|
formData.append("token", md5(password));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(getUploadUrl(), {
|
const response = await fetch(getUploadUrl(), {
|
||||||
|
@ -807,17 +1028,6 @@ async function uploadFile() {
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
hideFileUpload();
|
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 {
|
} else {
|
||||||
alert("Failed to upload file. Please try again.");
|
alert("Failed to upload file. Please try again.");
|
||||||
}
|
}
|
||||||
|
@ -1143,4 +1353,4 @@ if (uploadField) {
|
||||||
this.value = "";
|
this.value = "";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -798,6 +798,20 @@ fun main(args: Array<String>) {
|
||||||
Files.copy(uploadedFile.content(), filePath)
|
Files.copy(uploadedFile.content(), filePath)
|
||||||
|
|
||||||
val room = if (ctx.formParam("room") != null) ctx.formParam("room") else "general"
|
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 {
|
val processedData = JSONObject().apply {
|
||||||
put("type", "fileStatus")
|
put("type", "fileStatus")
|
||||||
|
@ -808,7 +822,7 @@ fun main(args: Array<String>) {
|
||||||
|
|
||||||
val processedData2 = JSONObject().apply {
|
val processedData2 = JSONObject().apply {
|
||||||
put("type", "file")
|
put("type", "file")
|
||||||
put("username", "system")
|
put("username", username)
|
||||||
put("room", room)
|
put("room", room)
|
||||||
put("content", "https://maxwellj.xyz/chookchat/uploads/$newFilename")
|
put("content", "https://maxwellj.xyz/chookchat/uploads/$newFilename")
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user