import {q, ElemJS, ejs} from "./basic.js" import {store} from "./store/store.js" import {SubscribeMapList} from "./store/SubscribeMapList.js" import {SubscribeValue} from "./store/SubscribeValue.js" import {Timeline} from "./Timeline.js" import * as lsm from "./lsm.js" import {resolveMxc} from "./functions.js" class ActiveGroupMarker extends ElemJS { constructor() { super(q("#c-group-marker")) store.activeGroup.subscribe("changeSelf", this.render.bind(this)) } render() { if (store.activeGroup.exists()) { const group = store.activeGroup.value() this.style("opacity", 1) this.style("transform", `translateY(${group.element.offsetTop}px)`) } else { this.style("opacity", 0) } } } const activeGroupMarker = new ActiveGroupMarker() class Group extends ElemJS { constructor(key, data) { super("div") this.data = data this.order = this.data.order this.class("c-group") this.child( (this.data.icon ? ejs("img").class("c-group__icon").attribute("src", this.data.icon) : ejs("div").class("c-group__icon") ), ejs("div").class("c-group__name").text(this.data.name) ) this.on("click", this.onClick.bind(this)) store.activeGroup.subscribe("changeSelf", this.render.bind(this)) } render() { const active = store.activeGroup.value() === this this.element.classList[active ? "add" : "remove"]("c-group--active") } onClick() { store.activeGroup.set(this) } } class Room extends ElemJS { constructor(id, data) { super("div") this.id = id this.data = data this.timeline = new Timeline(this.id) this.group = null this.members = new SubscribeMapList(SubscribeValue) this.class("c-room") this.on("click", this.onClick.bind(this)) store.activeRoom.subscribe("changeSelf", this.render.bind(this)) this.render() } get order() { if (this.group) { let chars = 36 let total = 0 const name = this.getName() for (let i = 0; i < name.length; i++) { const c = name[i] let d = 0 if (c >= "A" && c <= "Z") d = c.charCodeAt(0) - 65 + 10 else if (c >= "a" && c <= "z") d = c.charCodeAt(0) - 97 + 10 else if (c >= "0" && c <= "9") d = +c total += d * chars ** (-i) } return total } else { return -this.timeline.latest } } getName() { let name = this.data.state.events.find(e => e.type === "m.room.name") if (name) { name = name.content.name } else { const users = this.data.summary["m.heroes"] const usernames = users.map(u => (u.match(/^@([^:]+):/) || [])[1] || u) name = usernames.join(", ") } return name } getIcon() { const avatar = this.data.state.events.find(e => e.type === "m.room.avatar") if (avatar) { return resolveMxc(avatar.content.url || avatar.content.avatar_url, 32, "crop") } else { return null } } isDirect() { return store.directs.has(this.id) } setGroup(id) { this.group = id } getGroup() { if (this.group) { return store.groups.get(this.group).value() } else { return this.isDirect() ? store.groups.get("directs").value() : store.groups.get("channels").value() } } onClick() { store.activeRoom.set(this) } render() { this.clearChildren() // data const icon = this.getIcon() if (icon) { this.child(ejs("img").class("c-room__icon").attribute("src", icon)) } else { this.child(ejs("div").class("c-room__icon", "c-room__icon--no-icon")) } this.child(ejs("div").class("c-room__name").text(this.getName())) // active const active = store.activeRoom.value() === this this.element.classList[active ? "add" : "remove"]("c-room--active") } } class Rooms extends ElemJS { constructor() { super(q("#c-rooms")) this.roomData = [] this.rooms = [] store.rooms.subscribe("askAdd", this.askAdd.bind(this)) store.rooms.subscribe("addItem", this.addItem.bind(this)) // store.rooms.subscribe("changeItem", this.render.bind(this)) store.activeGroup.subscribe("changeSelf", this.render.bind(this)) store.directs.subscribe("changeItem", this.render.bind(this)) store.newEvents.subscribe("changeSelf", this.sort.bind(this)) this.render() } sort() { store.rooms.sort() this.render() } askAdd(event, {key, data}) { const room = new Room(key, data) store.rooms.addEnd(key, room) } addItem(event, key) { const room = store.rooms.get(key).value() if (room.getGroup() === store.activeGroup.value()) { this.child(room) } } render() { this.clearChildren() let first = null // set room list store.rooms.forEach((id, room) => { if (room.value().getGroup() === store.activeGroup.value()) { if (!first) first = room.value() this.child(room.value()) } }) // if needed, change the active room to be an item in the room list if (!store.activeRoom.exists() || store.activeRoom.value().getGroup() !== store.activeGroup.value()) { if (first) { store.activeRoom.set(first) } else { store.activeRoom.delete() } } } } const rooms = new Rooms() class Groups extends ElemJS { constructor() { super(q("#c-groups-list")) store.groups.subscribe("askAdd", this.askAdd.bind(this)) store.groups.subscribe("changeItem", this.render.bind(this)) } askAdd(event, {key, data}) { const group = new Group(key, data) store.groups.addEnd(key, group) store.groups.sort() } render() { this.clearChildren() store.groups.forEach((key, item) => { this.child(item.value()) }) } } const groups = new Groups()