diff --git a/index.html b/index.html index 910581c2..dfd528b3 100644 --- a/index.html +++ b/index.html @@ -6,14 +6,16 @@

+
- \ No newline at end of file + diff --git a/src/main.js b/src/main.js index d7bd015e..6d2d7412 100644 --- a/src/main.js +++ b/src/main.js @@ -2,6 +2,8 @@ import HomeServerApi from "./matrix/hs-api.js"; import Session from "./matrix/session.js"; import createIdbStorage from "./matrix/storage/idb/create.js"; import Sync from "./matrix/sync.js"; +import ListView from "./ui/web/ListView.js"; +import RoomTile from "./ui/web/RoomTile.js"; const HOST = "localhost"; const HOMESERVER = `http://${HOST}:8008`; @@ -32,8 +34,14 @@ async function login(username, password, homeserver) { return {sessionId, loginData}; } +function showRooms(container, rooms) { + const sortedRooms = rooms.sortValues((a, b) => a.name.localeCompare(b.name)); + const listView = new ListView(sortedRooms, (room) => new RoomTile(room)); + container.appendChild(listView.mount()); +} + // eslint-disable-next-line no-unused-vars -export default async function main(label, button) { +export default async function main(label, button, container) { try { let sessionId = getSessionId(USER_ID); let loginData; @@ -46,6 +54,7 @@ export default async function main(label, button) { await session.setLoginData(loginData); } await session.load(); + showRooms(container, session.rooms); const hsApi = new HomeServerApi(HOMESERVER, session.accessToken); console.log("session loaded"); if (!session.syncToken) { diff --git a/src/matrix/room/room.js b/src/matrix/room/room.js index db963cdb..8a33f758 100644 --- a/src/matrix/room/room.js +++ b/src/matrix/room/room.js @@ -25,4 +25,8 @@ export default class Room extends EventEmitter { this._summary.load(summary); return this._persister.load(txn); } + + get name() { + return this._summary.name; + } } diff --git a/src/matrix/room/summary.js b/src/matrix/room/summary.js index fc2d772c..872d1122 100644 --- a/src/matrix/room/summary.js +++ b/src/matrix/room/summary.js @@ -17,7 +17,7 @@ export default class RoomSummary { } get name() { - return this._name || "Room without a name"; + return this._name || this._roomId; } get lastMessage() { diff --git a/src/observable/index.js b/src/observable/index.js index f33f84f6..3f2b4bf3 100644 --- a/src/observable/index.js +++ b/src/observable/index.js @@ -8,7 +8,7 @@ export { default as ObservableMap } from "./map/ObservableMap.js"; // avoid circular dependency between these classes // and BaseObservableMap (as they extend it) Object.assign(BaseObservableMap.prototype, { - asSortedList(comparator) { + sortValues(comparator) { return new SortedMapList(this, comparator); }, diff --git a/src/ui/web/ListView.js b/src/ui/web/ListView.js index ba4f230f..2aea9152 100644 --- a/src/ui/web/ListView.js +++ b/src/ui/web/ListView.js @@ -1,16 +1,20 @@ import * as html from "./html.js"; class UIView { - mount(initialValue) { - - } - - unmount() { - - } - - update() { + mount() {} + unmount() {} + update(_value) {} + // can only be called between a call to mount and unmount + root() {} +} +function insertAt(parentNode, idx, childNode) { + const isLast = idx === parentNode.childElementCount - 1; + if (isLast) { + parentNode.appendChild(childNode); + } else { + const nextDomNode = parentNode.children[idx + 1]; + parentNode.insertBefore(childNode, nextDomNode); } } @@ -23,10 +27,12 @@ export default class ListView { this._childInstances = null; } - getDOMNode() { + root() { return this._root; } + update() {} + mount() { this._subscription = this._collection.subscribe(this); this._root = html.ul({className: "ListView"}); @@ -48,31 +54,26 @@ export default class ListView { this._childInstances = null; } - onAdd(i, value) { + onAdd(idx, value) { const child = this._childCreator(value); - const childDomNode = child.mount(); - this._childInstances.splice(i, 0, child); - const isLast = i === this._collection.length - 1; - if (isLast) { - this._root.appendChild(childDomNode); - } else { - const nextDomNode = this._childInstances[i + 1].getDOMNode(); - this._root.insertBefore(childDomNode, nextDomNode); - } - + this._childInstances.splice(idx, 0, child); + insertAt(this._root, idx, child.mount()); } - onRemove(i, _value) { - const [child] = this._childInstances.splice(i, 1); - child.getDOMNode().remove(); + onRemove(idx, _value) { + const [child] = this._childInstances.splice(idx, 1); + child.root().remove(); child.unmount(); } onMove(fromIdx, toIdx, value) { - + const [child] = this._childInstances.splice(fromIdx, 1); + this._childInstances.splice(toIdx, 0, child); + child.root().remove(); + insertAt(this._root, toIdx, child.root()); } - onChange(i, value) { + onUpdate(i, value) { this._childInstances[i].update(value); } } diff --git a/src/ui/web/RoomTile.js b/src/ui/web/RoomTile.js new file mode 100644 index 00000000..eeb10555 --- /dev/null +++ b/src/ui/web/RoomTile.js @@ -0,0 +1,25 @@ +import { li } from "./html.js"; + +export default class RoomTile { + constructor(room) { + this._room = room; + this._root = null; + } + + mount() { + this._root = li(null, this._room.name); + return this._root; + } + + unmount() { + } + + update() { + // no data-binding yet + this._root.innerText = this._room.name; + } + + root() { + return this._root; + } +} diff --git a/src/ui/web/html.js b/src/ui/web/html.js index 9946887d..c5c0a266 100644 --- a/src/ui/web/html.js +++ b/src/ui/web/html.js @@ -4,12 +4,15 @@ export function setAttribute(el, name, value) { export function el(elementName, attrs, children) { const e = document.createElement(elementName); - if (typeof attrs === "object") { + if (typeof attrs === "object" && attrs !== null) { for (let [name, value] of Object.entries(attrs)) { setAttribute(e, name, value); } } - if (Array.isArray(children)) { + if (children) { + if (!Array.isArray(children)) { + children = [children]; + } // TODO: use fragment here? for (let c of children) { if (typeof c === "string") {