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";
|
return "announcement";
|
||||||
}
|
}
|
||||||
|
|
||||||
get label() {
|
get announcement() {
|
||||||
const event = this._entry.event;
|
const event = this._entry.event;
|
||||||
const content = event.content;
|
const content = event.content;
|
||||||
return `${event.sender} changed membership to ${content.membership}`;
|
return `${event.sender} changed membership to ${content.membership}`;
|
||||||
|
|
|
@ -6,9 +6,9 @@ export default class RoomNameTile extends SimpleTile {
|
||||||
return "announcement";
|
return "announcement";
|
||||||
}
|
}
|
||||||
|
|
||||||
get label() {
|
get announcement() {
|
||||||
const event = this._entry.event;
|
const event = this._entry.event;
|
||||||
const content = event.content;
|
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":
|
case "m.emote":
|
||||||
return new TextTile(options);
|
return new TextTile(options);
|
||||||
case "m.image":
|
case "m.image":
|
||||||
return new ImageTile(options);
|
return null; // not supported yet
|
||||||
|
// return new ImageTile(options);
|
||||||
case "m.location":
|
case "m.location":
|
||||||
return new LocationTile(options);
|
return new LocationTile(options);
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import Template from "./Template.js";
|
import Template from "./Template.js";
|
||||||
|
|
||||||
export default class TemplateView {
|
export default class TemplateView {
|
||||||
constructor(value) {
|
constructor(vm, bindToChangeEvent) {
|
||||||
this.viewModel = value;
|
this.viewModel = vm;
|
||||||
|
this._changeEventHandler = bindToChangeEvent ? this.update.bind(this, this.viewModel) : null;
|
||||||
this._template = null;
|
this._template = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +12,9 @@ export default class TemplateView {
|
||||||
}
|
}
|
||||||
|
|
||||||
mount() {
|
mount() {
|
||||||
|
if (this._changeEventHandler) {
|
||||||
|
this.viewModel.on("change", this._changeEventHandler);
|
||||||
|
}
|
||||||
this._template = new Template(this.viewModel, (t, value) => this.render(t, value));
|
this._template = new Template(this.viewModel, (t, value) => this.render(t, value));
|
||||||
return this.root();
|
return this.root();
|
||||||
}
|
}
|
||||||
|
@ -20,6 +24,9 @@ export default class TemplateView {
|
||||||
}
|
}
|
||||||
|
|
||||||
unmount() {
|
unmount() {
|
||||||
|
if (this._changeEventHandler) {
|
||||||
|
this.viewModel.off("change", this._changeEventHandler);
|
||||||
|
}
|
||||||
this._template.dispose();
|
this._template.dispose();
|
||||||
this._template = null;
|
this._template = null;
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
// DOM helper functions
|
// DOM helper functions
|
||||||
|
|
||||||
export function isChildren(children) {
|
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);
|
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 {
|
export default class RoomPlaceholderView {
|
||||||
constructor() {
|
constructor() {
|
|
@ -1,4 +1,4 @@
|
||||||
import TemplateView from "./TemplateView.js";
|
import TemplateView from "../general/TemplateView.js";
|
||||||
|
|
||||||
export default class RoomTile extends TemplateView {
|
export default class RoomTile extends TemplateView {
|
||||||
render(t) {
|
render(t) {
|
|
@ -1,9 +1,10 @@
|
||||||
import ListView from "./ListView.js";
|
import ListView from "../general/ListView.js";
|
||||||
import RoomTile from "./RoomTile.js";
|
import RoomTile from "./RoomTile.js";
|
||||||
import RoomView from "./RoomView.js";
|
import RoomView from "./room/RoomView.js";
|
||||||
import SwitchView from "./SwitchView.js";
|
import SwitchView from "../general/SwitchView.js";
|
||||||
import RoomPlaceholderView from "./RoomPlaceholderView.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 {
|
export default class SessionView {
|
||||||
constructor(viewModel) {
|
constructor(viewModel) {
|
||||||
|
@ -21,8 +22,7 @@ export default class SessionView {
|
||||||
|
|
||||||
mount() {
|
mount() {
|
||||||
this._viewModel.on("change", this._onViewModelChange);
|
this._viewModel.on("change", this._onViewModelChange);
|
||||||
|
this._syncStatusBar = new SyncStatusBar(this._viewModel.syncStatusViewModel);
|
||||||
this._root = tag.div({className: "SessionView"});
|
|
||||||
this._roomList = new ListView(
|
this._roomList = new ListView(
|
||||||
{
|
{
|
||||||
list: this._viewModel.roomList,
|
list: this._viewModel.roomList,
|
||||||
|
@ -30,9 +30,16 @@ export default class SessionView {
|
||||||
},
|
},
|
||||||
(room) => new RoomTile(room)
|
(room) => new RoomTile(room)
|
||||||
);
|
);
|
||||||
this._root.appendChild(this._roomList.mount());
|
|
||||||
this._middleSwitcher = new SwitchView(new RoomPlaceholderView());
|
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;
|
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 TimelineTile from "./timeline/TimelineTile.js";
|
||||||
import ListView from "./ListView.js";
|
import ListView from "../../general/ListView.js";
|
||||||
import {tag} from "./html.js";
|
import {tag} from "../../general/html.js";
|
||||||
import GapView from "./timeline/GapView.js";
|
import GapView from "./timeline/GapView.js";
|
||||||
|
|
||||||
export default class RoomView {
|
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 {
|
export default class GapView extends TemplateView {
|
||||||
render(t, vm) {
|
render(t, vm) {
|
||||||
const className = {
|
const className = {
|
||||||
gap: true,
|
GapView: true,
|
||||||
isLoading: vm => vm.isLoading
|
isLoading: vm => vm.isLoading
|
||||||
};
|
};
|
||||||
const label = (vm.isUp ? "🠝" : "🠟") + " fill gap"; //no binding
|
const label = (vm.isUp ? "🠝" : "🠟") + " fill gap"; //no binding
|
||||||
return t.li({className}, [
|
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))
|
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