From f4b13dbde4584d23524a65d530d9c56cac6b16c8 Mon Sep 17 00:00:00 2001 From: Cadence Ember Date: Mon, 9 Nov 2020 01:11:28 +1300 Subject: [PATCH] Send own typing status --- src/js/chat-input.js | 61 +++++++++++++++++++++++++++++++ src/js/store/subscribe_value.js | 2 +- src/js/typing.js | 7 +++- src/sass/components/messages.sass | 1 + 4 files changed, 69 insertions(+), 2 deletions(-) diff --git a/src/js/chat-input.js b/src/js/chat-input.js index 9558746..23d06fe 100644 --- a/src/js/chat-input.js +++ b/src/js/chat-input.js @@ -5,24 +5,85 @@ const {chat} = require("./chat.js") const input = q("#c-chat-textarea") +class TypingManager { + constructor() { + this.time = 20000 // how long to appear to type for + this.margin = 5000 // how long before the end of the timeout to send the request again + /** 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() { diff --git a/src/js/store/subscribe_value.js b/src/js/store/subscribe_value.js index eaa2cdd..9c71959 100644 --- a/src/js/store/subscribe_value.js +++ b/src/js/store/subscribe_value.js @@ -30,7 +30,7 @@ class SubscribeValue extends Subscribable { edit(f) { if (this.exists()) { - f(this.data) + this.data = f(this.data) this.set(this.data) } else { throw new Error("Tried to edit a SubscribeValue that had no value") diff --git a/src/js/typing.js b/src/js/typing.js index 46990d6..b6208ef 100644 --- a/src/js/typing.js +++ b/src/js/typing.js @@ -1,5 +1,6 @@ const {ElemJS, ejs, q} = require("./basic") const {store} = require("./store/store") +const lsm = require("./lsm") /** * Maximum number of typing users to display all names for. @@ -26,6 +27,7 @@ class Typing extends ElemJS { changeRoom() { if (this.typingUnsubscribe) { this.typingUnsubscribe() + this.typingUnsubscribe = null } if (!store.activeRoom.exists()) return const room = store.activeRoom.value() @@ -36,8 +38,11 @@ class Typing extends ElemJS { render() { if (!store.activeRoom.exists()) return const room = store.activeRoom.value() - const users = room.timeline.typing.value() + let users = [...room.timeline.typing.value()] + // don't show own typing status + users = users.filter(u => u !== lsm.get("mx_user_id")) if (users.length === 0) { + // nobody is typing this.removeClass("c-typing--typing") } else { let message = "" diff --git a/src/sass/components/messages.sass b/src/sass/components/messages.sass index 30ab3f2..170ae71 100644 --- a/src/sass/components/messages.sass +++ b/src/sass/components/messages.sass @@ -92,6 +92,7 @@ background-color: c.$darkest padding: 8px border: 1px solid c.$divider + white-space: pre-wrap code background-color: c.$darker