xssbook/public/js/chat.js

241 lines
6.6 KiB
JavaScript
Raw Permalink Normal View History

2023-08-22 03:19:53 +00:00
import { body, div, span, p, parse } from './main.js'
import { loadself, chatlist, chatload, loadusers, chatcreate } from './api.js'
import { createRoomDisplay, header, parseMessage, parseRoom, parseUser, createSingleLineInput } from './components.js'
2023-07-26 05:04:39 +00:00
2023-08-22 03:19:53 +00:00
async function getUser(user_id) {
if (data.users[user_id]) {
return data.users[user_id]
} else {
let request = (await loadusers([user_id]))
if (request.status != 200) {
location.href = 'login'
} else {
data.users[user_id] = request.json[0]
return request.json[0]
}
}
}
async function parseMessageImpl(message) {
let user = await getUser(message.user_id)
return parseMessage(message, user)
}
async function onRoomClick(room) {
for (const room of Object.values(data.rooms)) {
room.display.style.display = 'none'
room.button.classList.remove('current')
}
room.display.style.display = ''
room.button.classList.add('current')
}
2023-07-26 05:04:39 +00:00
2023-08-22 03:19:53 +00:00
async function render() {
2023-07-26 05:04:39 +00:00
let new_body =
body({},
...header(false, false, true, data.self.user_id),
2023-08-22 03:19:53 +00:00
div({id: 'cent'},
div({id: 'sidebar'},
span({class: 'ltext'},
parse("Rooms")
),
createSingleLineInput(
{
type: 'text',
name: 'addRoom',
class: 'addRoom input',
style: 'flex-grow: 0; width: 80%; margin-left: auto; margin-right: auto;'
},
async (text) => {
let result = (await chatcreate(text))
if (result.status != 201) {
alert(result.msg)
return false
} else {
return true
}
}
),
),
div({id: 'center'})
)
2023-07-26 05:04:39 +00:00
)
document.body.replaceWith(new_body)
}
const data = {
self: {},
2023-08-22 03:19:53 +00:00
users: [],
rooms: {},
}
2023-08-22 04:15:10 +00:00
async function loadRoomPage(room) {
2023-08-22 03:19:53 +00:00
let request = (await chatload (
room.newest_msg,
room.page,
2023-08-22 04:15:10 +00:00
room.room_id
2023-08-22 03:19:53 +00:00
))
if (request.json == undefined) {
alert(request.msg)
return
}
2023-08-22 04:15:10 +00:00
let messages = room.display.getElementsByClassName('messages')[0]
2023-08-22 03:19:53 +00:00
for (const msg of request.json) {
room.messages.push(msg)
2023-08-22 04:15:10 +00:00
messages.appendChild(await parseMessageImpl(msg))
2023-08-22 03:19:53 +00:00
}
room.page++
2023-08-22 04:15:10 +00:00
return request.json.length > 0
2023-08-22 03:19:53 +00:00
}
async function loadRoom(room_id) {
let room = data.rooms[room_id]
2023-08-22 04:15:10 +00:00
let batch = []
for (const user_id of room.users) {
if (data.users[user_id]) continue
batch.push(user_id)
}
if (batch.length > 1) {
let request = (await loadusers(batch))
if (request.status != 200) {
location.href = '/login'
} else {
for (const user of request.json) {
data.users[user.user_id] = user
}
2023-08-22 03:19:53 +00:00
}
}
2023-08-22 04:15:10 +00:00
room.display = createRoomDisplay(room, loadRoomPage)
2023-08-22 03:19:53 +00:00
let displays = document.getElementById("center")
displays.appendChild(room.display)
let button = parseRoom(room, onRoomClick)
if (displays.children.length > 1) {
room.display.style.display = 'none'
} else {
button.classList.add('current')
}
2023-08-22 04:15:10 +00:00
room.page = 0
room.messages = []
if (room.newest_msg == undefined || room.newest_msg < 0)
room.newest_msg = Number.MAX_SAFE_INTEGER
await loadRoomPage(room)
room.newest_msg = Math.min(
...room.messages.map(m => m.message_id)
)
room.page = 0
2023-08-22 03:19:53 +00:00
let sidebar = document.getElementById("sidebar")
sidebar.appendChild(button)
room.button = button
if (!room.people) room.people = room.people = {}
let people = room.display.getElementsByClassName("roomDisplayPeople")[0]
for (const user_id of room.users) {
if (room.people[user_id]) continue
let user = await getUser(user_id)
let el = parseUser(user)
people.appendChild(el)
room.people[user_id] = el
}
}
async function onMessage(message) {
let event = JSON.parse(message.data)
switch (event.type) {
case "message": {
let room = data.rooms[event.room_id]
if (!room) return
let display = room.display
let messages = display.getElementsByClassName('messages')[0]
messages.prepend(await parseMessageImpl(event))
break;
}
case "add": {
let room = data.rooms[event.room.room_id]
if (!room) {
// we are the user being added
data.rooms[event.room.room_id] = event.room
loadRoom(event.room.room_id)
} else {
let display = room.display
let people = display.getElementsByClassName('roomDisplayPeople')[0]
if (!room.people[event.user_id]) {
let user = await getUser(event.user_id)
let el = parseUser(user)
people.appendChild(el)
room.people[event.user_id] = el
}
}
break;
}
case "leave": {
let room = data.rooms[event.room_id]
if (!room) return
if (room.people[event.user_id]) {
room.people[event.user_id].remove()
delete room.people[event.user_id]
}
if (event.user_id == data.self.user_id) {
room.display.remove()
room.button.remove()
2023-08-22 04:15:10 +00:00
delete data.rooms[event.room_id]
2023-08-22 03:19:53 +00:00
}
break;
}
case "typing": {
break;
}
default: {
console.warn("unhandled event: " + message.data)
break;
}
}
2023-07-26 05:04:39 +00:00
}
async function init() {
let request = (await loadself());
if (request.json == undefined) {
location.href = '/login'
return
}
2023-08-22 04:15:10 +00:00
data.self = request.json
2023-07-26 05:04:39 +00:00
data.users[data.self.user_id] = data.self
render()
2023-08-22 03:19:53 +00:00
let rooms = (await chatlist());
if (rooms.json === undefined) {
alert(rooms.msg)
} else {
for (const room of rooms.json) {
data.rooms[room.room_id] = room
loadRoom(room.room_id)
}
}
let socket = new WebSocket(window.location.protocol.replace("http", "ws") + "//" + location.host + "/api/chat/connect")
socket.addEventListener("message", onMessage);
2023-07-26 05:04:39 +00:00
}
init()