const {q} = require("./basic.js") const {store} = require("./store/store.js") const lsm = require("./lsm.js") const {chat} = require("./chat.js") const {toHTML} = require("discord-markdown") const input = q("#c-chat-textarea") class TypingManager { constructor() { /** How long to appear to type for. */ this.time = 20000 /** How long before the end of the timeout to send the request again. */ this.margin = 5000 /** The room that we're typing in. We can semantically only type in one room at a time. */ this.typingRoom = null this.timeout = null } request(id, typing) { const url = new URL(`${lsm.get("domain")}/_matrix/client/r0/rooms/${id}/typing/${lsm.get("mx_user_id")}`) url.searchParams.set("access_token", lsm.get("access_token")) const body = {typing} if (typing) body.timeout = this.time fetch(url.toString(), { method: "PUT", body: JSON.stringify(body) }) } schedule(id) { this.request(id, true) this.timeout = setTimeout(() => { this.schedule(id) }, this.time - this.margin) } update(id) { if (id) { // typing somewhere if (this.typingRoom === id) return // already typing, don't do anything // state this.typingRoom = id // mark and schedule this.schedule(id) // add self to typing list now instead of waiting a round trip const typing = store.rooms.get(id).value().timeline.typing typing.edit(list => list.concat(lsm.get("mx_user_id"))) } else { // stopped typing if (this.typingRoom) { clearTimeout(this.timeout) this.request(this.typingRoom, false) } this.typingRoom = null } } } const typingManager = new TypingManager() store.activeRoom.subscribe("changeSelf", () => { // stop typing. you semantically can't type in a room you're not in. typingManager.update(null) // focus input box if (store.activeRoom.exists()) { input.focus() } }) input.addEventListener("keydown", event => { if (!store.activeRoom.exists()) return // send message? if (event.key === "Enter" && !event.shiftKey && !event.ctrlKey) { event.preventDefault() const body = input.value send(input.value) input.value = "" fixHeight() return } }) input.addEventListener("input", () => { fixHeight() // set typing if (input.value) { typingManager.update(store.activeRoom.value().id) } else { typingManager.update(null) } }) function fixHeight() { input.style.height = "0px" // console.log(input.clientHeight, input.scrollHeight) input.style.height = (input.scrollHeight + 1) + "px" } function send(body) { if (!store.activeRoom.exists()) return if (!body.trim().length) return const content = { msgtype: "m.text", format: "org.matrix.custom.html", body, formatted_body: toHTML(body), "chat.carbon.message.input_body": body } return store.activeRoom.value().timeline.send("m.room.message", content) }