{ "version": 3, "sources": ["../../../emoji_chat/chat.ts"], "sourcesContent": ["// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0-or-later\nexport {};\n\nconst messageInput = document.getElementById(\n \"message-input\",\n) as HTMLInputElement;\nconst messageInputForm = messageInput.form!;\nconst messageSection = document.getElementById(\"message-section\")!;\nconst usingOpenMoji = document.getElementById(\"openmoji-attribution\");\nconst openmojiVersion = usingOpenMoji?.getAttribute(\"openmoji-version\");\nconst connectionIndicator = document.getElementById(\"connection-state\")!;\nconst currentUser = document.getElementById(\"current-user\")!;\nlet reconnectTimeout = 100;\nlet reconnectTries = 0;\nlet lastMessage = \"\";\n\nconst timeStampToText = (timestamp: number) => {\n return new Date(timestamp + 1651075200000).toLocaleString();\n};\n\nconst getOpenMojiType = () => usingOpenMoji?.getAttribute(\"type\");\n\ninterface Message {\n author: string[];\n content: string[];\n timestamp: number;\n}\n\nconst appendMessage = (msg: Message) => {\n const el = document.createElement(\"div\");\n const emojiType = getOpenMojiType();\n if (emojiType === \"img\") {\n for (const emoji of msg.author) {\n el.append(emojiToIMG(emoji));\n }\n el.innerHTML += \": \";\n for (const emoji of msg.content) {\n el.append(emojiToIMG(emoji));\n }\n } else {\n el.innerText = `${msg.author.join(\"\")}: ${msg.content.join(\"\")}`;\n if (emojiType) {\n el.classList.add(\"openmoji\");\n }\n }\n el.setAttribute(\"tooltip\", timeStampToText(msg.timestamp));\n messageSection.append(el);\n};\n\nconst displayCurrentUser = (name: string[]) => {\n currentUser.innerHTML = \"\";\n const emojiType = getOpenMojiType();\n if (emojiType === \"img\") {\n for (const emoji of name) {\n currentUser.append(emojiToIMG(emoji));\n }\n return;\n }\n if (emojiType) {\n currentUser.classList.add(\"openmoji\");\n }\n currentUser.innerText = name.join(\"\");\n};\n\nconst emojiToIMG = (emoji: string) => {\n // eslint-disable-next-line @typescript-eslint/no-misused-spread\n const chars = [...emoji];\n const emojiCode = (\n chars.length == 2 && chars[1] === \"\\uFE0F\" ? [chars[0]!] : chars\n )\n .map((e: string) => e.codePointAt(0)!.toString(16).padStart(4, \"0\"))\n .join(\"-\")\n .toUpperCase();\n\n const imgEl = document.createElement(\"img\");\n\n const path = `/static/openmoji/svg/${emojiCode}.svg`;\n imgEl.src = openmojiVersion ? `${path}?v=${openmojiVersion}` : path;\n\n imgEl.classList.add(\"emoji\");\n imgEl.alt = emoji;\n\n return imgEl;\n};\n\nconst resetLastMessage = () => {\n if (lastMessage && !messageInput.value) {\n messageInput.value = lastMessage;\n lastMessage = \"\";\n }\n};\n\nconst setConnectionState = (state: string) => {\n let tooltip;\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n connectionIndicator.onclick = () => {};\n if (state === \"connecting\") {\n tooltip = \"Versuche mit WebSocket zu verbinden\";\n } else if (state === \"connected\") {\n tooltip = \"Mit WebSocket verbunden!\";\n } else if (state === \"disconnected\") {\n tooltip = \"Verbindung getrennt. Drücke hier um erneut zu versuchen.\";\n connectionIndicator.onclick = () => {\n reconnectTries = 0;\n reconnectTimeout = 500;\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n connectionIndicator.onclick = () => {};\n openWS();\n };\n } else {\n console.error(\"invalid state\", state);\n return;\n }\n connectionIndicator.setAttribute(\"state\", state);\n connectionIndicator.setAttribute(\"tooltip\", tooltip);\n};\n\nconst handleWebSocketData = (event: { data: string }) => {\n const data = JSON.parse(event.data) as {\n type: string;\n // the following are only present depending on the type\n message: Message;\n messages: Message[];\n current_user: string[];\n retry_after: number;\n users: string[];\n error: string;\n };\n switch (data.type) {\n case \"messages\": {\n messageSection.innerText = \"\";\n for (const msg of data.messages) {\n appendMessage(msg);\n }\n break;\n }\n case \"message\": {\n // console.debug(\"New message\", data[\"message\"]);\n appendMessage(data.message);\n break;\n }\n case \"init\": {\n displayCurrentUser(data.current_user);\n console.log(\"Connected as\", data.current_user.join(\"\"));\n setConnectionState(\"connected\");\n reconnectTimeout = 100;\n reconnectTries = 0;\n break;\n }\n case \"users\": {\n // only gets sent in dev mode of website\n console.debug(\"Received users data\", data.users);\n break;\n }\n case \"ratelimit\": {\n resetLastMessage();\n // TODO: Don't use alert\n alert(`Retry after ${data.retry_after} seconds.`);\n break;\n }\n case \"error\": {\n resetLastMessage();\n alert(data.error); // TODO: Don't use alert\n break;\n }\n default: {\n console.error(`Invalid type ${data.type}`);\n }\n }\n};\n\nconst openWS = () => {\n setConnectionState(\"connecting\");\n const ws = new WebSocket(\n (location.protocol === \"https:\" ? \"wss:\" : \"ws:\") +\n `//${location.host}/websocket/emoji-chat`,\n );\n const pingInterval = setInterval(() => {\n ws.send(\"\");\n }, 10000);\n ws.onclose = (event) => {\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n messageInputForm.onsubmit = () => {};\n if (event.wasClean) {\n console.debug(\n `Connection closed cleanly, code=${event.code} reason=${event.reason}`,\n );\n setConnectionState(\"disconnected\");\n return;\n }\n console.debug(\n `Connection closed, reconnecting in ${reconnectTimeout}ms`,\n );\n setConnectionState(\"connecting\");\n clearInterval(pingInterval);\n if (reconnectTries > 20) {\n // ~3 minutes not connected, just give up\n setConnectionState(\"disconnected\");\n return;\n }\n setTimeout(() => {\n reconnectTimeout = Math.max(\n 500, // minimum 500ms, for a better curve\n Math.floor(\n // maximum 15s, so we don't have to wait too long\n Math.min(15000, 1.5 * reconnectTimeout - 200),\n ),\n );\n reconnectTries++;\n openWS(); // restart connection\n }, reconnectTimeout);\n };\n ws.onopen = (event) => {\n console.debug(\"Opened WebSocket\", event);\n };\n ws.onmessage = handleWebSocketData;\n\n messageInputForm.onsubmit = (event) => {\n if (messageInput.value !== \"\") {\n lastMessage = messageInput.value;\n ws.send(\n JSON.stringify({\n type: \"message\",\n message: messageInput.value,\n }),\n );\n messageInput.value = \"\";\n }\n event.preventDefault();\n };\n};\nopenWS();\n"], "mappings": "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", "names": ["messageInput", "messageInputForm", "messageSection", "usingOpenMoji", "openmojiVersion", "connectionIndicator", "currentUser", "reconnectTimeout", "reconnectTries", "lastMessage", "timeStampToText", "timestamp", "getOpenMojiType", "appendMessage", "msg", "el", "emojiType", "emoji", "emojiToIMG", "displayCurrentUser", "name", "chars", "emojiCode", "e", "imgEl", "path", "resetLastMessage", "setConnectionState", "state", "tooltip", "openWS", "handleWebSocketData", "event", "data", "ws", "pingInterval"] }