forked from mystiq/hydrogen-web
organize view code in directory like viewmodels
This commit is contained in:
parent
95e1d55b97
commit
a5a333b71a
18 changed files with 129 additions and 22 deletions
|
@ -6,7 +6,7 @@ export default class RoomNameTile extends SimpleTile {
|
|||
return "announcement";
|
||||
}
|
||||
|
||||
get label() {
|
||||
get announcement() {
|
||||
const event = this._entry.event;
|
||||
const content = event.content;
|
||||
return `${event.sender} changed membership to ${content.membership}`;
|
||||
|
|
|
@ -6,9 +6,9 @@ export default class RoomNameTile extends SimpleTile {
|
|||
return "announcement";
|
||||
}
|
||||
|
||||
get label() {
|
||||
get announcement() {
|
||||
const event = this._entry.event;
|
||||
const content = event.content;
|
||||
return `${event.sender} changed the room name to "${content.name}"`
|
||||
return `${event.sender} named the room "${content.name}"`
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,8 @@ export default function ({timeline}) {
|
|||
case "m.emote":
|
||||
return new TextTile(options);
|
||||
case "m.image":
|
||||
return new ImageTile(options);
|
||||
return null; // not supported yet
|
||||
// return new ImageTile(options);
|
||||
case "m.location":
|
||||
return new LocationTile(options);
|
||||
default:
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import Template from "./Template.js";
|
||||
|
||||
export default class TemplateView {
|
||||
constructor(value) {
|
||||
this.viewModel = value;
|
||||
constructor(vm, bindToChangeEvent) {
|
||||
this.viewModel = vm;
|
||||
this._changeEventHandler = bindToChangeEvent ? this.update.bind(this, this.viewModel) : null;
|
||||
this._template = null;
|
||||
}
|
||||
|
||||
|
@ -11,6 +12,9 @@ export default class TemplateView {
|
|||
}
|
||||
|
||||
mount() {
|
||||
if (this._changeEventHandler) {
|
||||
this.viewModel.on("change", this._changeEventHandler);
|
||||
}
|
||||
this._template = new Template(this.viewModel, (t, value) => this.render(t, value));
|
||||
return this.root();
|
||||
}
|
||||
|
@ -20,6 +24,9 @@ export default class TemplateView {
|
|||
}
|
||||
|
||||
unmount() {
|
||||
if (this._changeEventHandler) {
|
||||
this.viewModel.off("change", this._changeEventHandler);
|
||||
}
|
||||
this._template.dispose();
|
||||
this._template = null;
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
// DOM helper functions
|
||||
|
||||
export function isChildren(children) {
|
||||
// children should be an not-object (that's the attributes), or a domnode, or an array
|
||||
return typeof children !== "object" || !!children.nodeType || Array.isArray(children);
|
||||
}
|
||||
|
19
src/ui/web/login/LoginView.js
Normal file
19
src/ui/web/login/LoginView.js
Normal file
|
@ -0,0 +1,19 @@
|
|||
import TemplateView from "./general/TemplateView.js";
|
||||
|
||||
export default class LoginView extends TemplateView {
|
||||
render(t, vm) {
|
||||
const username = t.input({type: "text", placeholder: vm.usernamePlaceholder});
|
||||
const password = t.input({type: "password", placeholder: vm.usernamePlaceholder});
|
||||
const homeserver = t.input({type: "text", placeholder: vm.hsPlaceholder, value: vm.defaultHS});
|
||||
return t.div({className: "login form"}, [
|
||||
t.if(vm => vm.error, t => t.div({className: "error"}, vm => vm.error)),
|
||||
t.div(username),
|
||||
t.div(password),
|
||||
t.div(homeserver),
|
||||
t.div(t.button({
|
||||
onClick: () => vm.login(username.value, password.value, homeserver.value),
|
||||
disabled: vm => vm.isBusy
|
||||
}, "Log In"))
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
import {tag} from "./html.js";
|
||||
import {tag} from "../general/html.js";
|
||||
|
||||
export default class RoomPlaceholderView {
|
||||
constructor() {
|
|
@ -1,4 +1,4 @@
|
|||
import TemplateView from "./TemplateView.js";
|
||||
import TemplateView from "../general/TemplateView.js";
|
||||
|
||||
export default class RoomTile extends TemplateView {
|
||||
render(t) {
|
|
@ -1,9 +1,10 @@
|
|||
import ListView from "./ListView.js";
|
||||
import ListView from "../general/ListView.js";
|
||||
import RoomTile from "./RoomTile.js";
|
||||
import RoomView from "./RoomView.js";
|
||||
import SwitchView from "./SwitchView.js";
|
||||
import RoomView from "./room/RoomView.js";
|
||||
import SwitchView from "../general/SwitchView.js";
|
||||
import RoomPlaceholderView from "./RoomPlaceholderView.js";
|
||||
import {tag} from "./html.js";
|
||||
import SyncStatusBar from "./SyncStatusBar.js";
|
||||
import {tag} from "../general/html.js";
|
||||
|
||||
export default class SessionView {
|
||||
constructor(viewModel) {
|
||||
|
@ -21,8 +22,7 @@ export default class SessionView {
|
|||
|
||||
mount() {
|
||||
this._viewModel.on("change", this._onViewModelChange);
|
||||
|
||||
this._root = tag.div({className: "SessionView"});
|
||||
this._syncStatusBar = new SyncStatusBar(this._viewModel.syncStatusViewModel);
|
||||
this._roomList = new ListView(
|
||||
{
|
||||
list: this._viewModel.roomList,
|
||||
|
@ -30,9 +30,16 @@ export default class SessionView {
|
|||
},
|
||||
(room) => new RoomTile(room)
|
||||
);
|
||||
this._root.appendChild(this._roomList.mount());
|
||||
this._middleSwitcher = new SwitchView(new RoomPlaceholderView());
|
||||
this._root.appendChild(this._middleSwitcher.mount());
|
||||
|
||||
this._root = tag.div({className: "SessionView"}, [
|
||||
this._syncStatusBar.mount(),
|
||||
tag.div({className: "main"}, [
|
||||
this._roomList.mount(),
|
||||
this._middleSwitcher.mount()
|
||||
])
|
||||
]);
|
||||
|
||||
return this._root;
|
||||
}
|
||||
|
16
src/ui/web/session/SyncStatusBar.js
Normal file
16
src/ui/web/session/SyncStatusBar.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
import TemplateView from "../general/TemplateView.js";
|
||||
|
||||
export default class SyncStatusBar extends TemplateView {
|
||||
constructor(vm) {
|
||||
super(vm, true);
|
||||
}
|
||||
|
||||
render(t, vm) {
|
||||
return t.div({className: {
|
||||
"SyncStatusBar": true,
|
||||
}}, [
|
||||
vm => vm.status,
|
||||
t.if(vm => !vm.isSyncing, t => t.button({onClick: () => vm.trySync()}, "Try syncing"))
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
import TimelineTile from "./TimelineTile.js";
|
||||
import ListView from "./ListView.js";
|
||||
import {tag} from "./html.js";
|
||||
import TimelineTile from "./timeline/TimelineTile.js";
|
||||
import ListView from "../../general/ListView.js";
|
||||
import {tag} from "../../general/html.js";
|
||||
import GapView from "./timeline/GapView.js";
|
||||
|
||||
export default class RoomView {
|
7
src/ui/web/session/room/timeline/AnnoucementView.js
Normal file
7
src/ui/web/session/room/timeline/AnnoucementView.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
import TemplateView from "../../../general/TemplateView.js";
|
||||
|
||||
export default class AnnouncementView extends TemplateView {
|
||||
render(t) {
|
||||
return t.li({className: "AnnouncementView"}, vm => vm.announcement);
|
||||
}
|
||||
}
|
|
@ -1,14 +1,17 @@
|
|||
import TemplateView from "../TemplateView.js";
|
||||
import TemplateView from "../../../general/TemplateView.js";
|
||||
|
||||
export default class GapView extends TemplateView {
|
||||
render(t, vm) {
|
||||
const className = {
|
||||
gap: true,
|
||||
GapView: true,
|
||||
isLoading: vm => vm.isLoading
|
||||
};
|
||||
const label = (vm.isUp ? "🠝" : "🠟") + " fill gap"; //no binding
|
||||
return t.li({className}, [
|
||||
t.button({onClick: () => this.viewModel.fill(), disabled: vm => vm.isLoading}, label),
|
||||
t.button({
|
||||
onClick: () => this.viewModel.fill(),
|
||||
disabled: vm => vm.isLoading
|
||||
}, label),
|
||||
t.if(vm => vm.error, t => t.strong(vm => vm.error))
|
||||
]);
|
||||
}
|
13
src/ui/web/session/room/timeline/TextMessageView.js
Normal file
13
src/ui/web/session/room/timeline/TextMessageView.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
import TemplateView from "../../../general/TemplateView.js";
|
||||
|
||||
export default class TextMessageView extends TemplateView {
|
||||
render(t, vm) {
|
||||
return t.li(
|
||||
{className: {"TextMessageView": true, own: vm.isOwn}},
|
||||
t.div({className: "message-container"}, [
|
||||
t.div({className: "sender"}, vm.sender),
|
||||
t.p([vm.text, t.time(vm.time)]),
|
||||
])
|
||||
);
|
||||
}
|
||||
}
|
33
src/ui/web/session/room/timeline/TimelineTile.js
Normal file
33
src/ui/web/session/room/timeline/TimelineTile.js
Normal file
|
@ -0,0 +1,33 @@
|
|||
import {tag} from "../../../general/html.js";
|
||||
|
||||
export default class TimelineTile {
|
||||
constructor(tileVM) {
|
||||
this._tileVM = tileVM;
|
||||
this._root = null;
|
||||
}
|
||||
|
||||
root() {
|
||||
return this._root;
|
||||
}
|
||||
|
||||
mount() {
|
||||
this._root = renderTile(this._tileVM);
|
||||
return this._root;
|
||||
}
|
||||
|
||||
unmount() {}
|
||||
|
||||
update(vm, paramName) {
|
||||
}
|
||||
}
|
||||
|
||||
function renderTile(tile) {
|
||||
switch (tile.shape) {
|
||||
case "message":
|
||||
return tag.li([tag.strong(tile.internalId+" "), tile.label]);
|
||||
case "announcement":
|
||||
return tag.li([tag.strong(tile.internalId+" "), tile.announcement]);
|
||||
default:
|
||||
return tag.li([tag.strong(tile.internalId+" "), "unknown tile shape: " + tile.shape]);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue