forked from mystiq/hydrogen-web
fix TS errors in TimelineView
This commit is contained in:
parent
00aa40ea7b
commit
d9ddeaf107
1 changed files with 33 additions and 24 deletions
|
@ -15,7 +15,8 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {ListView} from "../../general/ListView";
|
import {ListView} from "../../general/ListView";
|
||||||
import {TemplateView, TemplateBuilder} from "../../general/TemplateView.js";
|
import {TemplateView, Builder} from "../../general/TemplateView";
|
||||||
|
import {IObservableValue} from "../../general/BaseUpdateView";
|
||||||
import {GapView} from "./timeline/GapView.js";
|
import {GapView} from "./timeline/GapView.js";
|
||||||
import {TextMessageView} from "./timeline/TextMessageView.js";
|
import {TextMessageView} from "./timeline/TextMessageView.js";
|
||||||
import {ImageView} from "./timeline/ImageView.js";
|
import {ImageView} from "./timeline/ImageView.js";
|
||||||
|
@ -25,9 +26,15 @@ import {MissingAttachmentView} from "./timeline/MissingAttachmentView.js";
|
||||||
import {AnnouncementView} from "./timeline/AnnouncementView.js";
|
import {AnnouncementView} from "./timeline/AnnouncementView.js";
|
||||||
import {RedactedView} from "./timeline/RedactedView.js";
|
import {RedactedView} from "./timeline/RedactedView.js";
|
||||||
import {SimpleTile} from "../../../../../domain/session/room/timeline/tiles/SimpleTile.js";
|
import {SimpleTile} from "../../../../../domain/session/room/timeline/tiles/SimpleTile.js";
|
||||||
import {TimelineViewModel} from "../../../../../domain/session/room/timeline/TimelineViewModel.js";
|
|
||||||
import {BaseObservableList as ObservableList} from "../../../../../observable/list/BaseObservableList.js";
|
import {BaseObservableList as ObservableList} from "../../../../../observable/list/BaseObservableList.js";
|
||||||
|
|
||||||
|
//import {TimelineViewModel} from "../../../../../domain/session/room/timeline/TimelineViewModel.js";
|
||||||
|
interface TimelineViewModel extends IObservableValue {
|
||||||
|
showJumpDown: boolean;
|
||||||
|
tiles: ObservableList<SimpleTile>;
|
||||||
|
setVisibleTileRange(start?: SimpleTile, end?: SimpleTile);
|
||||||
|
}
|
||||||
|
|
||||||
type TileView = GapView | AnnouncementView | TextMessageView |
|
type TileView = GapView | AnnouncementView | TextMessageView |
|
||||||
ImageView | VideoView | FileView | MissingAttachmentView | RedactedView;
|
ImageView | VideoView | FileView | MissingAttachmentView | RedactedView;
|
||||||
type TileViewConstructor = (this: TileView, SimpleTile) => void;
|
type TileViewConstructor = (this: TileView, SimpleTile) => void;
|
||||||
|
@ -71,7 +78,7 @@ export class TimelineView extends TemplateView<TimelineViewModel> {
|
||||||
private tilesView?: TilesListView;
|
private tilesView?: TilesListView;
|
||||||
private resizeObserver?: ResizeObserver;
|
private resizeObserver?: ResizeObserver;
|
||||||
|
|
||||||
render(t: TemplateBuilder, vm: TimelineViewModel) {
|
render(t: Builder<TimelineViewModel>, vm: TimelineViewModel) {
|
||||||
// assume this view will be mounted in the parent DOM straight away
|
// assume this view will be mounted in the parent DOM straight away
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
// do initial scroll positioning
|
// do initial scroll positioning
|
||||||
|
@ -103,38 +110,41 @@ export class TimelineView extends TemplateView<TimelineViewModel> {
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
private get scroller() {
|
private get scrollNode(): HTMLElement {
|
||||||
return this.root().firstElementChild as HTMLElement;
|
return (this.root()! as HTMLElement).firstElementChild! as HTMLElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
private get tilesNode(): HTMLElement {
|
||||||
|
return this.tilesView!.root()! as HTMLElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
private jumpDown() {
|
private jumpDown() {
|
||||||
const {scroller} = this;
|
const {scrollNode} = this;
|
||||||
this.stickToBottom = true;
|
this.stickToBottom = true;
|
||||||
scroller.scrollTop = scroller.scrollHeight;
|
scrollNode.scrollTop = scrollNode.scrollHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
public unmount() {
|
public unmount() {
|
||||||
super.unmount();
|
super.unmount();
|
||||||
if (this.resizeObserver) {
|
if (this.resizeObserver) {
|
||||||
this.resizeObserver.unobserve(this.root());
|
this.resizeObserver.unobserve(this.root()! as Element);
|
||||||
this.resizeObserver = null;
|
this.resizeObserver = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private restoreScrollPosition() {
|
private restoreScrollPosition() {
|
||||||
const {scroller} = this;
|
const {scrollNode, tilesNode} = this;
|
||||||
const tiles = this.tilesView!.root() as HTMLElement;
|
|
||||||
|
|
||||||
const missingTilesHeight = scroller.clientHeight - tiles.clientHeight;
|
const missingTilesHeight = scrollNode.clientHeight - tilesNode.clientHeight;
|
||||||
if (missingTilesHeight > 0) {
|
if (missingTilesHeight > 0) {
|
||||||
tiles.style.setProperty("margin-top", `${missingTilesHeight}px`);
|
tilesNode.style.setProperty("margin-top", `${missingTilesHeight}px`);
|
||||||
// we don't have enough tiles to fill the viewport, so set all as visible
|
// we don't have enough tiles to fill the viewport, so set all as visible
|
||||||
const len = this.value.tiles.length;
|
const len = this.value.tiles.length;
|
||||||
this.updateVisibleRange(0, len - 1);
|
this.updateVisibleRange(0, len - 1);
|
||||||
} else {
|
} else {
|
||||||
tiles.style.removeProperty("margin-top");
|
tilesNode.style.removeProperty("margin-top");
|
||||||
if (this.stickToBottom) {
|
if (this.stickToBottom) {
|
||||||
scroller.scrollTop = scroller.scrollHeight;
|
scrollNode.scrollTop = scrollNode.scrollHeight;
|
||||||
} else if (this.anchoredNode) {
|
} else if (this.anchoredNode) {
|
||||||
const newAnchoredBottom = bottom(this.anchoredNode!);
|
const newAnchoredBottom = bottom(this.anchoredNode!);
|
||||||
if (newAnchoredBottom !== this.anchoredBottom) {
|
if (newAnchoredBottom !== this.anchoredBottom) {
|
||||||
|
@ -142,10 +152,10 @@ export class TimelineView extends TemplateView<TimelineViewModel> {
|
||||||
// scrollBy tends to create less scroll jumps than reassigning scrollTop as it does
|
// scrollBy tends to create less scroll jumps than reassigning scrollTop as it does
|
||||||
// not depend on reading scrollTop, which might be out of date as some platforms
|
// not depend on reading scrollTop, which might be out of date as some platforms
|
||||||
// run scrolling off the main thread.
|
// run scrolling off the main thread.
|
||||||
if (typeof scroller.scrollBy === "function") {
|
if (typeof scrollNode.scrollBy === "function") {
|
||||||
scroller.scrollBy(0, bottomDiff);
|
scrollNode.scrollBy(0, bottomDiff);
|
||||||
} else {
|
} else {
|
||||||
scroller.scrollTop = scroller.scrollTop + bottomDiff;
|
scrollNode.scrollTop = scrollNode.scrollTop + bottomDiff;
|
||||||
}
|
}
|
||||||
this.anchoredBottom = newAnchoredBottom;
|
this.anchoredBottom = newAnchoredBottom;
|
||||||
}
|
}
|
||||||
|
@ -156,9 +166,8 @@ export class TimelineView extends TemplateView<TimelineViewModel> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private onScroll(): void {
|
private onScroll(): void {
|
||||||
const {scroller} = this;
|
const {scrollNode, tilesNode} = this;
|
||||||
const {scrollHeight, scrollTop, clientHeight} = scroller;
|
const {scrollHeight, scrollTop, clientHeight} = scrollNode;
|
||||||
const tiles = this.tilesView!.root() as HTMLElement;
|
|
||||||
|
|
||||||
let bottomNodeIndex;
|
let bottomNodeIndex;
|
||||||
this.stickToBottom = Math.abs(scrollHeight - (scrollTop + clientHeight)) < 1;
|
this.stickToBottom = Math.abs(scrollHeight - (scrollTop + clientHeight)) < 1;
|
||||||
|
@ -168,12 +177,12 @@ export class TimelineView extends TemplateView<TimelineViewModel> {
|
||||||
} else {
|
} else {
|
||||||
const viewportBottom = scrollTop + clientHeight;
|
const viewportBottom = scrollTop + clientHeight;
|
||||||
// console.log(`viewportBottom: ${viewportBottom} (${scrollTop} + ${clientHeight})`);
|
// console.log(`viewportBottom: ${viewportBottom} (${scrollTop} + ${clientHeight})`);
|
||||||
const anchoredNodeIndex = findFirstNodeIndexAtOrBelow(tiles, viewportBottom);
|
const anchoredNodeIndex = findFirstNodeIndexAtOrBelow(tilesNode, viewportBottom);
|
||||||
this.anchoredNode = tiles.childNodes[anchoredNodeIndex] as HTMLElement;
|
this.anchoredNode = tilesNode.childNodes[anchoredNodeIndex] as HTMLElement;
|
||||||
this.anchoredBottom = bottom(this.anchoredNode!);
|
this.anchoredBottom = bottom(this.anchoredNode!);
|
||||||
bottomNodeIndex = anchoredNodeIndex;
|
bottomNodeIndex = anchoredNodeIndex;
|
||||||
}
|
}
|
||||||
let topNodeIndex = findFirstNodeIndexAtOrBelow(tiles, scrollTop, bottomNodeIndex);
|
let topNodeIndex = findFirstNodeIndexAtOrBelow(tilesNode, scrollTop, bottomNodeIndex);
|
||||||
this.updateVisibleRange(topNodeIndex, bottomNodeIndex);
|
this.updateVisibleRange(topNodeIndex, bottomNodeIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue