forked from mystiq/hydrogen-web
render date separator in base class for all tiles
apart from gap, which doesn't have date since we add a container when the date separator needs to be shown, and we don't want to rerender the whole tile, we always render timeline tiles with a DIV rather than an LI (same for the UL).
This commit is contained in:
parent
a488ff143e
commit
457c096c9b
5 changed files with 75 additions and 28 deletions
|
@ -55,7 +55,7 @@ export class MessageComposer extends TemplateView {
|
|||
className: "cancel",
|
||||
onClick: () => this._clearReplyingTo()
|
||||
}, "Close"),
|
||||
t.view(new TileView(rvm, this._viewClassForTile, { interactive: false }, "div"))
|
||||
t.view(new TileView(rvm, this._viewClassForTile, { interactive: false }))
|
||||
]);
|
||||
});
|
||||
const input = t.div({className: "MessageComposer_input"}, [
|
||||
|
|
|
@ -192,6 +192,7 @@ class TilesListView extends ListView<SimpleTile, TileView> {
|
|||
super({
|
||||
list: tiles,
|
||||
onItemClick: (tileView, evt) => tileView.onClick(evt),
|
||||
tagName: "div"
|
||||
}, tile => {
|
||||
const TileView = viewClassForTile(tile);
|
||||
return new TileView(tile, viewClassForTile);
|
||||
|
|
|
@ -14,18 +14,10 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import {TemplateView} from "../../../general/TemplateView";
|
||||
import {BaseTileView} from "./BaseTileView";
|
||||
|
||||
export class AnnouncementView extends TemplateView {
|
||||
// ignore other arguments
|
||||
constructor(vm) {
|
||||
super(vm);
|
||||
export class AnnouncementView extends BaseTileView {
|
||||
renderTile(t, vm) {
|
||||
return t.div({className: "AnnouncementView"}, t.div(vm => vm.announcement));
|
||||
}
|
||||
|
||||
render(t) {
|
||||
return t.li({className: "AnnouncementView"}, t.div(vm => vm.announcement));
|
||||
}
|
||||
|
||||
/* This is called by the parent ListView, which just has 1 listener for the whole list */
|
||||
onClick() {}
|
||||
}
|
||||
|
|
|
@ -18,17 +18,15 @@ limitations under the License.
|
|||
import {renderStaticAvatar} from "../../../avatar";
|
||||
import {tag} from "../../../general/html";
|
||||
import {mountView} from "../../../general/utils";
|
||||
import {TemplateView} from "../../../general/TemplateView";
|
||||
import {BaseTileView} from "./BaseTileView";
|
||||
import {Popup} from "../../../general/Popup.js";
|
||||
import {Menu} from "../../../general/Menu.js";
|
||||
import {ReactionsView} from "./ReactionsView.js";
|
||||
|
||||
export class BaseMessageView extends TemplateView {
|
||||
constructor(value, viewClassForTile, renderFlags, tagName = "li") {
|
||||
super(value);
|
||||
export class BaseMessageView extends BaseTileView {
|
||||
constructor(value, viewClassForTile, renderFlags) {
|
||||
super(value, viewClassForTile);
|
||||
this._menuPopup = null;
|
||||
this._tagName = tagName;
|
||||
this._viewClassForTile = viewClassForTile;
|
||||
// TODO An enum could be nice to make code easier to read at call sites.
|
||||
this._renderFlags = renderFlags;
|
||||
}
|
||||
|
@ -36,12 +34,12 @@ export class BaseMessageView extends TemplateView {
|
|||
get _interactive() { return this._renderFlags?.interactive ?? true; }
|
||||
get _isReplyPreview() { return this._renderFlags?.reply; }
|
||||
|
||||
render(t, vm) {
|
||||
renderTile(t, vm) {
|
||||
const children = [this.renderMessageBody(t, vm)];
|
||||
if (this._interactive) {
|
||||
children.push(t.button({className: "Timeline_messageOptions"}, "⋯"));
|
||||
}
|
||||
const li = t.el(this._tagName, {
|
||||
const tile = t.div({
|
||||
className: {
|
||||
"Timeline_message": true,
|
||||
own: vm.isOwn,
|
||||
|
@ -59,13 +57,13 @@ export class BaseMessageView extends TemplateView {
|
|||
// don't use `t` from within the side-effect callback
|
||||
t.mapSideEffect(vm => vm.isContinuation, (isContinuation, wasContinuation) => {
|
||||
if (isContinuation && wasContinuation === false) {
|
||||
li.removeChild(li.querySelector(".Timeline_messageAvatar"));
|
||||
li.removeChild(li.querySelector(".Timeline_messageSender"));
|
||||
tile.removeChild(tile.querySelector(".Timeline_messageAvatar"));
|
||||
tile.removeChild(tile.querySelector(".Timeline_messageSender"));
|
||||
} else if (!isContinuation && !this._isReplyPreview) {
|
||||
const avatar = tag.a({href: vm.memberPanelLink, className: "Timeline_messageAvatar"}, [renderStaticAvatar(vm, 30)]);
|
||||
const sender = tag.div({className: `Timeline_messageSender usercolor${vm.avatarColorNumber}`}, vm.displayName);
|
||||
li.insertBefore(avatar, li.firstChild);
|
||||
li.insertBefore(sender, li.firstChild);
|
||||
tile.insertBefore(avatar, tile.firstChild);
|
||||
tile.insertBefore(sender, tile.firstChild);
|
||||
}
|
||||
});
|
||||
// similarly, we could do this with a simple ifView,
|
||||
|
@ -75,15 +73,15 @@ export class BaseMessageView extends TemplateView {
|
|||
if (reactions && this._interactive && !reactionsView) {
|
||||
reactionsView = new ReactionsView(reactions);
|
||||
this.addSubView(reactionsView);
|
||||
li.appendChild(mountView(reactionsView));
|
||||
tile.appendChild(mountView(reactionsView));
|
||||
} else if (!reactions && reactionsView) {
|
||||
li.removeChild(reactionsView.root());
|
||||
tile.removeChild(reactionsView.root());
|
||||
reactionsView.unmount();
|
||||
this.removeSubView(reactionsView);
|
||||
reactionsView = null;
|
||||
}
|
||||
});
|
||||
return li;
|
||||
return tile;
|
||||
}
|
||||
|
||||
/* This is called by the parent ListView, which just has 1 listener for the whole list */
|
||||
|
|
56
src/platform/web/ui/session/room/timeline/BaseTileView.js
Normal file
56
src/platform/web/ui/session/room/timeline/BaseTileView.js
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
Copyright 2020 Bruno Windels <bruno@windels.cloud>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import {TemplateView} from "../../../general/TemplateView";
|
||||
|
||||
export class BaseTileView extends TemplateView {
|
||||
// ignore other arguments
|
||||
constructor(vm, viewClassForTile) {
|
||||
super(vm);
|
||||
this._viewClassForTile = viewClassForTile;
|
||||
this._root = undefined;
|
||||
}
|
||||
|
||||
root() {
|
||||
return this._root;
|
||||
}
|
||||
|
||||
render(t, vm) {
|
||||
const tile = this.renderTile(t, vm);
|
||||
const swapRoot = newRoot => {
|
||||
this._root?.replaceWith(newRoot);
|
||||
this._root = newRoot;
|
||||
}
|
||||
t.mapSideEffect(vm => vm.hasDateSeparator, hasDateSeparator => {
|
||||
if (hasDateSeparator) {
|
||||
const container = t.div([this._renderDateSeparator(t, vm)]);
|
||||
swapRoot(container);
|
||||
container.appendChild(tile);
|
||||
} else {
|
||||
swapRoot(tile);
|
||||
}
|
||||
});
|
||||
return this._root;
|
||||
}
|
||||
|
||||
_renderDateSeparator(t, vm) {
|
||||
// if this needs any bindings, we need to use a subview
|
||||
return t.div({className: "DateSeparator"}, t.time(vm.date));
|
||||
}
|
||||
|
||||
/* This is called by the parent ListView, which just has 1 listener for the whole list */
|
||||
onClick() {}
|
||||
}
|
Loading…
Reference in a new issue