diff --git a/.gitignore b/.gitignore index 1d83ade..75e7d32 100644 --- a/.gitignore +++ b/.gitignore @@ -288,10 +288,6 @@ modules.xml # End of https://www.toptal.com/developers/gitignore/api/node,vscode,webstorm,webstorm+all -# Emacs -*~ -\#*# - # Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option) /build/ diff --git a/src/js/chat.js b/src/js/chat.js index 6695c3a..050ff8b 100644 --- a/src/js/chat.js +++ b/src/js/chat.js @@ -42,7 +42,7 @@ class Chat extends ElemJS { } this.addSubscription("beforeChange", timeline, beforeChangeSubscription) - // Make sure after loading scrollback we don't move the scroll position + //Make sure after loading scrollback we don't move the scroll position const beforeScrollbackLoadSubscription = () => { const lastScrollHeight = chatMessages.scrollHeight; diff --git a/src/js/functions.js b/src/js/functions.js index da60793..bf94921 100644 --- a/src/js/functions.js +++ b/src/js/functions.js @@ -1,8 +1,7 @@ const lsm = require("./lsm.js") function resolveMxc(url, size, method) { - let [server, id] = url.match(/^mxc:\/\/([^/]+)\/(.*)/).slice(1) - id = id.replace(/#.*$/, "") + const [server, id] = url.match(/^mxc:\/\/([^/]+)\/(.*)/).slice(1) if (size && method) { return `${lsm.get("domain")}/_matrix/media/r0/thumbnail/${server}/${id}?width=${size}&height=${size}&method=${method}` } else { diff --git a/src/js/sender.js b/src/js/sender.js deleted file mode 100644 index 55943dc..0000000 --- a/src/js/sender.js +++ /dev/null @@ -1,120 +0,0 @@ -const {ElemJS, ejs} = require("./basic.js") -const {store} = require("./store/store.js") -const {resolveMxc} = require("./functions.js") - -function nameToColor(str) { - // code from element's react sdk - const colors = ["#55a7f0", "#da55ff", "#1bc47c", "#ea657e", "#fd8637", "#22cec6", "#8c8de3", "#71bf22"] - let hash = 0 - let i - let chr - if (str.length === 0) { - return hash - } - for (i = 0; i < str.length; i++) { - chr = str.charCodeAt(i) - hash = ((hash << 5) - hash) + chr - hash |= 0 - } - hash = Math.abs(hash) % 8 - return colors[hash] -} - -class Avatar extends ElemJS { - constructor() { - super("div") - this.class("c-message-group__avatar") - - this.mxc = undefined - this.image = null - - this.update(null) - } - - update(mxc) { - if (mxc === this.mxc) return - this.mxc = mxc - this.hasImage = !!mxc - if (this.hasImage) { - const size = 96 - const url = resolveMxc(mxc, size, "crop") - this.image = ejs("img").class("c-message-group__icon").attribute("src", url).attribute("width", size).attribute("height", size) - this.image.on("error", this.onError.bind(this)) - } - this.render() - } - - onError() { - this.hasImage = false - this.render() - } - - render() { - this.clearChildren() - if (this.hasImage) { - this.child(this.image) - } else { - this.child( - ejs("div").class("c-message-group__icon", "c-message-group__icon--no-icon") - ) - } - } -} - -/** Must update at least once to render. */ -class Name extends ElemJS { - constructor() { - super("div") - this.class("c-message-group__name") - - /** - * Keeps track of whether we have the proper display name or not. - * If we do, then we shoudn't override it with the mxid if the name becomes unavailable. - */ - this.hasName = false - this.name = "" - this.mxid = "" - } - - update(event) { - this.mxid = event.state_key - if (event.content.displayname) { - this.hasName = true - this.name = event.content.displayname - } else if (!this.hasName) { - this.name = this.mxid - } - this.render() - } - - render() { - // set text - this.text(this.name) - // set color - this.style("color", nameToColor(this.mxid)) - } -} - -class Sender { - constructor(roomID, mxid) { - this.sender = store.rooms.get(roomID).value().members.get(mxid) - this.name = new Name() - this.avatar = new Avatar() - this.sender.subscribe("changeSelf", this.update.bind(this)) - this.update() - } - - update() { - if (this.sender.exists()) { - // name - this.name.update(this.sender.value()) - - // avatar - this.avatar.update(this.sender.value().content.avatar_url) - } - } -} - -module.exports = { - Sender -} diff --git a/src/js/timeline.js b/src/js/timeline.js index c03c635..270b5c8 100644 --- a/src/js/timeline.js +++ b/src/js/timeline.js @@ -2,8 +2,8 @@ const {ElemJS, ejs} = require("./basic.js") const {Subscribable} = require("./store/subscribable.js") const {store} = require("./store/store.js") const {Anchor} = require("./anchor.js") -const {Sender} = require("./sender.js") const lsm = require("./lsm.js") +const {resolveMxc} = require("./functions.js") let debug = false @@ -100,6 +100,41 @@ class Event extends ElemJS { } } +class Sender { + constructor(roomID, mxid) { + this.sender = store.rooms.get(roomID).value().members.get(mxid) + this.sender.subscribe("changeSelf", this.update.bind(this)) + this.name = new ElemJS("div").class("c-message-group__name") + this.avatar = new ElemJS("div").class("c-message-group__avatar") + this.displayingGoodData = false + this.update() + } + + update() { + if (this.sender.exists()) { + // name + if (this.sender.value().content.displayname) { + this.name.text(this.sender.value().content.displayname) + this.displayingGoodData = true + } else if (!this.displayingGoodData) { + this.name.text(this.sender.value().state_key) + } + + // avatar + this.avatar.clearChildren() + if (this.sender.value().content.avatar_url) { + this.avatar.child( + ejs("img").class("c-message-group__icon").attribute("src", resolveMxc(this.sender.value().content.avatar_url, 96, "crop")) + ) + } else { + this.avatar.child( + ejs("div").class("c-message-group__icon", "c-message-group__icon--no-icon") + ) + } + } + } +} + class EventGroup extends ElemJS { constructor(reactive, list) { super("div") @@ -266,11 +301,7 @@ class Timeline extends Subscribable { if (eventData.type === "m.room.member") { // update members if (eventData.membership !== "leave") { - const member = this.room.members.get(eventData.state_key) - // only use the latest state - if (!member.exists() || eventData.origin_server_ts > member.data.origin_server_ts) { - member.set(eventData) - } + this.room.members.get(eventData.state_key).set(eventData) } } } @@ -365,13 +396,7 @@ class Timeline extends Subscribable { this.from = root.end // console.log(this.updateEvents, root.chunk) if (root.state) this.updateStateEvents(root.state) - if (root.chunk.length) { - // there are events to display - this.updateEvents(root.chunk) - } else { - // we reached the top of the scrollback - this.reactiveTimeline.loadMore.remove() - } + this.updateEvents(root.chunk) this.broadcast("afterScrollbackLoad") } diff --git a/src/sass/components/messages.sass b/src/sass/components/messages.sass index 2a7665a..8a33dc2 100644 --- a/src/sass/components/messages.sass +++ b/src/sass/components/messages.sass @@ -23,7 +23,7 @@ border-radius: 50% &--no-icon - background-color: #bbb + background-color: #48d &__intro display: flex