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' 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') } async function render() { let new_body = body({}, ...header(false, false, true, data.self.user_id), 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'}) ) ) document.body.replaceWith(new_body) } const data = { self: {}, users: [], rooms: {}, } async function loadRoomPage(room) { let request = (await chatload ( room.newest_msg, room.page, room.room_id )) if (request.json == undefined) { alert(request.msg) return } let messages = room.display.getElementsByClassName('messages')[0] for (const msg of request.json) { room.messages.push(msg) messages.appendChild(await parseMessageImpl(msg)) } room.page++ return request.json.length > 0 } async function loadRoom(room_id) { let room = data.rooms[room_id] 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 } } } room.display = createRoomDisplay(room, loadRoomPage) 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') } 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 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() delete data.rooms[event.room_id] } break; } case "typing": { break; } default: { console.warn("unhandled event: " + message.data) break; } } } async function init() { let request = (await loadself()); if (request.json == undefined) { location.href = '/login' return } data.self = request.json data.users[data.self.user_id] = data.self render() 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); } init()