organize view code in directory like viewmodels

This commit is contained in:
Bruno Windels 2019-06-16 10:52:02 +02:00
parent 95e1d55b97
commit a5a333b71a
18 changed files with 129 additions and 22 deletions

View file

@ -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}`;

View file

@ -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}"`
} }
} }

View file

@ -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:

View file

@ -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;
} }

View file

@ -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);
} }

View 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"))
]);
}
}

View file

@ -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() {

View file

@ -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) {

View file

@ -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;
} }

View 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"))
]);
}
}

View file

@ -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 {

View 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);
}
}

View file

@ -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))
]); ]);
} }

View 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)]),
])
);
}
}

View 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]);
}
}