Fix restoring scroll position on edited message

This commit is contained in:
Eduard Kuzmenko 2022-06-28 02:37:32 +02:00
parent bbbf308ff0
commit 29074062b1
4 changed files with 57 additions and 35 deletions

View File

@ -503,7 +503,7 @@ export default class BubbleGroups {
prepareForGrouping(bubble: HTMLElement, message: MyMessage) {
const foundItem = this.getItemByBubble(bubble);
if(foundItem) { // should happen only on edit
debugger;
// debugger;
return;
}

View File

@ -248,7 +248,7 @@ export default class ChatBubbles {
private attachPlaceholderOnRender: () => void;
private bubblesToEject: Set<HTMLElement> = new Set();
private bubblesToReplace: Set<HTMLElement> = new Set();
private bubblesToReplace: Map<HTMLElement, HTMLElement> = new Map(); // TO -> FROM
private updatePlaceholderPosition: () => void;
private setPeerOptions: {lastMsgId: number; topMessage: number;};
@ -3153,7 +3153,7 @@ export default class ChatBubbles {
loadQueue = filterQueue(loadQueue);
const restoreScroll = this.prepareToSaveScroll(reverse);
const {restoreScroll, scrollSaver} = this.prepareToSaveScroll(reverse);
// if(this.messagesQueueOnRender) {
// this.messagesQueueOnRender();
// }
@ -3163,7 +3163,9 @@ export default class ChatBubbles {
}
this.ejectBubbles();
for(const bubble of this.bubblesToReplace) {
for(const [bubble, oldBubble] of this.bubblesToReplace) {
scrollSaver.replaceSaved(oldBubble, bubble);
if(!loadQueue.find((details) => details.bubble === bubble)) {
continue;
}
@ -3317,7 +3319,7 @@ export default class ChatBubbles {
this.bubblesToEject.add(bubble);
this.bubblesToReplace.delete(bubble);
this.bubblesToReplace.add(newBubble);
this.bubblesToReplace.set(newBubble, bubble);
this.bubbleGroups.changeBubbleByBubble(bubble, newBubble);
}
@ -4414,7 +4416,7 @@ export default class ChatBubbles {
private prepareToSaveScroll(reverse?: boolean) {
const isMounted = !!this.chatInner.parentElement;
if(!isMounted) {
return;
return {};
}
const log = this.log.bindPrefix('prepareToSaveScroll');
@ -4431,11 +4433,14 @@ export default class ChatBubbles {
// const saved = scrollSaver.getSaved();
// const hadScroll = saved.scrollHeight !== saved.clientHeight;
return () => {
log('restore');
// scrollSaver.restore(_history.length === 1 && !reverse ? false : true);
scrollSaver.restore(reverse);
this.onRenderScrollSet(scrollSaver.getSaved());
return {
restoreScroll: () => {
log('restore');
// scrollSaver.restore(_history.length === 1 && !reverse ? false : true);
scrollSaver.restore(reverse);
this.onRenderScrollSet(scrollSaver.getSaved());
},
scrollSaver
};
}

View File

@ -15,8 +15,7 @@ export default class ScrollSaver {
private scrollHeightMinusTop: number;
private scrollTop: number;
private clientHeight: number;
private anchor: HTMLElement;
private rect: DOMRect;
private elements: {element: HTMLElement, rect: DOMRect}[];
/**
*
@ -43,43 +42,50 @@ export default class ScrollSaver {
};
}
public findAnchor() {
public findElements() {
const {container} = this;
const containerRect = container.getBoundingClientRect();
const bubbles = Array.from(container.querySelectorAll(this.query)) as HTMLElement[];
let rect: DOMRect, anchor: HTMLElement;
const elements: ScrollSaver['elements'] = [];
for(const bubble of bubbles) {
const elementRect = bubble.getBoundingClientRect();
const visibleRect = getVisibleRect(bubble, container, undefined, elementRect, containerRect);
if(visibleRect) {
rect = elementRect;
anchor = bubble;
elements.push({element: bubble, rect: elementRect});
// break; // find first
} else if(anchor) { // find last
} else if(elements.length) { // find last
break;
}
}
if(!rect) {
if(!elements.length) {
const bubble = bubbles[0];
if(bubble) {
rect = bubble.getBoundingClientRect();
anchor = bubble;
elements.push({element: bubble, rect: bubble.getBoundingClientRect()});
}
}
return {rect, anchor};
return elements;
}
public findAndSetAnchor() {
const {rect, anchor} = this.findAnchor();
this.rect = rect;
this.anchor = anchor;
public replaceSaved(from: HTMLElement, to: HTMLElement) {
if(!this.elements) {
return;
}
const idx = this.elements.findIndex(({element}) => from === element);
if(idx !== -1) {
this.elements[idx].element = to;
}
}
public findAndSetElements() {
this.elements = this.findElements();
}
public save() {
this.findAndSetAnchor();
// console.warn('scroll save', this.anchor, this.rect);
this.findAndSetElements();
console.warn('scroll save', this.elements);
this._save();
}
@ -121,21 +127,32 @@ export default class ScrollSaver {
const {scrollTop, scrollHeight} = this.scrollable;
this.scrollHeight = scrollHeight;
if(!this.anchor?.parentElement) { // try to find new anchor
this.findAndSetAnchor();
let anchor: ScrollSaver['elements'][0];
// for(let i = this.elements.length - 1; i >= 0; --i) {
// const _anchor = this.elements[i];
// if(_anchor.element.parentElement) {
// anchor = _anchor;
// break;
// }
// }
anchor = this.elements[this.elements.length - 1];
if(!anchor?.element?.parentElement) { // try to find new anchor
this.findAndSetElements();
anchor = this.elements[this.elements.length - 1];
if(!this.anchor) { // fallback to old method if smth is really strange
if(!anchor) { // fallback to old method if smth is really strange
this._restore(useReflow);
return;
}
}
const rect = this.rect;
const newRect = this.anchor.getBoundingClientRect();
const {element, rect} = anchor;
const newRect = element.getBoundingClientRect();
const diff = newRect.bottom - rect.bottom;
this.setScrollTop(scrollTop + diff, useReflow);
// if(diff) debugger;
// console.warn('scroll restore', rect, diff, newRect);
console.warn('scroll restore', rect, diff, newRect);
}
public _restore(useReflow?: boolean) {

View File

@ -2367,7 +2367,7 @@ $bubble-beside-button-width: 38px;
color: var(--monospace-text-color);
}
.reply.is-overriding-color {
&:not(.just-media) .reply.is-overriding-color {
.reply-border {
background-color: rgb(var(--override-color));
}