const {ElemJS, q, ejs} = require("./basic.js") const {store} = require("./store/store.js") const chatMessages = q("#c-chat-messages") class Chat extends ElemJS { constructor() { super(q("#c-chat")) this.removableSubscriptions = [] store.activeRoom.subscribe("changeSelf", this.changeRoom.bind(this)) this.render() } unsubscribe() { this.removableSubscriptions.forEach(({name, target, subscription}) => { target.unsubscribe(name, subscription) }) this.removableSubscriptions.length = 0 } changeRoom() { // disconnect from the previous room this.unsubscribe() // connect to the new room's timeline updater if (store.activeRoom.exists()) { const timeline = store.activeRoom.value().timeline const beforeChangeSubscription = () => { // scroll anchor does not work if the timeline is scrolled to the top. // at the start, when there are not enough messages for a full screen, this is the case. // once there are enough messages that scrolling is necessary, we initiate a scroll down to activate the scroll anchor. let oldDifference = chatMessages.scrollHeight - chatMessages.clientHeight setTimeout(() => { let newDifference = chatMessages.scrollHeight - chatMessages.clientHeight // console.log("height difference", oldDifference, newDifference) if (oldDifference < 24) { // this is jank this.element.parentElement.scrollBy(0, 1000) } }, 0) } this.addSubscription("beforeChange", timeline, beforeChangeSubscription) // Make sure after loading scrollback we don't move the scroll position const beforeScrollbackLoadSubscription = () => { const lastScrollHeight = chatMessages.scrollHeight; const afterScrollbackLoadSub = () => { const scrollDiff = chatMessages.scrollHeight - lastScrollHeight; chatMessages.scrollTop += scrollDiff; timeline.unsubscribe("afterScrollbackLoad", afterScrollbackLoadSub) } timeline.subscribe("afterScrollbackLoad", afterScrollbackLoadSub) } this.addSubscription("beforeScrollbackLoad", timeline, beforeScrollbackLoadSubscription) } this.render() } addSubscription(name, target, subscription) { this.removableSubscriptions.push({name, target, subscription}) target.subscribe(name, subscription) } render() { this.clearChildren() if (store.activeRoom.exists()) { const reactiveTimeline = store.activeRoom.value().timeline.getTimeline() this.child(reactiveTimeline) setTimeout(() => { this.element.parentElement.scrollBy(0, 1) reactiveTimeline.anchor.scroll() }, 0) } } } const chat = new Chat() module.exports = {chat}