diff --git a/README.md b/README.md index 357aa4b..4536623 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,9 @@ early in development. These important features still need to be implemented: - Unreads +- Chat history - Typing indicators +- Formatting - Emojis - Reactions - Encryption diff --git a/src/home.pug b/src/home.pug index 3277b89..09a00c7 100644 --- a/src/home.pug +++ b/src/home.pug @@ -53,4 +53,3 @@ html .c-chat__inner#c-chat .c-chat-input textarea(placeholder="Send a message..." autocomplete="off").c-chat-input__textarea#c-chat-textarea - .c-typing#c-typing diff --git a/src/js/functions.js b/src/js/functions.js index db43a16..da60793 100644 --- a/src/js/functions.js +++ b/src/js/functions.js @@ -10,28 +10,4 @@ function resolveMxc(url, size, method) { } } -function extractLocalpart(mxid) { - // try to extract the localpart from the mxid - let match = mxid.match(/^@([^:]+):/) - if (match) { - return match[1] - } - // localpart extraction failed, use the whole mxid - return mxid -} - -function extractDisplayName(stateEvent) { - const mxid = stateEvent.state_key - // see if a display name is set - if (stateEvent.content.displayname) { - return stateEvent.content.displayname - } - // fall back to the mxid - return extractLocalpart(mxid) -} - -module.exports = { - resolveMxc, - extractLocalpart, - extractDisplayName -} +module.exports = {resolveMxc} diff --git a/src/js/main.js b/src/js/main.js index fa5dc06..a15bc7f 100644 --- a/src/js/main.js +++ b/src/js/main.js @@ -2,8 +2,7 @@ const groups = require("./groups.js") const chat_input = require("./chat-input.js") const room_picker = require("./room-picker.js") const sync = require("./sync/sync.js") -const chat = require("./chat.js") -require("./typing.js") +const chat = require("./chat.js") if (!localStorage.getItem("access_token")) { location.assign("./login/") diff --git a/src/js/room-picker.js b/src/js/room-picker.js index 3046612..b04bcc6 100644 --- a/src/js/room-picker.js +++ b/src/js/room-picker.js @@ -4,7 +4,7 @@ const {SubscribeMapList} = require("./store/subscribe_map_list.js") const {SubscribeValue} = require("./store/subscribe_value.js") const {Timeline} = require("./timeline.js") const lsm = require("./lsm.js") -const {resolveMxc, extractLocalpart, extractDisplayName} = require("./functions.js") +const {resolveMxc} = require("./functions.js") class ActiveGroupMarker extends ElemJS { constructor() { @@ -93,15 +93,6 @@ class Room extends ElemJS { } } - getMemberName(mxid) { - if (this.members.has(mxid)) { - const state = this.members.get(mxid).value() - return extractDisplayName(state) - } else { - return extractLocalpart(mxid) - } - } - getName() { // if the room has a name let name = this.data.state.events.find(e => e.type === "m.room.name") @@ -116,7 +107,22 @@ class Room extends ElemJS { // if the room has no alias, use the names of its members ("heroes") const users = this.data.summary["m.heroes"] if (users && users.length) { - const usernames = users.map(mxid => this.getMemberName(mxid)) + const usernames = users.map(u => { + // if the member is in the room, use their display name + if (this.members.has(u)) { + const displayname = this.members.get(u).value().content.displayname + if (displayname) { + return displayname + } + } + // we don't have the member, so extract the localpart from the mxid + const match = u.match(/^@([^:]+):/) + if (match) { + return match[1] + } + // localpart extraction failed, use the whole mxid + return u + }) return usernames.join(", ") } // the room is empty diff --git a/src/js/store/subscribable.js b/src/js/store/subscribable.js index 56bf971..e87bab2 100644 --- a/src/js/store/subscribable.js +++ b/src/js/store/subscribable.js @@ -20,8 +20,6 @@ class Subscribable { } else { throw new Error(`Cannot subscribe to non-existent event ${event}, available events are: ${Object.keys(this.events).join(", ")}`) } - // return a function we can call to easily unsubscribe - return () => this.unsubscribe(event, callback) } unsubscribe(event, callback) { diff --git a/src/js/sync/sync.js b/src/js/sync/sync.js index 945e5cc..c17b0e9 100644 --- a/src/js/sync/sync.js +++ b/src/js/sync/sync.js @@ -57,7 +57,6 @@ function manageSync(root) { if (data.timeline.events.length) newEvents = true timeline.updateStateEvents(data.state.events) timeline.updateEvents(data.timeline.events) - timeline.updateEphemeral(data.ephemeral.events) }) // set up groups diff --git a/src/js/timeline.js b/src/js/timeline.js index 2743404..3204a5c 100644 --- a/src/js/timeline.js +++ b/src/js/timeline.js @@ -1,6 +1,5 @@ const {ElemJS, ejs} = require("./basic.js") const {Subscribable} = require("./store/subscribable.js") -const {SubscribeValue} = require("./store/subscribe_value.js") const {store} = require("./store/store.js") const {Anchor} = require("./anchor.js") const {Sender} = require("./sender.js") @@ -40,6 +39,7 @@ function eventSearch(list, event, min = 0, max = NO_MAX) { else return eventSearch(list, event, mid + 1, max) } + class EventGroup extends ElemJS { constructor(reactive, list) { super("div") @@ -81,6 +81,7 @@ class EventGroup extends ElemJS { } } + /** Displays a spinner and creates an event to notify timeline to load more messages */ class LoadMore extends ElemJS { constructor(id) { @@ -196,7 +197,6 @@ class Timeline extends Subscribable { this.latest = 0 this.pending = new Set() this.pendingEdits = [] - this.typing = new SubscribeValue().set([]) this.from = null } @@ -275,14 +275,6 @@ class Timeline extends Subscribable { this.broadcast("afterChange") } - updateEphemeral(events) { - for (const eventData of events) { - if (eventData.type === "m.typing") { - this.typing.set(eventData.content.user_ids) - } - } - } - removeEvent(id) { if (!this.map.has(id)) throw new Error(`Tried to delete event ID ${id} which does not exist`) this.map.get(id).removeEvent() diff --git a/src/js/typing.js b/src/js/typing.js deleted file mode 100644 index 46990d6..0000000 --- a/src/js/typing.js +++ /dev/null @@ -1,64 +0,0 @@ -const {ElemJS, ejs, q} = require("./basic") -const {store} = require("./store/store") - -/** - * Maximum number of typing users to display all names for. - * More will be shown as "X users are typing". - */ -const maxUsers = 4 - -function getMemberName(mxid) { - return store.activeRoom.value().getMemberName(mxid) -} - -class Typing extends ElemJS { - constructor() { - super(q("#c-typing")) - - this.typingUnsubscribe = null - - this.message = ejs("span") - this.child(this.message) - - store.activeRoom.subscribe("changeSelf", this.changeRoom.bind(this)) - } - - changeRoom() { - if (this.typingUnsubscribe) { - this.typingUnsubscribe() - } - if (!store.activeRoom.exists()) return - const room = store.activeRoom.value() - this.typingUnsubscribe = room.timeline.typing.subscribe("changeSelf", this.render.bind(this)) - this.render() - } - - render() { - if (!store.activeRoom.exists()) return - const room = store.activeRoom.value() - const users = room.timeline.typing.value() - if (users.length === 0) { - this.removeClass("c-typing--typing") - } else { - let message = "" - if (users.length === 1) { - message = `${getMemberName(users[0])} is typing...` - } else if (users.length <= maxUsers) { - // feel free to rewrite this loop if you know a better way - for (let i = 0; i < users.length; i++) { - if (i < users.length-1) { - message += `${getMemberName(users[i])}, ` - } else { - message += `and ${getMemberName(users[i])} are typing...` - } - } - } else { - message = `${users.length} people are typing...` - } - this.class("c-typing--typing") - this.message.text(message) - } - } -} - -new Typing() diff --git a/src/sass/components/chat-input.sass b/src/sass/components/chat-input.sass index bb82dde..892fee6 100644 --- a/src/sass/components/chat-input.sass +++ b/src/sass/components/chat-input.sass @@ -6,14 +6,11 @@ -webkit-appearance: $value .c-chat-input - position: relative width: 100% border-top: 2px solid c.$divider background-color: c.$dark &__textarea - position: relative - z-index: 1 width: calc(100% - 40px) height: 16px + (16px * 1.45) box-sizing: border-box diff --git a/src/sass/components/typing.sass b/src/sass/components/typing.sass deleted file mode 100644 index dad8d90..0000000 --- a/src/sass/components/typing.sass +++ /dev/null @@ -1,21 +0,0 @@ -@use "../colors" as c - -.c-typing - height: 39px - background: c.$divider - position: absolute - right: 0 - left: 0 - top: 0 - z-index: 0 - margin: 20px - border-radius: 8px - padding: 0px 12px - font-size: 14px - line-height: 19px - transform: translateY(0px) - transition: transform 0.15s ease - color: #fff - - &--typing - transform: translateY(-21px) diff --git a/src/sass/main.sass b/src/sass/main.sass index 9d7251f..24cd6ca 100644 --- a/src/sass/main.sass +++ b/src/sass/main.sass @@ -4,7 +4,6 @@ @use "./components/messages" @use "./components/chat" @use "./components/chat-input" -@use "./components/typing" @use "./components/anchor" @use "./components/highlighted-code" @use "./loading"