import { q, ElemJS, ejs } from "./basic.js"; import { store } from "./store/store.js"; import { Timeline } from "./Timeline.js"; import * as lsm from "./lsm.js"; function resolveMxc(url, size, method) { 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 { return `${lsm.get("domain")}/_matrix/media/r0/download/${server}/${id}`; } } 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.group = null; 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();