Overte-community-apps-Alezi.../applications/armored-chat/index.html
Armored Dragon 2e30a977e6
Fix timestamps not being stored in message history.
Signed-off-by: Armored Dragon <publicmail@armoreddragon.com>
2024-03-17 04:16:04 -05:00

301 lines
10 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="https://cdn.jsdelivr.net/npm/node-forge@1.0.0/dist/forge.min.js"></script>
<link rel="stylesheet" href="index.css" />
<!-- Compact messages -->
<!-- <link id="compact-messages" rel="stylesheet" href="compact-messages.css" /> -->
</head>
<body>
<!-- The primary page. This is where people will chat -->
<div class="header">
<div class="left">
<button data-target="domain-chat" class="active">
<span><img src="./img/ui/world_white.png" /></span>
</button>
<button data-target="local-chat">
<span><img src="./img/ui/social_black.png" /></span>
</button>
<!-- <button data-target="pm-chat">
<span><img src="./img/ui/user_black.png" /></span>
</button> -->
</div>
<div class="right">
<button data-target="settings">
<span><img src="./img/ui/settings_black.png" /></span>
</button>
</div>
</div>
<div id="domain-chat" class="page chat">
<div class="content message-list"></div>
</div>
<!-- Local Chat -->
<div id="local-chat" class="page hidden">
<div class="content message-list"></div>
</div>
<!-- DM page. -->
<div id="pm-chat" class="page hidden">
<div class="content">PM content</div>
</div>
<!-- Settings page. Adjust the chat here -->
<div id="settings" class="page hidden">
<div class="content settings">
<!-- <div class="setting setting-toggle">
<span>Show typing indicator</span>
<input id="typing-indicator-toggle" type="checkbox" />
</div> -->
<!-- <div class="setting setting-toggle">
<span>Show speech bubbles</span>
<input id="speech-bubble-toggle" type="checkbox" />
</div> -->
<div class="setting setting-toggle">
<span>Compact Mode</span>
<input id="compact-message-toggle" type="checkbox" />
</div>
<div class="setting setting-toggle">
<span>External Window</span>
<input id="external-window-toggle" type="checkbox" />
</div>
<div class="setting setting-button">
<span>Erase history</span>
<input id="erase-history" type="button" title="Clear" value="Clear" />
</div>
<div class="setting setting-value">
<span>Max history</span>
<input id="max-history" type="number" title="Maximum entires to store" />
</div>
</div>
</div>
<div class="footer text-entry">
<input id="message-entry" type="text" placeholder="Enter message here..." />
<button id="send-message">
<span><img src="./img/ui/send_black.png" /></span>
</button>
</div>
</body>
</html>
<script>
"use strict";
_emitEvent({ type: "initialized" }); // Tell the script we are ready
const qs = (target) => document.querySelector(target);
const qsa = (target) => document.querySelectorAll(target);
var scroll_distance = 100000; // The scroll distance for the chat window to automatically scroll down with.
var compact_mode = false; // Compact messages
var external_window = false;
// Start listening for new messages
EventBridge.scriptEventReceived.connect(_newScriptEvent);
// HTML Event listeners
qs("#send-message").addEventListener("click", _sendMessage);
qs("#message-entry").addEventListener("keyup", (event) => {
if (event.keyCode === 13) _sendMessage(); // Enter key, send message
});
// Add event listeners to all nav-buttons
qsa(".header button").forEach((button) => {
button.addEventListener("click", () => {
_switchPage(button.dataset.target, button);
if (button.dataset.target === "settings") {
qs(".footer.text-entry").classList.add("hidden");
} else {
qs(".footer.text-entry").classList.remove("hidden");
}
});
});
function _switchPage(target, button) {
// Hide all pages
qsa(".page").forEach((page) => page.classList.add("hidden"));
// Deactivate all nav-buttons
qsa(".header button").forEach((button) => deactivateButton(button));
// Show target page
qs(`#${target}`).classList.remove("hidden");
// Sets active for target button
activateButton(button);
function deactivateButton(button) {
button.querySelector("img").src = button.querySelector("img").src.replace("_white", "_black");
button.classList.remove("active");
}
function activateButton(button) {
button.querySelector("img").src = button.querySelector("img").src.replace("_black", "_white");
button.classList.add("active");
button.blur();
// Tell script where we are at
_emitEvent({ type: "page_update", page: button.dataset.target.replace("-chat", "") });
}
}
function _sendMessage() {
qs("#send-message").blur();
// Don't send empty messages.
if (qs("#message-entry").value.length === 0) return;
// Send what is in the text area as a message
_emitEvent({ type: "send_message", message: qs("#message-entry").value });
// Clear the message area
qs("#message-entry").value = "";
}
function _newScriptEvent(message) {
message = JSON.parse(message);
switch (message.type) {
case "show_message":
_showMessage(message);
break;
case "setting_update":
_newSetting(message);
break;
}
}
// Settings
qs("#compact-message-toggle").addEventListener("change", function () {
_toggleCompactMode();
_emitEvent({ type: "setting_update", setting_name: "compact_chat", setting_value: compact_mode });
});
function _toggleCompactMode() {
compact_mode = !compact_mode;
if (compact_mode) {
// Add the stylesheet to the head
document.head.insertAdjacentHTML("beforeend", '<link id="compact-messages-ss" rel="stylesheet" href="compact-messages.css" />');
} else {
// Remove the compact messages stylesheet
qs("#compact-messages-ss").remove();
}
}
qs("#external-window-toggle").addEventListener("change", function () {
external_window = !external_window;
_emitEvent({ type: "setting_update", setting_name: "external_window", setting_value: external_window });
});
qs("#erase-history").addEventListener("click", () => {
let response = confirm("Are you sure you want to erase all messages?");
if (response) _emitEvent({ type: "action", action: "clear_history" });
// _emitEvent({ type: "setting_update", setting_name: "max_history", setting_value: compact_mode });
});
qs("#max-history").addEventListener("change", () => {
_emitEvent({ type: "setting_update", setting_name: "max_history", setting_value: qs("#max-history").value });
});
// TODO: Limit embeds to 3.
function _showMessage(message) {
var target = message.channel + "-chat";
// Clone template message
let message_template = qs("#message-listing");
let message_clone = message_template.content.cloneNode(true);
let message_embeds = "";
message_clone.querySelector(".body").innerHTML = "";
message_clone.querySelector(".embeds").innerHTML = "";
// Youtube embeds
let yt_url = message.message.match(/(https?:\/\/)?(www\.)?(youtube\.com\/watch\?v=|youtu\.be\/)([^& \n<]+)(?:[^ \n<]+)?/g);
if (yt_url) {
yt_url.forEach((url) => {
message_embeds += `<iframe class="z-depth-2" width='420' height='236' src='https://www.youtube.com/embed/${url.toString().split("/")[3]}' frameborder='0'></iframe><br>`;
});
}
// Image embeds
let image_link = message.message.match(/.+.(png|jpg|jpeg|webp)/g);
if (image_link) {
image_link.forEach((image) => {
message_embeds += `<span class='image-container'><img src='${image}'></span><br>`;
});
}
// Linkify links
let link_url = message.message.match(/(?:^|\s)(https?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+(?:\/[\w\-\._~:/?#[\]@!\$&'\(\)\*\+,;=.]*)?(?=\s|$)/g);
if (link_url) {
link_url.forEach((link) => {
message_embeds += `<a href='#' onclick='_emitEvent({type:"open_url", url: "${link}" })'>${link}</a><br>`;
message.message = message.message.replace(link, "");
});
}
// Update template data to message data
message_clone.querySelector(".name").innerText = message.displayName;
if (!message.timeString) {
message_clone.querySelector(".timestamp").innerText = new Date().toLocaleTimeString(undefined, { hour12: false });
message_clone.querySelector(".timestamp").title = new Date().toLocaleDateString(undefined, {
month: "long",
day: "numeric",
});
} else {
message_clone.querySelector(".timestamp").innerText = message.timeString;
message_clone.querySelector(".timestamp").title = message.dateString;
}
message_clone.querySelector(".embeds").innerHTML = message_embeds;
message_clone.querySelector(".body").innerText = message.message;
// Append to the message list
qs("#" + target + " .message-list").appendChild(message_clone);
// Scroll to the bottom of the page
qs("#" + target + " .message-list").scrollTop = scroll_distance;
// Increase scroll distance so it will continue to work for future messages.
scroll_distance = scroll_distance + 100000;
}
/**
* Called when the script is initialized and we are loading the user settings
*/
function _newSetting(message) {
switch (message.setting_name) {
case "compact_chat":
qs("#compact-message-toggle").checked = true;
_toggleCompactMode();
break;
case "external_window":
qs("#external-window-toggle").checked = true;
external_window = true;
break;
case "max_history":
qs(`#max-history`).value = message.setting_value;
break;
}
}
/**
* Emit a packet to the HTML front end. Easy communication!
* @param {Object} packet - The Object packet to emit to the HTML
* @param {("setting_update"|"send_message"|"page_update"|"open_url"|"initialized")} packet.type - The type of packet it is
*/
function _emitEvent(packet = { type: "" }) {
EventBridge.emitWebEvent(JSON.stringify(packet));
}
</script>
<template id="message-listing">
<div class="message">
<div class="pfp"><img src="./img/ui/user_white.png" /></div>
<div class="name">[NAME]</div>
<div class="timestamp" title="[DATE]">[TIMESTAMP]</div>
<div>
<div class="embeds">[EMBEDS]</div>
<div class="body">[CONTENT]</div>
</div>
</div>
</template>
<!-- <script src="encrpytion.js"></script> -->