generated from t/malachite
397 lines
10 KiB
JavaScript
397 lines
10 KiB
JavaScript
const STATE = {
|
|
id: 0,
|
|
chat_id: "",
|
|
observer: null,
|
|
is_loading: false,
|
|
stream_element: null,
|
|
last_message_time: 0,
|
|
last_read_receipt_load: 0,
|
|
};
|
|
|
|
function create_streamer(chat_id, hook_element) {
|
|
STATE.chat_id = chat_id;
|
|
STATE.stream_element = hook_element.parentElement;
|
|
|
|
STATE.observer = new IntersectionObserver(
|
|
(entries) => {
|
|
load_messages();
|
|
},
|
|
{
|
|
root: document.body,
|
|
rootMargin: "0px",
|
|
scrollMargin: "0px",
|
|
threshold: 1.0,
|
|
},
|
|
);
|
|
|
|
STATE.observer.observe(hook_element);
|
|
read_receipt();
|
|
}
|
|
|
|
function load_messages() {
|
|
if (STATE.is_loading) {
|
|
return;
|
|
}
|
|
|
|
STATE.is_loading = true;
|
|
STATE.id += 1;
|
|
|
|
fetch(
|
|
`/chats/_templates/chat/${STATE.chat_id}/messages/before/${STATE.last_message_time}?use_id=${STATE.id}`,
|
|
)
|
|
.then((res) => res.text())
|
|
.then((res) => {
|
|
setTimeout(() => {
|
|
STATE.is_loading = false;
|
|
}, 2000);
|
|
|
|
STATE.stream_element.innerHTML += res;
|
|
STATE.last_message_time = Number.parseInt(
|
|
document
|
|
.getElementById(`msgs_data_${STATE.id}`)
|
|
.getAttribute("data-first-message-time"),
|
|
);
|
|
|
|
if (document.getElementById(`msgs_quit_${STATE.id}`)) {
|
|
STATE.observer.disconnect();
|
|
console.log("quit");
|
|
} else {
|
|
STATE.observer.unobserve(
|
|
STATE.stream_element.querySelector(
|
|
"[ui_ident=data_marker]",
|
|
),
|
|
);
|
|
|
|
STATE.stream_element
|
|
.querySelector("[ui_ident=data_marker]")
|
|
.remove();
|
|
|
|
const element = document.createElement("div");
|
|
element.setAttribute("ui_ident", "data_marker");
|
|
STATE.stream_element.append(element);
|
|
STATE.observer.observe(element);
|
|
}
|
|
});
|
|
}
|
|
|
|
function render_message(id) {
|
|
STATE.is_loading = true;
|
|
fetch(`/chats/_templates/message/${id}`)
|
|
.then((res) => res.text())
|
|
.then((res) => {
|
|
STATE.is_loading = false;
|
|
STATE.stream_element.innerHTML = `${res}${STATE.stream_element.innerHTML}`;
|
|
mark_message_read();
|
|
scroll_bottom();
|
|
|
|
if (document.getElementById("delivered_read_status")) {
|
|
document.getElementById("delivered_read_status").remove(); // clear read receipt box
|
|
}
|
|
});
|
|
}
|
|
|
|
function scroll_bottom() {
|
|
STATE.stream_element.parentElement.scrollTo(
|
|
0,
|
|
STATE.stream_element.parentElement.scrollHeight,
|
|
);
|
|
}
|
|
|
|
function sock_con() {
|
|
const socket = new WebSocket(
|
|
`//${window.location.origin.split("//")[1]}/api/v1/chats/${STATE.chat_id}/_connect`,
|
|
);
|
|
|
|
socket.addEventListener("message", async (event) => {
|
|
if (event.data === "Ping") {
|
|
return socket.send("Pong");
|
|
}
|
|
|
|
const msg = JSON.parse(event.data);
|
|
|
|
if (msg.method === "MessageCreate") {
|
|
render_message(msg.body);
|
|
} else if (msg.method === "MessageDelete") {
|
|
if (document.getElementById(`message_${msg.body}`)) {
|
|
document.getElementById(`message_${msg.body}`).remove();
|
|
}
|
|
} else if (msg.method === "MessageUpdate") {
|
|
const [id, content] = JSON.parse(msg.body);
|
|
document.getElementById(`${id}_body`).innerHTML =
|
|
await render_markdown(content);
|
|
} else if (msg.method === "ReadReceipt") {
|
|
setTimeout(() => {
|
|
read_receipt();
|
|
}, 150);
|
|
}
|
|
});
|
|
}
|
|
|
|
function create_message(e) {
|
|
e.preventDefault();
|
|
|
|
const body = new FormData();
|
|
|
|
// attach images
|
|
if (e.target.images) {
|
|
for (const file of e.target.images.files) {
|
|
body.append(file.name, file);
|
|
}
|
|
}
|
|
|
|
// add json body
|
|
body.append(
|
|
"body",
|
|
JSON.stringify({
|
|
content: e.target.content.value,
|
|
}),
|
|
);
|
|
|
|
// send request
|
|
fetch(`/api/v1/messages/${STATE.chat_id}`, { method: "POST", body })
|
|
.then((res) => res.json())
|
|
.then((res) => {
|
|
if (res.ok) {
|
|
e.target.reset();
|
|
document.getElementById("images_zone").classList.add("hidden");
|
|
} else {
|
|
show_message(res.message, res.ok);
|
|
}
|
|
});
|
|
}
|
|
|
|
function mark_message_read() {
|
|
fetch(`/api/v1/chats/${STATE.chat_id}/read_message`, {
|
|
method: "POST",
|
|
})
|
|
.then((res) => res.json())
|
|
.then((res) => {
|
|
if (!res.ok) {
|
|
show_message(res.message, res.ok);
|
|
}
|
|
});
|
|
}
|
|
|
|
function read_receipt() {
|
|
if (new Date().getTime() - STATE.last_read_receipt_load < 150) {
|
|
console.log("too soon");
|
|
return;
|
|
}
|
|
|
|
STATE.last_read_receipt_load = new Date().getTime();
|
|
|
|
if (document.getElementById("delivered_read_status")) {
|
|
document.getElementById("delivered_read_status").remove();
|
|
}
|
|
|
|
fetch(`/chats/_templates/chat/${STATE.chat_id}/read_receipt`)
|
|
.then((res) => res.text())
|
|
.then((res) => {
|
|
document.getElementById("read_receipt_zone").innerHTML = res;
|
|
});
|
|
}
|
|
|
|
function delete_message(id) {
|
|
if (!confirm("Are you sure you want to do this?")) {
|
|
return;
|
|
}
|
|
|
|
fetch(`/api/v1/messages/${id}`, {
|
|
method: "DELETE",
|
|
})
|
|
.then((res) => res.json())
|
|
.then((res) => {
|
|
if (!res.ok) {
|
|
show_message(res.message, res.ok);
|
|
}
|
|
});
|
|
}
|
|
|
|
async function render_markdown(content) {
|
|
return await (
|
|
await fetch("/api/v1/markdown", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ content }),
|
|
})
|
|
).text();
|
|
}
|
|
|
|
function edit_message_ui(id) {
|
|
document.getElementById(`${id}_body`).classList.add("hidden");
|
|
document.getElementById(`${id}_edit_area`).classList.remove("hidden");
|
|
}
|
|
|
|
function edit_message(id, e) {
|
|
e.preventDefault();
|
|
|
|
fetch(`/api/v1/messages/${id}`, {
|
|
method: "PUT",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
body: JSON.stringify({
|
|
content: e.target.content.value,
|
|
}),
|
|
})
|
|
.then((res) => res.json())
|
|
.then(async (res) => {
|
|
if (!res.ok) {
|
|
show_message(res.message, res.ok);
|
|
} else {
|
|
document
|
|
.getElementById(`${id}_body`)
|
|
.classList.remove("hidden");
|
|
document
|
|
.getElementById(`${id}_edit_area`)
|
|
.classList.add("hidden");
|
|
}
|
|
});
|
|
}
|
|
|
|
function leave_chat(id) {
|
|
if (!confirm("Are you sure you would like to do this?")) {
|
|
return;
|
|
}
|
|
|
|
fetch(`/api/v1/chats/${id}/leave`, {
|
|
method: "POST",
|
|
})
|
|
.then((res) => res.json())
|
|
.then((res) => {
|
|
show_message(res.message, res.ok);
|
|
});
|
|
}
|
|
|
|
function add_member_to_chat(e, chat_id) {
|
|
e.preventDefault();
|
|
document.getElementById("add_user_dialog").close();
|
|
fetch(`/api/v1/chats/${chat_id}/members/add/${e.target.username.value}`, {
|
|
method: "POST",
|
|
})
|
|
.then((res) => res.json())
|
|
.then((res) => {
|
|
show_message(res.message, res.ok);
|
|
});
|
|
}
|
|
|
|
function update_chat_info(id, info) {
|
|
fetch(`/api/v1/chats/${id}/info`, {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
body: JSON.stringify({
|
|
info,
|
|
}),
|
|
})
|
|
.then((res) => res.json())
|
|
.then((res) => {
|
|
show_message(res.message, res.ok);
|
|
});
|
|
}
|
|
|
|
function rename_chat(id, info) {
|
|
const new_name = prompt("New name:");
|
|
|
|
if (!new_name) {
|
|
return;
|
|
}
|
|
|
|
info.name = new_name;
|
|
update_chat_info(id, info);
|
|
}
|
|
|
|
function remove_member_from_chat(chat_id, uid) {
|
|
if (!confirm("Are you sure you would like to do this?")) {
|
|
return;
|
|
}
|
|
|
|
fetch(`/api/v1/chats/${chat_id}/members/remove/${uid}`, {
|
|
method: "POST",
|
|
})
|
|
.then((res) => res.json())
|
|
.then((res) => {
|
|
show_message(res.message, res.ok);
|
|
});
|
|
}
|
|
|
|
function create_direct_chat_with_user(id) {
|
|
fetch(`/api/v1/chats`, {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
body: JSON.stringify({
|
|
style: "Direct",
|
|
members: [id],
|
|
}),
|
|
})
|
|
.then((res) => res.json())
|
|
.then((res) => {
|
|
if (!res.ok) {
|
|
show_message(res.message, res.ok);
|
|
} else {
|
|
window.location.href = `/chats/${res.payload}`;
|
|
}
|
|
});
|
|
}
|
|
|
|
function pin_message(e, id) {
|
|
fetch(`/api/v1/chats/${STATE.chat_id}/pins/${id}`, {
|
|
method: "POST",
|
|
})
|
|
.then((res) => res.json())
|
|
.then((res) => {
|
|
show_message(res.message, res.ok);
|
|
|
|
if (res.ok) {
|
|
e.target.remove();
|
|
}
|
|
});
|
|
}
|
|
|
|
function unpin_message(id) {
|
|
fetch(`/api/v1/chats/${STATE.chat_id}/pins/${id}`, {
|
|
method: "DELETE",
|
|
})
|
|
.then((res) => res.json())
|
|
.then((res) => {
|
|
show_message(res.message, res.ok);
|
|
});
|
|
}
|
|
|
|
function display_pending_images(e) {
|
|
document.getElementById("images_zone").innerHTML = "";
|
|
document.getElementById("images_zone").classList.remove("hidden");
|
|
|
|
if (e.target.files.length < 1) {
|
|
document.getElementById("images_zone").classList.add("hidden");
|
|
return;
|
|
}
|
|
|
|
let idx = 0;
|
|
for (const file of e.target.files) {
|
|
document.getElementById("images_zone").innerHTML +=
|
|
`<button class="button surface" onclick="remove_file_from_picker('images', ${idx})">${file.name}</button>`;
|
|
idx += 1;
|
|
}
|
|
}
|
|
|
|
function remove_file_from_picker(input_id, idx) {
|
|
const input = document.getElementById(input_id);
|
|
const files = Array.from(input.files);
|
|
files.splice(idx - 1, 1);
|
|
|
|
// update files
|
|
const list = new DataTransfer();
|
|
|
|
for (item of files) {
|
|
list.items.add(item);
|
|
}
|
|
|
|
input.files = list.files;
|
|
|
|
// render
|
|
display_pending_images({ target: input });
|
|
}
|