Merge branch 'princess' into rich-messages
This commit is contained in:
		
						commit
						217a815750
					
				
					 6 changed files with 141 additions and 40 deletions
				
			
		
							
								
								
									
										4
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							| 
						 | 
					@ -288,6 +288,10 @@ modules.xml
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# End of https://www.toptal.com/developers/gitignore/api/node,vscode,webstorm,webstorm+all
 | 
					# 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)
 | 
					# Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/build/
 | 
					/build/
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,8 @@
 | 
				
			||||||
const lsm = require("./lsm.js")
 | 
					const lsm = require("./lsm.js")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function resolveMxc(url, size, method) {
 | 
					function resolveMxc(url, size, method) {
 | 
				
			||||||
	const [server, id] = url.match(/^mxc:\/\/([^/]+)\/(.*)/).slice(1)
 | 
						let [server, id] = url.match(/^mxc:\/\/([^/]+)\/(.*)/).slice(1)
 | 
				
			||||||
 | 
						id = id.replace(/#.*$/, "")
 | 
				
			||||||
	if (size && method) {
 | 
						if (size && method) {
 | 
				
			||||||
		return `${lsm.get("domain")}/_matrix/media/r0/thumbnail/${server}/${id}?width=${size}&height=${size}&method=${method}`
 | 
							return `${lsm.get("domain")}/_matrix/media/r0/thumbnail/${server}/${id}?width=${size}&height=${size}&method=${method}`
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										120
									
								
								src/js/sender.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								src/js/sender.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,120 @@
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@ const {ElemJS, ejs} = require("./basic.js")
 | 
				
			||||||
const {Subscribable} = require("./store/subscribable.js")
 | 
					const {Subscribable} = require("./store/subscribable.js")
 | 
				
			||||||
const {store} = require("./store/store.js")
 | 
					const {store} = require("./store/store.js")
 | 
				
			||||||
const {Anchor} = require("./anchor.js")
 | 
					const {Anchor} = require("./anchor.js")
 | 
				
			||||||
 | 
					const {Sender} = require("./sender.js")
 | 
				
			||||||
const lsm = require("./lsm.js")
 | 
					const lsm = require("./lsm.js")
 | 
				
			||||||
const {resolveMxc} = require("./functions.js")
 | 
					const {resolveMxc} = require("./functions.js")
 | 
				
			||||||
const {renderEvent} = require("./events/renderEvent")
 | 
					const {renderEvent} = require("./events/renderEvent")
 | 
				
			||||||
| 
						 | 
					@ -39,41 +40,6 @@ function eventSearch(list, event, min = 0, max = NO_MAX) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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 {
 | 
					class EventGroup extends ElemJS {
 | 
				
			||||||
	constructor(reactive, list) {
 | 
						constructor(reactive, list) {
 | 
				
			||||||
		super("div")
 | 
							super("div")
 | 
				
			||||||
| 
						 | 
					@ -240,7 +206,11 @@ class Timeline extends Subscribable {
 | 
				
			||||||
			if (eventData.type === "m.room.member") {
 | 
								if (eventData.type === "m.room.member") {
 | 
				
			||||||
				// update members
 | 
									// update members
 | 
				
			||||||
				if (eventData.membership !== "leave") {
 | 
									if (eventData.membership !== "leave") {
 | 
				
			||||||
					this.room.members.get(eventData.state_key).set(eventData)
 | 
										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)
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -335,7 +305,13 @@ class Timeline extends Subscribable {
 | 
				
			||||||
		this.from = root.end
 | 
							this.from = root.end
 | 
				
			||||||
		// console.log(this.updateEvents, root.chunk)
 | 
							// console.log(this.updateEvents, root.chunk)
 | 
				
			||||||
		if (root.state) this.updateStateEvents(root.state)
 | 
							if (root.state) this.updateStateEvents(root.state)
 | 
				
			||||||
 | 
							if (root.chunk.length) {
 | 
				
			||||||
 | 
								// there are events to display
 | 
				
			||||||
			this.updateEvents(root.chunk)
 | 
								this.updateEvents(root.chunk)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								// we reached the top of the scrollback
 | 
				
			||||||
 | 
								this.reactiveTimeline.loadMore.remove()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		this.broadcast("afterScrollbackLoad")
 | 
							this.broadcast("afterScrollbackLoad")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,7 +23,7 @@
 | 
				
			||||||
    border-radius: 50%
 | 
					    border-radius: 50%
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    &--no-icon
 | 
					    &--no-icon
 | 
				
			||||||
      background-color: #48d
 | 
					      background-color: #bbb
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  &__intro
 | 
					  &__intro
 | 
				
			||||||
    display: flex
 | 
					    display: flex
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue